(当我说“对象地址”时,我的意思是你在Python中键入的用于访问对象的字符串。例如'life.State.step'
。大多数时候,最后一个点之前的所有对象都是包/模块,但在某些情况下,它们可以是类或其他对象。)
在我的Python project中,我经常需要使用对象地址。我必须完成的一些任务:
'life.life.State.step'
可能是对象的官方地址,但如果'life.State.step'
指向同一个对象,我会想要使用它,因为它更短。)'garlicsim_lib.simpacks.prisoner.prisoner.State.step'
可能是对象的官方地址,但我假设用户知道prisoner
包的位置,所以我想使用'prisoner.prisoner.State.step'
作为地址。)是否有处理类似事情的模块/框架?我写了一些实用程序模块来做这些事情,但是如果有人已经编写了一个更成熟的模块来执行此操作,我宁愿使用它。
一个注意事项:请不要试图向我展示这些事情的快速实施。它比看起来更复杂,有很多陷阱,任何快速脏代码都可能在许多重要情况下失败。这些任务需要经过实战考验的代码。
更新:当我说“对象”时,我主要是指类,模块,函数,方法,这些东西。很抱歉没有说清楚。
答案 0 :(得分:5)
简短的回答:不。你想要的是不可能的。
答案很长,你认为对象的“地址”就是这样。 life.State.step
仅仅是在特定时间获取对象的引用的方法之一。稍后相同的“地址”可以给你一个不同的对象,或者它可能是一个错误。更重要的是,你的的这个“地址”取决于上下文。在life.State.step
中,结束对象不仅取决于life.State
和life.State.step
是什么,还取决于名称life
在该命名空间中引用的对象
您的要求的具体答案:
结束对象无法找到你引用它的方式,也没有任何你给对象的代码。 “地址”不是名称,它不依赖于对象,它只是一个任意的Python表达式,导致对象引用(就像所有表达式一样。)你只能使这个工作,几乎 ,具有不期望移动的特定对象,例如类和模块。即便如此,那些的对象可以移动,并经常做移动,所以你尝试的可能会破坏。
如上所述,“地址”取决于很多内容,但这部分相当简单:__import__()
和getattr()
可以为您提供这些内容。然而,它们将非常脆弱,特别是当涉及的内容多于属性访问时。它只能远程处理模块中的内容。
“缩短”名称需要检查每个可能的名称,意味着所有模块和所有本地名称,以及它们的所有属性,这些都是不可思议的。这将是一个非常缓慢且耗时的过程,面对任何使用__getattr__
或__getattribute__
方法的任何事物,或者使用不仅仅返回值的属性,都会非常脆弱。
与3相同。
答案 1 :(得分:4)
我发布了address_tools
模块,它完全符合我的要求。
Here is the code。 Here are the tests
它是GarlicSim的一部分,因此您可以installing garlicsim
使用它并执行from garlicsim.general_misc import address_tools
。其主要功能是describe
和resolve
,它们与repr
和eval
平行。文档字符串解释了这些函数如何工作的一切。
Python 3 fork of GarlicSim上甚至还有一个Python 3版本。如果要在Python 3代码上使用address_tools
,请安装它。
答案 2 :(得分:1)
对于第3点和第4点,我猜您正在寻找像
这样的设施from life import life # life represents life.life
from garlicsim_lib.simpacks import prisoner
但是,建议不要这样做,因为这会使您或阅读代码的人更难以快速了解prisoner
所代表的内容(模块的来源是什么?您必须先查看代码的开头)获取此信息的代码。)
对于第1点,你可以这样做:
from uncertainties import UFloat
print UFloat.__module__ # prints 'uncertainties'
import sys
module_of_UFloat = sys.modules[UFloat.__module__]
对于第2点,给定字符串'garlicsim_lib.simpacks.prisoner',您可以获得它所引用的对象:
obj = eval('garlicsim_lib.simpacks.prisoner')
这假设您已使用
导入模块import garlicsim_lib # or garlicsim_lib.simpacks
如果你甚至希望这是自动的,你可以按照
的方式做点什么import imp
module_name = address_string.split('.', 1)[0]
mod_info = imp.find_module(module_name)
try:
imp.load_module(module_name, *mod_info)
finally:
# Proper closing of the module file:
if mod_info[0] is not None:
mod_info[0].close()
这仅适用于最简单的情况(例如,garlicsim_lib.simpacks
需要提供garlicsim_lib
)。
然而,以这种方式进行编码非常不寻常。
答案 3 :(得分:0)
Twisted的#2为twisted / python / reflect.py。你需要类似它来制作一个基于字符串的配置系统,比如Django的urls.py配置。
查看代码和版本控制日志,了解他们必须做些什么才能使其正常工作 - 并且失败! - 正确的方式。
您正在寻找的其他内容对Python环境施加了足够的限制,以至于没有通用解决方案。
这是一些有点实现你的#1
的东西>>> import pickle
>>> def identify(f):
... name = f.__name__
... module_name = pickle.whichmodule(f, name)
... return module_name + "." + name
...
>>> identify(math.cos)
'math.cos'
>>> from xml.sax.saxutils import handler
>>> identify(handler)
'__main__.xml.sax.handler'
>>>
您的#3未定义。如果我做
__builtin__.step = path.to.your.stap
然后搜索代码应该将其视为“步骤”吗?
我能想到的最简单的实现只是搜索所有模块并寻找顶级元素,这正是你想要的
>>> import sys
>>> def _find_paths(x):
... for module_name, module in sys.modules.items():
... if module is None:
... continue
... for (member_name, obj) in module.__dict__.items():
... if obj is x:
... yield module_name + "." + member_name
...
>>> def find_shortest_name_to_object(x):
... return min( (len(name), name) for name in _find_paths(x) )[1]
...
>>> find_shortest_name_to_object(handler)
'__builtin__._'
>>> 5
5
>>> find_shortest_name_to_object(handler)
'xml.sax.handler'
>>>
在这里你可以看到'handler'实际上是在前一个表达式返回的_中,使它成为最短的名字。
如果你想要其他东西,比如递归搜索所有模块的所有成员,那么只需编写代码即可。但正如“_”示例所示,会有惊喜。另外,这不稳定,因为导入另一个模块可能会使另一个对象路径可用且更短。
这就是为什么人们一遍又一遍地说,你想要的东西对任何东西都没有用,这就是为什么它没有模块的原因。
至于你的#4,世界上任何一般包装如何满足这些命名需求?
无论如何,你写了
请不要试图快速给我看 实施这些事情。它的 那里比看起来更复杂 有很多陷阱,任何 快速脏代码可能会失败 对于许多重要案件。这些 任务需要经过实战考验的代码。
所以不要把我的例子看成是解决方案,而是把你所要求的东西作为一个例子。这是一个如此脆弱的解决方案空间,而那些在那里冒险的人(主要是出于好奇心)有一些不同的担忧,即一次性定制解决方案是最好的。大多数这些模块没有任何意义,如果它确实有意义,模块的功能可能比代码更长。
因此,你的问题的答案是“不,没有这样的模块。”
使您的问题更加令人困惑的是,Python的C实现已经定义了“对象地址”。 docs for id()说:
CPython实现细节:这是对象的地址。
您要查找的是名称或对象的路径。不是“Python对象地址。”