How come an object that implements __iter__ is not recognized as iterable? - python

Let's say you work with a wrapper object:
class IterOrNotIter:
def __init__(self):
self.f = open('/tmp/toto.txt')
def __getattr__(self, item):
try:
return self.__getattribute__(item)
except AttributeError:
return self.f.__getattribute__(item)
This object implements __iter__, because it passes any call to it to its member f, which implements it. Case in point:
>>> x = IterOrNotIter()
>>> x.__iter__().__next__()
'Whatever was in /tmp/toto.txt\n'
According to the documentation (https://docs.python.org/3/library/stdtypes.html#iterator-types), IterOrNotIter should thus be iterable.
However, the Python interpreter does not recognize an IterOrNotIter object as actually being iterable:
>>> x = IterOrNotIter()
>>> for l in x:
... print(l)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'IterOrNotIter' object is not iterable
Whereas this works:
>>> x = IterOrNotIter()
>>> for l in x.f:
... print(l)
...
Whatever was in /tmp/toto.txt
I don't understand why.

Basically because your class just doesn't have a real __iter__ method:
>>> hasattr(IterOrNotIter, '__iter__')
False
So it doesn't qualify as iterator because the actual check for __iter__ checks for the existence instead of assuming it's implemented. So workarounds with __getattr__ or __getattribute__ (unfortunatly) don't work.
This is actually mentioned in the documentation for __getattribute__:
Note
This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions. See Special method lookup.
The latter section also explains the why:
Bypassing the __getattribute__() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).
Emphasis mine.

Related

How to make a class or function uncallable in Python?

I want to make a class or function uncallable, so when the callable function is used on the function object/class object like callable(function) it will return False. I have already found out how to stop a class from being called and having instances by this:
class Object:
def __new__(cls):
raise TypeError('{} is not callable'.format(cls.__name__))
but then when I use callable(Object), it still returns True. How do I make it uncallable and so then return False when the callable function is used on it?
even when I use
Object.__new__ = None
or
Object.__call__ = None
it still returns False
I don't think it is possible to make function objects or class objects uncallable from the perspective of callable, which basically just checks if the class has a __call__ attribute. You can make a user-defined class uncallable that was defined as callable, e.g.:
>>> class Foo:
... def __call__(self): return 'foo!'
...
>>> Foo()()
'foo!'
>>> callable(Foo())
True
>>> del Foo.__call__
>>> callable(Foo())
False
However, class objects all inherit from type, a built-in, and you cannot delete attributes from built-in classes:
>>> del type.__call__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'type'
And even if you hacked your way around it, it would break the interpreter, because it fundamentally relies on class objects being callable, and this would prevent all classes from being callable.
Perhaps there is some metaclass magic you can do to make a class object uncallable, but the attribute resolution in this scenario is a bit arcane... my naive attempts have failed. I thought maybe this might work:
>>> class Uncallable(type):
... def __getattribute__(self, name):
... print('getting', name)
... if name == '__call__':
... raise AttributeError
... return super().__getattribute__(name)
...
>>> class Foo(metaclass=Uncallable): pass
...
>>> callable(Foo)
True
>>> Foo()
<__main__.Foo object at 0x7f830a892df0>
But it doesn't, because special methods (i.e. "dunder" methods) bypasses __getattribute__... maybe there is an obvious solution I'm not seeing...
Anyway, there are probably much more sensible workarounds. An uncallable class doesn't make a lot of sense anyway, what, exactly are you trying to actually accomplish?
I haven't investigated exactly why, but it's difficult if not impossible to prevent an object of <class 'type'> from being callable. A workaround for this is to have an object not of that class, that acts exactly the same way in every other respect except being callable.
This can be done to a user-created class by using a decorator and a template UncallableObject class, which, given a template, copies the entire contents of that template's __dict__ to itself, barring __call__ (because we don't want it to be callable), __dict__ (to avoid problems with recursion), and __weakref__ (because python does not allow it).
def uncallable(f):
class UncallableObject:
def __init__(self, other):
for k,v in other.__dict__.items():
if k not in ('__call__', '__dict__', '__weakref__'):
setattr(self, k, v)
g = UncallableObject(f)
return g
#uncallable
class Object:
pass
>>> #uncallable
... class Object: pass
...
>>> callable(Object)
False
>>> Object()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'UncallableObject' object is not callable
>>>
>>> #uncallable
... def funnyfunc():
... pass
...
>>> callable(funnyfunc)
False
>>> funnyfunc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'UncallableObject' object is not callable
In practice I see no practical reason to do this - using an Abstract Base Class could probably fulfill whatever purpose you're trying to aim for, and would be easier to maintain. Whether or not an object should be called ought to be an issue of documentation, for the sake of clarity.

