getattr(dir,"__name__") is dir.__name__
的计算结果为False
-getattr
的替代品是否会产生True
?
答案 0 :(得分:3)
内置函数的__name__
属性是implemented (on the CPython reference interpreter) as a property(从技术上来说,是一个获取集描述符),而不是以Python对象的形式存储为属性。
属性的作用类似于属性,但是在请求值时调用函数,在这种情况下为the function converts the C-style string name of the function to a Python str
on demand。因此,每当您查询dir.__name__
时,就会得到代表数据的全新构建的str
; as noted in the comments,这意味着没有方式拥有is
检查通行证;甚至dir.__name__ is dir.__name__
也会返回False
,因为每次__name__
的查询都会返回一个新的str
。
该语言不能保证__name__
的实现方式,因此您不应该假定它每次都返回相同的对象。语言保证的单例很少(None
,True
,False
,Ellipsis
和NotImplemented
是唯一元素,并且所有类都有唯一的标识);假设is
在不是您控制创建的对象的情况下可以与该集合中的任何东西一起工作是一个坏主意。如果要检查值是否相同,请使用==
而不是is
进行测试。
更新以解决遍历任意python对象图的问题,而不会被动态生成对象的描述符和其他内容(例如__getattr__
)所困扰(因此不应被调用以描述静态图):
The inspect.getattr_static
function应该让您“遍历从起始对象可到达的任意python对象图,同时尽可能少地考虑对象的类型及其属性的实现”(如your comment requested)。当该属性实际上是一个属性时,它会返回值,但不会触发对描述符(如@property
,__getattr__
或__getattribute__
的动态查找。因此inspect.getattr_static(dir, '__name__')
将返回CPython用于实现getset_descriptor
的{{1}},而无需实际检索字符串。在另一个__name__
是真实属性的对象(例如__name__
模块本身)上,它将返回该属性(inspect
返回inspect.getattr_static(inspect, '__name__')
)。
虽然它并不完美(某些属性实际上可能由真实的Python对象支持,而不是动态生成的对象,否则无法访问),但这至少是一个可行的解决方案;您将不会最终偶然创建新对象,也不会最终陷入无限的属性查找循环中(例如,每个可调用对象都可以一直在其上'inspect'
进行查找,并不断进行遍历),这样您至少可以找到一个能够大部分准确地反映对象图并且最终不会递归使用的解决方案。
值得注意的是,它将适当地保留身份语义。如果两个对象具有相同的属性(按标识),则结果将符合预期。如果两个对象共享一个描述符(例如,所有内置函数的__call__
,例如__name__
,bin
),则它将返回描述符本身,该标识符将与身份匹配。而且,这一切都不需要预先知道您所拥有的是属性还是描述符。