Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting special methods using setattr()

Is it possible to dynamically assign special methods, such as __getitem__, to a class instance using setattr()? For example, if I have this:

class Example (object):
    pass

And then try this:

>>> example = Example()
>>> setattr(example, '__getitem__', lambda x: 1)

I get this:

>>> example['something']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Example' object has no attribute '__getitem__'

But of course this works just fine:

>>> example.__getitem__('something')
1

There's obviously something going on here that I don't understand regarding how Python does method lookups for this sort of thing. Do these methods have to be set on the class, rather than on the instance?

UPDATE:

So, I should make it clear than I know I can see this on the Example class...I was hoping there was a way to set them per-instance, but the consensus I'm seeing so far is You Can't Do That.

like image 932
larsks Avatar asked May 07 '12 14:05

larsks


1 Answers

The issue here is that __getitem__() is defined at a class-level, not at instance-level:

>>> class Example (object):
...     pass
... 
>>> example = Example()
>>> setattr(Example, '__getitem__', lambda x, y: 1)
>>> example['something']
1

If you need it to be instance-specific:

>>> class Example(object):
...     def __getitem__(self, item):
...         return self._getitem(item)
... 
>>> example = Example()
>>> setattr(example, '_getitem', lambda x: 1)
>>> example['something']
1
>>> example2 = Example()
>>> setattr(example2, '_getitem', lambda x: 2)
>>> example['something']
1
>>> example2['something']
2
like image 169
Gareth Latty Avatar answered Oct 04 '22 19:10

Gareth Latty