How to dynamically change a property?
My problem is quite simple, I have a string that contains a path to a property, and I want to change that property through the string.
str = "someClass.property"
data = 123
'''
I don't know what str contains, as it is create开发者_StackOverflow中文版d 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" )
How do I acheive what I did above without touching exec()
?
You could use setattr
:
setattr(someClass, property, data)
Note that this is still dangerous if done without any user validation as your user could change the definition of existing attributes that they should not be able to modify.
A safer alternative is to use a dict
as a key-value store and put the user-defined properties in there.
First of all, do you want to set the property on a class or an instance? In general, the best approach is to use a registry to register the objects (classes or instances) you want to change. This can be a simple dictionary:
registry = {}
Then explicitly register those objects you want to be changable by the user, e.g.
class Foo(object):
pass
f1 = Foo()
f2 = Foo()
registry['Foo'] = Foo
registry['f1'] = f1
registry['f2'] = f2
For classes in general you could encapsulate this a bit more by using <<class>>.__name__
.
Lookup is easy and will fail nicely for anything that shouldn't be changable:
objectname, propertyname = str.split('.', 1)
o = registry[objectname]
Finally, setting the property can be done using setattr:
setattr(o, propertyname, data)
or a bit more OO-ish by defining explicit setting behaviour that can actually check the properties, e.g.
class Settable(object):
allowed = ('foo', 'bar')
def set(self, prop, val):
if prop not in self.allowed:
raise KeyError, prop
setattr(self, prop, val)
and derive from this class in stead:
class Foo(Settable):
allowed = Settable.allowed + ('blah',)
registry[objectname].set(propertyname, data)
精彩评论