我试图编写一个具有动态属性的类。考虑以下具有两个只读属性的类:
class Monster(object):
def __init__(self,color,has_fur):
self._color = color
self._has_fur = has_fur
@property
def color(self): return self._color
@property
def has_fur(self): return self._has_fur
我想对此进行推广,以便__init__
可以使用任意字典并从字典中的每个项创建只读属性。我可以这样做:
但是,这有一个严重的缺点:每次我创建Monster
的新实例时,实际上是在修改Monster
类。我没有为新的Monster
实例创建属性,而是有效地将属性添加到Monster
的所有实例中。要看到这个:
>>> hasattr(Monster2,"height")
False
>>> hasattr(Monster2,"has_claws")
False
>>> blue_monster = Monster2({"height":4.3,"color":"blue"})
>>> hasattr(Monster2,"height")
True
>>> hasattr(Monster2,"has_claws")
False
>>> red_monster = Monster2({"color":"red","has_claws":True})
>>> hasattr(Monster2,"height")
True
>>> hasattr(Monster2,"has_claws")
True
这当然有意义,因为我用setattr(self.__class__,key,property(lambda self,key=key: self._traits[key]))
显式地添加了属性作为类属性。这里我需要的是可以添加到实例中的属性。(即“实例属性”)。不幸的是,根据我阅读和尝试的所有内容,属性总是类属性,而不是实例属性。例如,这不起作用:
class Monster3(object):
def __init__(self,traits):
self._traits = traits
for key,value in traits.iteritems():
self.__dict__[key] = property(lambda self,key=key: self._traits[key])
>>> green_monster = Monster3({"color":"green"})
>>> green_monster.color
<property object at 0x028FDAB0>
所以我的问题是:“实例属性”是否存在?如果没有,原因是什么?我已经找到了很多关于Python中如何使用属性的信息,但是关于它们是如何实现的却很少。如果“实例属性”没有意义,我想了解原因。在
没有
因为属性被实现为descriptors。描述符的神奇之处在于,当在对象类型的字典中找到时,它们所做的事情与在对象字典中找到时的不同。在
阅读上面链接的描述指南。在
那么,你有没有办法做到这一点?在
嗯,是的,如果你愿意重新考虑一下设计。在
对于您的例子,您所要做的就是使用},并且动态生成无用的getter函数,因此可以用几行代码替换整个过程,就像Martijn Pieters的回答一样。在
_traits
代替{或者,如果您想将
.foo
重定向到._foo
如果foo
在_traits
的列表(或更好的情况下,集合)中,这同样简单:但是假设您实际上对getter函数有某种用途,每个属性实际上需要一些代码来生成值,这个值已经封装在一个函数中,并存储在
^{pr2}$_traits
中。在这种情况下:一个property()是一个描述符,它只在存储在类中时有效,而在实例中存储时不起作用。在
实现实例属性效果的一个简单方法是do def\u getattr\。这将允许您控制查找的行为。在
不,不存在按实例属性的事情;与所有描述符一样,属性总是总是在类中查找。请参见descriptor HOWTO了解具体的工作原理。在
您可以使用
__getattr__
钩子来实现动态属性,该钩子可以动态检查实例属性:但这些属性并不是真正的动态的;您可以直接在实例上设置这些属性:
^{pr2}$相关问题 更多 >
编程相关推荐