Reputation: 102
Can anyone explain the following strangeness?
This works as expected:
duncan@duncan:~/Working/wtf$ python -V
Python 2.7.3
duncan@duncan:~/Working/wtf$ cat test_without_get.py
class B(object):
def __setitem__(self, key, value):
print "__setitem__"
class A(object):
b = B()
a = A()
a.b
a.b[0] = 1
duncan@duncan:~/Working/wtf$ python test_without_get.py
__setitem__
But here __setitem__
breaks and appears to call __get__
in it's place:
duncan@duncan:~/Working/wtf$ cat test_with_get.py
class B(object):
def __setitem__(self, key, value):
print "__setitem__"
def __get__(self, instance, owner):
print "__get__"
class A(object):
b = B()
a = A()
a.b
a.b[0] = 1
duncan@duncan:~/Working/wtf$ python test_with_get.py
__get__
__get__
Traceback (most recent call last):
File "test_with_get.py", line 12, in <module>
a.b[0] = 1
TypeError: 'NoneType' object does not support item assignment
does any one have any insight int why this happens and how to work around it?
Further experimentation:
as suggested by ignacio-vazquez-abrams@ ,
if __get__
returns an object, things work as expected:
duncan@dunksbox:~/Working/wtf$ python -V
Python 2.7.3
duncan@dunksbox:~/Working/wtf$ cat test_with_get_working.py
class B(object):
def __setitem__(self, key, value):
print "__setitem__"
def __get__(self, instance, owner):
print "__get__"
return self
class A(object):
b = B()
a = A()
a.b
a.b[0] = 1
duncan@dunksbox:~/Working/wtf$ python ./test_with_get_working.py
__get__
__get__
__setitem__
but only if you are careful about what __get__
returns:
duncan@dunksbox:~/Working/wtf$ cat test_with_get_notworking.py
class B(object):
def __setitem__(self, key, value):
print "__setitem__"
def __get__(self, instance, owner):
print "__get__"
return [1]
class A(object):
b = B()
a = A()
a.b
a.b[0] = 1
duncan@dunksbox:~/Working/wtf$ python ./test_with_get_notworking.py
__get__
__get__
Upvotes: 0
Views: 53
Reputation: 798744
It happens because you've created B
as a descriptor since it defines one of the descriptor protocol methods. The only ways around it are to either not create it as a descriptor in the first place, or to return a separate object from the descriptor whose __setitem__()
method behaves as desired.
Upvotes: 1