【发布时间】:2013-11-18 07:56:01
【问题描述】:
我正在尝试编写一个具有动态属性的类。考虑以下具有两个只读属性的类:
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__ 可以获取任意字典并从字典中的每个项目创建只读属性。我可以这样做:
class Monster2(object):
def __init__(self,traits):
self._traits = traits
for key,value in traits.iteritems():
setattr(self.__class__,key,property(lambda self,key=key: self._traits[key]))
但是,这有一个严重的缺点:每次创建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 中使用属性的信息,但很少了解它们是如何实现的。如果“实例属性”没有意义,我想了解原因。
【问题讨论】:
-
避免使用子类有什么原因吗?
-
你为什么要这样做?如果你所有的 getter 函数都是从 dict 返回值的相同函数,为什么还要拥有它们呢?首先要有 getter 的唯一原因是如果您需要运行一些代码来生成值。
-
@abarnert:属性也常用于创建只读变量,请注意缺少设置器。不过你是对的,这是一个非常简单的例子,我的真实代码确实有更复杂的 getter。
标签: python properties