__setitem__和__get__之间的奇怪互动

时间:2013-12-18 01:59:40

标签: python-2.7

任何人都可以解释以下陌生感吗?

这可以按预期工作:

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__

但是这里__setitem__打破并且似乎在其中调用了__get__

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

任何人都有任何见解为什么会发生这种情况 以及如何解决它?


进一步的实验:

如ignacio-vazquez-abrams @所示, 如果__get__返回一个对象,则事情按预期工作:

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__

但是,只有在您对__get__返回的内容时要小心:

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__

1 个答案:

答案 0 :(得分:1)

之所以发生这种情况是因为您已将B创建为描述符,因为它定义了一种描述符协议方法。围绕它的唯一方法是首先不将其创建为描述符,或者从__setitem__()方法根据需要运行的描述符中返回单独的对象。