如何动态更改属性?

时间:2010-11-08 07:55:26

标签: python exec

我的问题很简单,我有一个包含属性路径的字符串,我想通过字符串更改该属性。

str = "someClass.property"
data = 123
'''
I don't know what str contains, as it is created by a user
I know that I could do this, but it smells like bad practice,
in PHP it's a criminal offence
'''
exec(str + " = data" )

如何在不触及exec()的情况下实现上述操作?

2 个答案:

答案 0 :(得分:3)

您可以使用setattr

setattr(someClass, property, data)

请注意,如果没有任何用户验证,这仍然很危险,因为您的用户可能会更改他们无法修改的现有属性的定义。

更安全的替代方法是使用dict作为键值存储,并将用户定义的属性放在那里。

答案 1 :(得分:0)

首先,您要在类或实例上设置属性吗?通常,最好的方法是使用注册表来注册要更改的对象(类或实例)。这可以是一个简单的字典:

registry = {}

然后显式注册您想要被用户修改的对象,例如

class Foo(object):
  pass

f1 = Foo()
f2 = Foo()

registry['Foo'] = Foo
registry['f1'] = f1
registry['f2'] = f2

对于一般的类,您可以使用<<class>>.__name__将其封装得更多一些。 查找很容易,对于任何不应该变化的东西都会很好地失败:

objectname, propertyname = str.split('.', 1)
o = registry[objectname]

最后,可以使用setattr:

设置属性
setattr(o, propertyname, data)

或者通过定义可以实际检查属性的显式设置行为来更多OO-ish,例如

class Settable(object):
  allowed = ('foo', 'bar')

  def set(self, prop, val):
    if prop not in self.allowed:
        raise KeyError, prop
    setattr(self, prop, val)

并从这个类派生而来:

class Foo(Settable):
    allowed = Settable.allowed + ('blah',)


registry[objectname].set(propertyname, data)