class A(): pass
a = A()
b = A()
a.b = b
b.c = 1
a.b # this is b
getattr(a, "b") # so is this
a.b.c # this is 1
getattr(a, "b.c") # this raises an AttributeError
Run Code Online (Sandbox Code Playgroud)
假设后者,我似乎很自然.我确信这是有充分理由的.它是什么?
Tha*_*all 64
你不能在getattr函数中放置一个句点,因为getattr就像访问对象的字典查找一样(但由于子类化和其他Python实现细节,它比这更复杂).
如果在a上使用'dir'函数,您将看到与对象属性对应的字典键.在这种情况下,字符串"bc" 不在字典键集合中.
执行此操作的唯一方法getattr是嵌套调用:
getattr(getattr(a, "b"), "c")
Run Code Online (Sandbox Code Playgroud)
幸运的是,标准库有一个更好的解决方案!
import operator
operator.attrgetter("b.c")(a)
Run Code Online (Sandbox Code Playgroud)
res*_*ate 43
Python的内置reduce功能可实现您正在寻找的功能.这是一个简单的小助手功能,可以完成工作:
class NoDefaultProvided(object):
pass
def getattrd(obj, name, default=NoDefaultProvided):
"""
Same as getattr(), but allows dot notation lookup
Discussed in:
http://stackoverflow.com/questions/11975781
"""
try:
return reduce(getattr, name.split("."), obj)
except AttributeError, e:
if default != NoDefaultProvided:
return default
raise
Run Code Online (Sandbox Code Playgroud)
测试证明;
>>> getattrd(int, 'a')
AttributeError: type object 'int' has no attribute 'a'
>>> getattr(int, 'a')
AttributeError: type object 'int' has no attribute 'a'
>>> getattrd(int, 'a', None)
None
>>> getattr(int, 'a', None)
None
>>> getattrd(int, 'a', None)
None
>>> getattrd(int, '__class__.__name__')
type
>>> getattrd(int, '__class__')
<type 'type'>
Run Code Online (Sandbox Code Playgroud)
我认为你的困惑源于直点符号(ex a.b.c)访问相同的参数getattr(),但解析逻辑是不同的.虽然它们本质上都是对象__dict__属性的关键,getattr()但不受对点可访问属性的更严格要求的约束.例如
setattr(foo, 'Big fat ugly string. But you can hash it.', 2)
Run Code Online (Sandbox Code Playgroud)
是有效的,因为该字符串只是成为一个哈希键foo.__dict__,但是
foo.Big fat ugly string. But you can hash it. = 2
Run Code Online (Sandbox Code Playgroud)
和
foo.'Big fat ugly string. But you can hash it.' = 2
Run Code Online (Sandbox Code Playgroud)
是语法错误,因为现在你要求解释器将这些东西解析为原始代码,但这不起作用.
另一方面,foo.b.c相当于foo.__dict__['b'].__dict__['c'],getattr(foo, 'b.c')相当于foo.__dict__['b.c'].这就是为什么getattr不能像你期望的那样工作.
因为getattr那样不行.getattr获取具有给定名称(第二个参数)的给定对象(第一个参数)的属性.所以你的代码:
getattr(a, "b.c") # this raises an AttributeError
Run Code Online (Sandbox Code Playgroud)
表示:访问"a"引用的对象的"bc"属性.显然,您的对象没有名为" b.c"的属性.
要获得"c"属性,您必须使用两个getattr调用:
getattr(getattr(a, "b"), "c")
Run Code Online (Sandbox Code Playgroud)
让我们解开它以便更好地理解:
b = getattr(a, "b")
c = getattr(b, "c")
Run Code Online (Sandbox Code Playgroud)
我认为实现您想要的最直接的方法是使用operator.attrgetter。
>>> import operator
>>> class B():
... c = 'foo'
...
>>> class A():
... b = B()
...
>>> a = A()
>>> operator.attrgetter('b.c')(a)
'foo'
Run Code Online (Sandbox Code Playgroud)
如果该属性不存在,那么您将获得一个 AttributeError
>>> operator.attrgetter('b.d')(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: B instance has no attribute 'd'
Run Code Online (Sandbox Code Playgroud)