在 Python 中,据我所知,变量实际上是对给定命名空间中对象的引用。所以在下面的例子中,不足为奇的是,当全局命名空间中的noise
发生变化时,cat.noise
返回的值也会发生变化,因为setattr中的引用
行使用的是 noise
的reference,而不是其基础值。
class Cat(object):
pass
noise = "meow"
setattr(Cat, "noise", property(lambda self: noise))
cat = Cat()
cat.noise
# Outputs "meow"
noise = "purrrrr"
cat.noise
# Outputs "purrrrr"
也就是说,有没有办法在调用 setattr
时传递噪音的 value ?我认为我可以通过使用一个函数来隔离 namespace ,并且确实有效:
class Cat(object):
pass
noise = "meow"
def setproperties(cls, k, v):
setattr(cls, k, property(lambda self: v))
setproperties(Cat, "noise", noise)
cat = Cat()
cat.noise
# Outputs "meow"
noise = "purrrrr"
cat.noise
# Still outputs "meow"
是否可以在不通过函数传递对象的情况下这样做(不使用 eval
等)?作为次要问题,我对引擎盖下发生的事情的推理是否正确?
编辑
根据评论中对不那么做作的示例的请求,请考虑以下内容。假设我正在尝试根据它的 friend Dog
的值动态设置 Cat
中的属性:
class Dog(object):
noise = 'woof'
adorable = True
class Cat(object):
friend = Dog
friend_attrs = filter(lambda attr: not attr.startswith('__'), Dog.__dict__)
for attr in friend_attrs:
setattr(Cat, "friend_" + attr, property(lambda self: getattr(self.friend, attr)))
cat = Cat()
cat.friend_noise
# Outputs True
cat.friend_adorable
# Outputs True
最佳答案
只需将噪声值传递给setattr
函数即可。例如
class C(object):
pass
noise = 'mrrrr'
setattr(C, 'noise', noise)
c = C()
c.noise
# outputs 'mrrrr'
noise = 'qwe'
c.noise
# outputs 'mrrrr'
编辑:用于出于某种原因需要 getter 函数的情况。
您可以使用中间值。
class D(object):
pass
noise = 'mrrrr'
setattr(D, '_noise', noise)
setattr(D, 'noise', property(lambda self: self._noise))
d = D()
d.noise
# Outputs 'mrrrr'
noise = 'pheew'
d.noise
# Outputs 'mrrrr'
编辑 2:使用偏函数。
import functools
class E(object):
pass
noise = 'mrrrr'
getter = lambda _, noise: noise
partial = functools.partial(getter, noise=noise)
setattr(E, 'noise', property(partial))
e = E()
e.noise
# Outputs 'mrrrr'
noise = 'fooooo'
e.noise
# Outputs 'mrrrr'
关于Python - 传递对象值而不是引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40664893/