问题描述
我有一个对象(Person
),该对象具有多个子对象(Pet, Residence
)作为属性.我希望能够像这样动态设置这些子对象的属性:
I have an object (Person
) that has multiple subobjects (Pet, Residence
) as properties. I want to be able to dynamically set the properties of these subobjects like so:
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'}
Currently I get the wrong output: {'pet': <__main__.Pet object at 0x10c5ec050>, 'residence': <__main__.Residence object at 0x10c5ec0d0>, 'pet.name': 'Sparky', 'residence.type': 'Apartment'}
如您所见,不是在Person
的Pet
子对象上设置name
属性,而是在Person
上创建了一个新的属性pet.name
.
As you can see, instead of setting the name
attribute on the Pet
subobject of the Person
, a new attribute pet.name
is created on the Person
.
-
我无法指定
person.pet
至setattr()
,因为将通过相同的方法设置不同的子对象,该方法将解析某些文本并在找到相关关键字时填充对象属性.
I cannot specify
person.pet
tosetattr()
because different sub-objects will be set by the same method, which parses some text and fills in the object attributes if/when a relevant key is found.
是否有简单/内置的方式来完成此任务?
Is there a easy/builtin way to accomplish this?
或者也许我需要编写一个递归函数来解析字符串并多次调用getattr()
直到找到必要的子对象,然后在找到的子对象上调用setattr()
?
Or perhaps I need to write a recursive function to parse the string and call getattr()
multiple times until the necessary subobject is found and then call setattr()
on that found subobject?
推荐答案
您可以使用 functools.reduce
:
You could use 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
字符串.
rgetattr
and rsetattr
are drop-in replacements for getattr
and setattr
,which can also handle dotted attr
strings.
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
这篇关于嵌套子对象/链接属性上的getattr和setattr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!