variable repr in python based on call depth

I have a (bad?) habit of displaying classes in Python like structures in Matlab, where each attribute is printed along with its value in a nice clean layout. This is done by implementing the __repr__ method in the class.
When working with objects inside of dictionaries or lists, this display style can be a bit distracting. In this case I'd like to do a more basic display.
Here's the envisioned pseudocode:
def __repr__(self):
if direct_call():
return do_complicated_printing(self)
else:
#something simple that isn't a ton of lines/characters
return type(self)
In this code direct_call() means that this isn't being called as part of another display call. Perhaps this might entail looking for repr in the stack? How would I implement direct call detection?
So I might have something like:
>>> data
<class my_class> with properties:
a: 1
cheese: 2
test: 'no testing'
But in a list I'd want a display like:
>>> data2 = [data, data, data, data]
>>> data2
[<class 'my_class'>,<class 'my_class',<class 'my_class'>,<class 'my_class'>]
I know it is possible for me to force this type of display by calling some function that does this, but I want my_class to be able to control this behavior, without extra work from the user in asking for it.
In other words, this is not a solution:
>>> print_like_I_want(data2)
This is a strange thing to want to do, and generally a function or method ought to do the same thing whoever is calling it. But in this case, __repr__ is only meant for the programmer's convenience, so convenience seems like a good enough reason to make it work the way you're asking for.
However, unfortunately what you want isn't actually possible, because for whatever reason, the list.__repr__ method isn't visible on the stack. I tested in Python 3.5.2 and Python 3.8.1:
>>> class ReprRaises:
... def __repr__(self):
... raise Exception()
...
>>> r = ReprRaises()
>>> r
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __repr__
Exception
>>> [r]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __repr__
Exception
As you can see, the stack is the same whether or not the object being repr'd is in a list. (The __repr__ frame on the stack belongs to the ReprRaises class, not list.)
I also tested using inspect.stack:
>>> import inspect
>>> class ReprPrints:
... def __repr__(self):
... print(*inspect.stack(), sep='\n')
... return 'foo'
>>> r = ReprPrints()
>>> r
FrameInfo(frame=<frame object at 0x7fcbe4a38588>, filename='<stdin>', lineno=3, function='__repr__', code_context=None, index=None)
FrameInfo(frame=<frame object at 0x7fcbe44fb388>, filename='<stdin>', lineno=1, function='<module>', code_context=None, index=None)
foo
>>> [r]
FrameInfo(frame=<frame object at 0x7fcbe4a38588>, filename='<stdin>', lineno=3, function='__repr__', code_context=None, index=None)
FrameInfo(frame=<frame object at 0x7fcbe44fb388>, filename='<stdin>', lineno=1, function='<module>', code_context=None, index=None)
[foo]
Again, there's no visible difference in the call stack between the object itself vs. the object in a list; so there's nothing for your __repr__ to check for.
So, the closest you can get is some kind of print_like_I_want function. This can at least be written in a way that lets each class define its own behaviour:
def pp(obj):
try:
_pp = obj._pp
except AttributeError:
print(repr(obj))
else:
print(_pp())
The only way I can think of to do it with fewer keypresses is by overloading a unary operator, like the usually-useless unary plus:
>>> class OverloadUnaryPlus:
... def __repr__(self):
... return 'foo'
... def __pos__(self):
... print('bar')
...
>>> obj = OverloadUnaryPlus()
>>> obj
foo
>>> +obj
bar
__repr__ is intended to provide a short, often programmatic display of an object. It's used as the method of choice for all built in containers to display elements. You should therefore override __repr__ to provide your short output.
__str__ is the function intended for the full fancy display of an object. It's what normally shows up when you print an object. You can also trigger it by calling str. You should put your long fancy output in __str__, not __repr__.
The only modification you will have to make is to explicitly call print(obj) or str(obj) rather than repr(obj) or just obj in the REPL. As #kaya3's excellent answer shows, stack inspection won't help you much, and in my opinion would not be a clean solution even if it did.

