嵌套子对象/链接属性上的getattr和setattr?
我有一个对象(Person
),其中有多个子对象(Pet, Residence
)作为属性。我希望能够像这样动态设置这些子对象的属性:
class Person(object):
def __init__(self):
self.pet = Pet()
self.residence = Residence()
class Pet(object):
def __init__(self,name='Fido',species='Dog'):
self.name = name
self.species = species
class Residence(object):
def __init__(self,type='House',sqft=None):
self.type = type
self.sqft=sqft
if __name__=='__main__':
p=Person()
setattr(p,'pet.name','Sparky')
setattr(p,'residence.type','Apartment')
print p.__dict__
目前我得到了错误的输出: {'pet': <__main__.Pet object at 0x10c5ec050>, 'residence':
<__main__.Residence object at 0x10c5ec0d0>, 'pet.name': 'Sparky',
'residence.type': 'Apartment'}
如您所见,不是name
在的Pet
子对象上设置属性,而是在上创建Person
了新属性。pet.name``Person
-
我无法指定
person.pet
,setattr()
因为将通过相同的方法设置不同的子对象,该方法将解析一些文本并在/找到相关键时填充对象属性。 -
是否有简单/内置的方法来完成此任务?
-
还是我需要编写一个递归函数来解析字符串并
getattr()
多次调用,直到找到必要的子对象,然后再调用setattr()
找到的子对象?
-
您可以使用
functools.reduce
:import functools def rsetattr(obj, attr, val): pre, _, post = attr.rpartition('.') return setattr(rgetattr(obj, pre) if pre else obj, post, val) # using wonder's beautiful simplification: https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects/31174427?noredirect=1#comment86638618_31174427 def rgetattr(obj, attr, *args): def _getattr(obj, attr): return getattr(obj, attr, *args) return functools.reduce(_getattr, [obj] + attr.split('.'))
rgetattr
并且rsetattr
是插入式替代getattr
和setattr
,这也可以处理点attr
串。
import functools class Person(object): def __init__(self): self.pet = Pet() self.residence = Residence() class Pet(object): def __init__(self,name='Fido',species='Dog'): self.name = name self.species = species class Residence(object): def __init__(self,type='House',sqft=None): self.type = type self.sqft=sqft def rsetattr(obj, attr, val): pre, _, post = attr.rpartition('.') return setattr(rgetattr(obj, pre) if pre else obj, post, val) def rgetattr(obj, attr, *args): def _getattr(obj, attr): return getattr(obj, attr, *args) return functools.reduce(_getattr, [obj] + attr.split('.'))
if __name__=='__main__': p = Person() print(rgetattr(p, 'pet.favorite.color', 'calico')) # 'calico' try: # Without a default argument, `rgetattr`, like `getattr`, raises # AttributeError when the dotted attribute is missing print(rgetattr(p, 'pet.favorite.color')) except AttributeError as err: print(err) # 'Pet' object has no attribute 'favorite' rsetattr(p, 'pet.name', 'Sparky') rsetattr(p, 'residence.type', 'Apartment') print(p.__dict__) print(p.pet.name) # Sparky print(p.residence.type) # Apartment