如何在不装箱的情况下动态访问 python 中的对象属性?
How to dynamically access object attributes in python without boxing?
getattr(dir,"__name__") is dir.__name__
的计算结果为 False
- 是否有 getattr
的替代方法会产生 True
?
built-in 函数的 __name__
属性是 implemented (on the CPython reference interpreter) as a property(从技术上讲,是一个 get-set 描述符),不是以 [=70] 的形式存储为属性=]对象。
属性的作用类似于属性,但在请求值时会调用一个函数,在本例中,the function converts the C-style string name of the function to a Python str
on demand. So each time you look up dir.__name__
, you get freshly constructed str
representing the data; ,这意味着 没有 方法is
检查通过;甚至 dir.__name__ is dir.__name__
returns False
,因为每次查找 __name__
return 都会生成一个新的 str
.
该语言不保证 __name__
的实现方式,因此您不应假设它每次 return 都是同一个对象。很少有语言保证的单例(None
、True
、False
、Ellipsis
和 NotImplemented
是大佬,所有 类 都有唯一身份);如果 is
不是您控制创建的对象,那么假设 is
可以处理不在该集合中的任何对象是一个坏主意。如果要检查 值 是否相同,请使用 ==
进行测试,而不是 is
.
更新以解决遍历 python 对象的任意图而不会被动态生成对象的描述符和其他东西(如 __getattr__
)挂起 (因此不应调用来描述静态图):
The inspect.getattr_static
function should let you "traverse an arbitrary graph of python objects reachable from a starting one while assuming as little possible about the types of objects and the implementation of their attributes" (as )。当属性实际上是一个属性时,它 return 是值,但它不会触发描述符的动态查找(如 @property
)、__getattr__
或 __getattribute__
。因此 inspect.getattr_static(dir, '__name__')
将 return CPython 用于实现 __name__
的 getset_descriptor
而无需实际检索字符串。在 __name__
是真实属性的不同对象上(例如 inspect
模块本身),它将 return 属性(inspect.getattr_static(inspect, '__name__')
returns 'inspect'
).
虽然它并不完美(某些属性实际上可能由真实的 Python 对象支持,而不是动态生成的对象,否则您无法访问),但它至少是一个可行的解决方案;你不会无意中创建新对象,也不会陷入 属性 查找的无限循环(例如,每个可调用对象都可以 __call__
永远查找它,将自己包裹起来并就这样结束了),所以你至少可以得到一个解决方案,它主要准确地反映了对象图,并且不会以递归的方式结束。
值得注意的是,它将正确地保留身份语义。如果两个对象具有相同的属性(按标识),则结果将按预期匹配。如果两个对象共享一个描述符(例如 __name__
用于所有 built-in 函数,例如 bin
、dir
),那么它 return 就是描述符本身,它将匹配身份。如果您拥有的是属性或描述符,它就可以完成这一切,而无需预先知道。
getattr(dir,"__name__") is dir.__name__
的计算结果为 False
- 是否有 getattr
的替代方法会产生 True
?
built-in 函数的 __name__
属性是 implemented (on the CPython reference interpreter) as a property(从技术上讲,是一个 get-set 描述符),不是以 [=70] 的形式存储为属性=]对象。
属性的作用类似于属性,但在请求值时会调用一个函数,在本例中,the function converts the C-style string name of the function to a Python str
on demand. So each time you look up dir.__name__
, you get freshly constructed str
representing the data; is
检查通过;甚至 dir.__name__ is dir.__name__
returns False
,因为每次查找 __name__
return 都会生成一个新的 str
.
该语言不保证 __name__
的实现方式,因此您不应假设它每次 return 都是同一个对象。很少有语言保证的单例(None
、True
、False
、Ellipsis
和 NotImplemented
是大佬,所有 类 都有唯一身份);如果 is
不是您控制创建的对象,那么假设 is
可以处理不在该集合中的任何对象是一个坏主意。如果要检查 值 是否相同,请使用 ==
进行测试,而不是 is
.
更新以解决遍历 python 对象的任意图而不会被动态生成对象的描述符和其他东西(如 __getattr__
)挂起 (因此不应调用来描述静态图):
The inspect.getattr_static
function should let you "traverse an arbitrary graph of python objects reachable from a starting one while assuming as little possible about the types of objects and the implementation of their attributes" (as @property
)、__getattr__
或 __getattribute__
。因此 inspect.getattr_static(dir, '__name__')
将 return CPython 用于实现 __name__
的 getset_descriptor
而无需实际检索字符串。在 __name__
是真实属性的不同对象上(例如 inspect
模块本身),它将 return 属性(inspect.getattr_static(inspect, '__name__')
returns 'inspect'
).
虽然它并不完美(某些属性实际上可能由真实的 Python 对象支持,而不是动态生成的对象,否则您无法访问),但它至少是一个可行的解决方案;你不会无意中创建新对象,也不会陷入 属性 查找的无限循环(例如,每个可调用对象都可以 __call__
永远查找它,将自己包裹起来并就这样结束了),所以你至少可以得到一个解决方案,它主要准确地反映了对象图,并且不会以递归的方式结束。
值得注意的是,它将正确地保留身份语义。如果两个对象具有相同的属性(按标识),则结果将按预期匹配。如果两个对象共享一个描述符(例如 __name__
用于所有 built-in 函数,例如 bin
、dir
),那么它 return 就是描述符本身,它将匹配身份。如果您拥有的是属性或描述符,它就可以完成这一切,而无需预先知道。