"implicit uses of special methods always rely on the class-level binding of the special method"

I have difficulty understanding the last part (in bold) from Python in a Nutshell
Per-Instance Methods
An instance can have instance-specific bindings for all attributes,
including callable attributes (methods). For a method, just like for
any other attribute (except those bound to overriding descriptors),
an instance-specific binding hides a class-level binding:
attribute lookup does not consider the class when it finds a
binding directly in the instance. An instance-specific binding for a
callable attribute does not perform any of the transformations
detailed in “Bound and Unbound Methods” on page 110: the attribute
reference returns exactly the same callable object that was earlier
bound directly to the instance attribute.
However, this does not work as you might expect
for per-instance bindings of the special methods that Python calls
implicitly as a result of various operations, as covered in “Special
Methods” on page 123. Such implicit uses of special methods always
rely on the class-level binding of the special method, if any. For
example:
def fake_get_item(idx): return idx
class MyClass(object): pass
n = MyClass()
n.__getitem__ = fake_get_item
print(n[23]) # results in:
# Traceback (most recent call last):
# File "<stdin>", line 1, in ?
# TypeError: unindexable object
What does it mean specifically?
Why is the error of the example?
Thanks.
Neglecting all the fine details it basically says that special methods (as defined in Pythons data model - generally these are the methods starting with two underscores and ending with two underscores and are rarely, if ever, called directly) will never be used implicitly from the instance even if defined there:
n[whatever] # will always call type(n).__getitem__(n, whatever)
This differs from attribute look-up which checks the instance first:
def fake_get_item(idx):
return idx
class MyClass(object):
pass
n = MyClass()
n.__getitem__ = fake_get_item
print(n.__getitem__(23)) # works because attribute lookup checks the instance first
There is a whole section in the documentation about this (including rationale): "Special method lookup":
3.3.9. Special method lookup
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary. That behaviour is the reason why the following code raises an exception:
>>> class C:
... pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()
The rationale behind this behaviour lies with a number of special methods such as __hash__() and __repr__() that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself:
>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument
[...]
Bypassing the __getattribute__() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).
To put it even more plainly, it means that you can't redefine the dunder methods on the fly. As a consequence, ==, +, and the rest of the operators always mean the same thing for all objects of type T.
I'll try to summarize what the extract says and in particular the part in bold.
Generally speaking, when Python tries to find the value of an attribute (including a method), it first checks the instance (i.e. the actual object you created), then the class.
The code below illustrates the generic behavior.
class MyClass(object):
def a(self):
print("howdy from the class")
n = MyClass()
#here the class method is called
n.a()
#'howdy from the class'
def new_a():
print("hello from new a")
n.a = new_a
#the new instance binding hides the class binding
n.a()
#'hello from new a'
What the part in bold states is that this behavior does not apply to "Special Methods" such as __getitem__. In other words, overriding __getitem__ at the instance level (n.__getitem__ = fake_get_item in your exemple) does nothing : when the method is called through the n[] syntax, an error is raised because the class does not implement the method.
(If the generic behavior also held in this case, the result of print(n[23]) would have been to print 23, i.e. executing the fake_get_item method).
Another example of the same behavior:
class MyClass(object):
def __getitem__(self, idx):
return idx
n = MyClass()
fake_get_item = lambda x: "fake"
print(fake_get_item(23))
#'fake'
n.__getitem__ = fake_get_item
print(n[23])
#'23'
In this example, the class method for __getitem__ (which returns the index number) is called instead of the instance binding (which returns 'fake').

Python __iter__ and for loops

