How to override the [] operator in Python? - python

What is the name of the method to override the [] operator (subscript notation) for a class in Python?

You need to use the __getitem__ method.
class MyClass:
def __getitem__(self, key):
return key * 2
myobj = MyClass()
myobj[3] #Output: 6
And if you're going to be setting values you'll need to implement the __setitem__ method too, otherwise this will happen:
>>> myobj[5] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__setitem__'

To fully overload it you also need to implement the __setitem__and __delitem__ methods.
edit
I almost forgot... if you want to completely emulate a list, you also need __getslice__, __setslice__ and __delslice__.
There are all documented in http://docs.python.org/reference/datamodel.html

You are looking for the __getitem__ method. See http://docs.python.org/reference/datamodel.html, section 3.4.6

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.

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

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.

Make a Python class throw an error when creating a new property

Let's say this is my class:
class A:
def __init__(self):
self.good_attr = None
self.really_good_attr = None
self.another_good_attr = None
Then a caller can set the values on those variables:
a = A()
a.good_attr = 'a value'
a.really_good_attr = 'better value'
a.another_good_attr = 'a good value'
But they can also add new attributes:
a.goood_value = 'evil'
This is not desirable for my use case. My object is being used to pass a number of values into a set of methods. (So essentially, this object replaces a long list of shared parameters on a few methods to avoid duplication and clearly distinguish what's shared and what's different.) If a caller typos an attribute name, then the attribute would just be ignored, resulting in unexpected and confusing and potentially hard to figure out behavior. It would be better to fail fast, notifying the caller that they used an attribute name that will be ignored. So something similar to the following is the behavior I would like when they use an attribute name that doesn't already exist on the object:
>>> a.goood_value = 'evil'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'goood_value'
How can I achieve this?
I would also like to note that I'm fully aware that a caller can create a new class and do whatever they want, bypassing this entirely. This would be unsupported behavior, though. Making the object I do provide just creates a fail-fast bonehead check to save time against typos for those who do leverage the object I'm providing (myself included), rather than making them scratch their heads wondering why things are behaving in unexpected ways.
You can hook into attribute setting with the __setattr__ method. This method is called for all attribute setting, so take into account it'll be called for your 'correct' attributes too:
class A(object):
good_attr = None
really_good_attr = None
another_good_attr = None
def __setattr__(self, name, value):
if not hasattr(self, name):
raise AttributeError(
'{} instance has no attribute {!r}'.format(
type(self).__name__, name))
super(A, self).__setattr__(name, value)
Because good_attr, etc. are defined on the class the hasattr() call returns True for those attributes, and no exception is raised. You can set those same attributes in __init__ too, but the attributes have to be defined on the class for hasattr() to work.
The alternative would be to create a whitelist you could test against.
Demo:
>>> a = A()
>>> a.good_attr = 'foo'
>>> a.bad_attr = 'foo'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 10, in __setattr__
AttributeError: A instance has no attribute 'bad_attr'
A determined developer can still add attributes to your instance by adding keys to the a.__dict__ instance dictionary, of course.
Another option is to use a side-effect of using __slots__; slots are used to save memory as a dictionary takes a little more space than just putting values directly into the C structure Python creates for each instance (no keys and dynamic table are needed then). That side-effect is that there is no place for more attributes on such a class instance:
class A(object):
__slots__ = ('good_attr', 'really_good_attr', 'another_good_attr')
def __init__(self):
self.good_attr = None
self.really_good_attr = None
self.another_good_attr = None
The error message then looks like:
>>> a = A()
>>> a.good_attr = 'foo'
>>> a.bad_attr = 'foo'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'bad_attr'
but do read the caveats listed in the documentation for using __slots__.
Because there is no __dict__ instance attribute when using __slots__, this option really closes the door on setting arbitrary attributes on the instances.
A more idiomatic option is to use a named tuple.
Python 3.6 and higher
In Python 3.6 and higher, you can use typing.NamedTuple to achieve this very easily:
from typing import NamedTuple, Any
class A(NamedTuple):
good_attr: Any = None
really_good_attr: Any = None
another_good_attr: Any = None
More specific type constraints can be used if desired, but the annotations must be included for NamedTuple to pick up on the attributes.
This blocks not only the addition of new attributes, but also the setting of existing attributes:
>>> a = A()
>>> a.goood_value = 'evil'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'goood_value'
>>> a.good_attr = 'a value'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
This forces you to specify all the values at construction time instead:
a = A(
good_attr='a value',
really_good_attr='better value',
another_good_attr='a good value',
)
Doing so is typically not a problem, and when it is, it can be worked around with the judicious use of local variables.
Python 3.5 and lower (including 2.x)
These versions of Python either do not have the typing module or typing.NamedTuple does not work as used above. In these versions, you can use collections.namedtuple to achieve mostly the same effect.
Defining the class is simple:
from collections import namedtuple
A = namedtuple('A', ['good_attr', 'really_good_attr', 'another_good_attr'])
And then construction works as above:
a = A(
good_attr='a value',
really_good_attr='better value',
another_good_attr='a good value',
)
However, this does not allow for the omission of some values from calling the constructor. You can either include None values explicitly when constructing the object:
a = A(
good_attr='a value',
really_good_attr=None,
another_good_attr='a good value',
)
Or you can use one of several techniques to give the argument a default value:
A.__new__.func_defaults = (None,) * 3
a = A(
good_attr='a value',
another_good_attr='a good value',
)
make the parameter private by adding two underscores to it, ex self.__good_attr, this way someone can't set that parameter outside of the class. Then make a function that sets the __good_attr variable and have that function throw an exception if it's wrong.

Python string object not callable

I am not able to understand why I am getting a Type Error for the following statement
log.debug('vec : %s blasted : %s\n' %(str(vec), str(bitBlasted)))
type(vec) is unicode
bitBlasted is a list
I am getting the following error
TypeError: 'str' object is not callable
Shadowing the built-in
Either as Collin said, you could be shadowing the built-in str:
>>> str = some_variable_or_string #this is wrong
>>> str(123.0) #Or this will happen
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
One solution would be to change the variable name to str_ or something. A better solution would be to avoid this kind of Hungarian naming system -- this isn't Java, use Python's polymorphism to its fullest and use a more descriptive name instead.
Not defining a proper method
Another possibility is that the object may not have a proper __str__ method or even one at all.
The way Python checks for the str method is:-
the __str__ method of the class
the __str__ method of its parent class
the __repr__ method of the class
the __repr__ method of its parent class
and the final fallback: a string in form of <module>.<classname> instance at <address> where <module> is self.__class__.__module__, <classname> is self.__class__.__name__ and <address> is id(self)
Even better than __str__ would be to use the new __unicode__ method (in Python 3.x, they're __bytes__ and __str__. You could then implement __str__ as a stub method:
class foo:
...
def __str__(self):
return unicode(self).encode('utf-8')
See this question for more details.
As mouad said, you've used the name str somewhere higher in the file. That shadows the existing built-in str, and causes the error. For example:
>>> mynum = 123
>>> print str(mynum)
123
>>> str = 'abc'
>>> print str(mynum)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

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