Python:为什么访问现有属性会触发“__getattr__”?
Python: why visiting an existing attribute triggered "__getattr__"?
我知道 python 的 __getattr__
在访问不存在的属性时会被触发。
但在下面的示例中,在 c1 的 __init__
中,我创建了一个名为 name 的自属性。访问时,两种访问方式都触发__getattr__
,打印“None”。
这对我来说很奇怪。我想我的理解或我的代码有问题?
$ cat n.py
class c1(object):
def __init__(s):
print 'init c1'
s.name='abc'
def __getattr__(s,name):
print "__getattr__:"+name
return None
def __setattr__(s,name,value):
print "__setattr__:"+value
def __get__(s,inst,owner):
print "__get__"
class d:
def __init__(s):
s.c=c1()
c=c1()
print c.name
o=d()
print o.c.name
$ python n.py
init c1
__setattr__:abc
__getattr__:name
None
init c1
__setattr__:abc
__getattr__:name
None
可以看到我在__init__
里面定义了s.name='abc'
,但是调用的时候不识别
您也实现了__setattr__
,并且在尝试设置属性时总是调用。您的版本只打印属性:
def __setattr__(s,name,value):
print "__setattr__:"+value
没有别的,这意味着该属性实际上不是 set。以上是为 s.name='abc'
表达式调用的,从未设置 name
属性,因此以后对 name
属性的任何访问都会再次发送到 __getattr__
。
让__setattr__
直接在__dict__
中设置值:
def __setattr__(self, name, value):
print "__setattr__:" + value
self.__dict__[name] = value
或使您的 class 成为 new-style class(继承自 object
),然后您可以通过 super(c1, self).__setattr__(name, value)
.
重新使用基础实现
附带说明:您实现了 c1.__get__
,大概是为了让 class 成为 descriptor object。但是描述符协议只适用于class属性,不适用于实例属性,然后只适用于new-styleclasses。您的 class d
不是新样式 class,并且您使用实例属性 c
来存储 c1
实例。
我知道 python 的 __getattr__
在访问不存在的属性时会被触发。
但在下面的示例中,在 c1 的 __init__
中,我创建了一个名为 name 的自属性。访问时,两种访问方式都触发__getattr__
,打印“None”。
这对我来说很奇怪。我想我的理解或我的代码有问题?
$ cat n.py
class c1(object):
def __init__(s):
print 'init c1'
s.name='abc'
def __getattr__(s,name):
print "__getattr__:"+name
return None
def __setattr__(s,name,value):
print "__setattr__:"+value
def __get__(s,inst,owner):
print "__get__"
class d:
def __init__(s):
s.c=c1()
c=c1()
print c.name
o=d()
print o.c.name
$ python n.py
init c1
__setattr__:abc
__getattr__:name
None
init c1
__setattr__:abc
__getattr__:name
None
可以看到我在__init__
里面定义了s.name='abc'
,但是调用的时候不识别
您也实现了__setattr__
,并且在尝试设置属性时总是调用。您的版本只打印属性:
def __setattr__(s,name,value):
print "__setattr__:"+value
没有别的,这意味着该属性实际上不是 set。以上是为 s.name='abc'
表达式调用的,从未设置 name
属性,因此以后对 name
属性的任何访问都会再次发送到 __getattr__
。
让__setattr__
直接在__dict__
中设置值:
def __setattr__(self, name, value):
print "__setattr__:" + value
self.__dict__[name] = value
或使您的 class 成为 new-style class(继承自 object
),然后您可以通过 super(c1, self).__setattr__(name, value)
.
附带说明:您实现了 c1.__get__
,大概是为了让 class 成为 descriptor object。但是描述符协议只适用于class属性,不适用于实例属性,然后只适用于new-styleclasses。您的 class d
不是新样式 class,并且您使用实例属性 c
来存储 c1
实例。