As I understand it, I can use the for loop construction on an object with a __iter__ method that returns an iterator. I have an object for which I implement the following __getattribute__ method:
def __getattribute__(self,name):
if name in ["read","readlines","readline","seek","__iter__","closed","fileno","flush","mode","tell","truncate","write","writelines","xreadlines"]:
return getattr(self.file,name)
return object.__getattribute__(self,name)
I have an object of this class, a for which the following happens:
>>> hasattr(a,"__iter__")
True
>>> for l in a: print l
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'TmpFile' object is not iterable
>>> for l in a.file: print l
...
>>>
So python sees that a has an __iter__ method, but doesn't think it is iterable. What have I done wrong? This is with python 2.6.4.
There's a subtle implementation detail getting in your way: __iter__ isn't actually an instance method, but a class method. That is, obj.__class__.__iter__(obj) is called, rather than obj.__iter__().
This is due to slots optimizations under the hood, allowing the Python runtime to set up iterators faster. This is needed since it's very important that iterators be as fast as possible.
It's not possible to define __getattribute__ for the underlying class type, so it's not possible to return this method dynamically. This applies to most __metamethods__; you'll need to write an actual wrapper.
Some of the special methods are optimised when a class is created and cannot be added later or overridden by assignment. See the documentation for __getattribute__ which says:
This method may still be bypassed when
looking up special methods as the
result of implicit invocation via
language syntax or built-in functions.
What you need to do in this case is provide a direct implementation of __iter__ that forwards the call:
def __iter__(self):
return self.file.__iter__()

Is there a way to create a python object that will be not sortable?

Is there a possibility to create any python object that will be not sortable? So that will be an exception when trying to sort a list of that objects?
I created a very simple class, didn't define any comparison methods, but still instances of this class are comparable and thus sortable. Maybe, my class inherits comparison methods from somewhere. But I don't want this behaviour.
You could define a __cmp__ method on the class and always raise an exception when it is called. That might do the trick.
Out of curiosity, why?
As Will McCutchen has mentioned, you can define a __cmp__ method that raises an exception to prevent garden variety sorting. Something like this:
class Foo(object):
def __cmp__(self, other):
raise Exception()
a = [Foo(), Foo(), Foo()]
a.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __cmp__
Exception
However, you cannot truly prevent a developer from sorting a list of your objects. Using the key or cmp argument with list.sort() or with the built-in standalone sorted() function , anyone can circumvent the __cmp__ method by using a custom comparison function or sorting key.
# continuing from above
>>> a = [Foo(), Foo(), Foo()]
>>> a
[<__main__.Foo object at 0x1004a3350>, <__main__.Foo object at 0x1004a3390>,
<__main__.Foo object at 0x1004a33d0>]
>>> a.sort(key=id, reverse=True)
>>> # or a.sort(cmp=lambda a, b: cmp(id(b), id(a)))
>>> # or sorted(a, key=id)
>>> # etc...
[<__main__.Foo object at 0x1004a33d0>, <__main__.Foo object at 0x1004a3390>,
<__main__.Foo object at 0x1004a3350>]
As others will point out, I'm not sure there's much value in trying to prevent someone from sorting an object. If this isn't just a curious itch you're trying to scratch, what's the use case for this?
The default list sorting uses the built-in cmp() function on its elements. The cmp() function checks if its arguments (2 elements from your list) have a __cmp__() method. If yes, this method is used for comparison. Otherwise, as in your case, the argument object IDs (return value of the built-in function id()) are used for comparison.
To let the sorting fail, you could define a comparison method which throws an Exception:
>>> class X(object):
... def __cmp__(self, other):
... raise StandardError # or whatever Exception you need
...
>>> l = [X(), X(), X()]
>>> l.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in __cmp__
StandardError
For what it's worth, in Python 3 the default will be for new items to not be comparable (and hence not sortable). In Python 2, you have to explicitly create a __cmp__ or __lt__ method, as others have said.
Why don't you just write a class that contains a list object and provides methods to access the data inside? By doing that you would effectively hide the list and therefore prevent them from sorting it.
Sets don't have a total ordering
>>> s=set((1,2,3))
>>> t=set("abc")
>>> s<t
False
>>> t<s
False
>>>
But no exception is raise when you try to sort them
>>> sorted([s,t])
[set([1, 2, 3]), set(['a', 'c', 'b'])]
The python sort algorithms use the __lt__ special method. Keeping in mind that using the cmp and key arguments of the sorting function and methods, it is suggested that your class defines a method:
def __lt__(self, other):
raise NotImplementedError

Categories