是否有用于处理Python对象地址的Python模块?
-
02-10-2019 - |
题
(当我说“对象地址”时,我的意思是您在python中输入的字符串以访问对象。例如 'life.State.step'
. 。在大多数情况下,最后一个点之前的所有对象都是软件包/模块,但是在某些情况下,它们可以是类或其他对象。)
在我的 Python项目 我经常需要使用对象地址来玩耍。我必须做的一些任务:
- 给定一个对象,获取其地址。
- 给定一个地址,获取对象,在途中导入任何所需的模块。
- 通过摆脱冗余中间模块来缩短对象的地址。 (例如,
'life.life.State.step'
可能是对象的官方地址,但是如果'life.State.step'
指向同一对象,我想改用它,因为它短。) - 通过“扎根”指定的模块缩短对象的地址。 (例如,
'garlicsim_lib.simpacks.prisoner.prisoner.State.step'
可能是对象的官方地址,但我认为用户知道prisoner
包是,所以我想使用'prisoner.prisoner.State.step'
作为地址。)
是否有一个可以处理类似事物的模块/框架?我写了一些实用程序模块来做这些事情,但是如果有人已经编写了一个更成熟的模块来做到这一点,那么我更喜欢使用它。
一张注意:请,不要试图向我展示这些事情的快速实施。它比看起来更复杂,有很多陷阱,并且在许多重要情况下,任何快速的n dirty代码都可能失败。这类任务要求进行战斗测试代码。
更新: 当我说“对象”时,我主要是指类,模块,函数,方法,类似的内容。抱歉,以前没有清楚这一点。
解决方案 2
我发布了 address_tools
模块完全可以完成我的要求。
这是 Garlicsim, ,因此您可以使用它 安装 garlicsim
并做 from garlicsim.general_misc import address_tools
. 。它的主要功能是 describe
和 resolve
, ,平行于 repr
和 eval
. 。 DocStrings解释了有关这些功能如何工作的一切。
甚至还有一个python 3版本 python 3叉子芯. 。如果要使用,请安装它 address_tools
在Python 3代码上。
其他提示
简短答案:不,您想要什么是不可能的。
漫长的答案是,您认为对象的“地址”只是什么。 life.State.step
只是获取对象的引用的方法之一 在那个特定的时间. 。稍后的相同的“地址”可以给您一个不同的对象,也可能是错误。更重要的是,您的这个“地址” 取决于上下文. 。在 life.State.step
, ,最终对象不仅取决于什么 life.State
和 life.State.step
是,但是 什么对象名称 life
指在该名称空间中.
您请求的具体答案:
最终对象具有 绝对没有办法 找出您如何提及它,并且都没有任何代码给对象。 “地址”不是一个名称,它与对象没有绑定,它只是一个任意的python表达式,导致对象参考(如所有表达式所做的。)您只能使此工作, 仅仅, ,没有期望四处走动的特定对象,例如类和模块。即使这样,这些对象 能够 四处走动 做 四处走动,因此您可能会打破什么。
如前所述,“地址”取决于许多事情,但是这部分非常容易:
__import__()
和getattr()
可以给你这些东西。但是,它们将非常脆弱,尤其是当涉及更多不仅仅是归因访问时。它只能与模块中的事物进行远程配合。“缩短”名称需要检查 每个可能的名字, ,表示所有模块和所有本地名称,以及 他们的所有属性, ,招聘。这将是一个非常缓慢且耗时的过程,面对任何事物,
__getattr__
或者__getattribute__
方法,或具有返回值更多的属性。与3是同一件事。
对于第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
, , 例如)。
但是,以这种方式进行编码是非常不寻常的。
扭曲的#2为扭曲/python/frofe.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'
>>>
在这里,您可以看到“处理程序”实际上是从先前的表达式返回中_中的,使其成为最短的名称。
如果您想要其他东西,例如递归搜索所有模块的所有成员,则只需对其进行编码。但是,正如“ _”示例所示,会有惊喜。另外,这不是稳定的,因为导入另一个模块可能会使另一个对象路径可用并更短。
这就是为什么人们一遍又一遍地说您想要的东西实际上对任何事情都没有用,这就是为什么没有模块的原因。
至于您的#4,在世界上,任何一般包裹如何满足这些命名需求?
无论如何,您写道
请,不要试图向我展示这些事情的快速实施。它比看起来更复杂,有很多陷阱,并且在许多重要情况下,任何快速的n dirty代码都可能失败。这类任务要求进行战斗测试代码。
因此,不要将我的示例视为解决方案,而是说明为什么要要求的内容的例子。这是一个脆弱的解决方案空间,少数在那里冒险(主要是出于好奇心)的关注点,以至于一次性定制解决方案是最好的事情。大多数这些模块没有任何意义,如果确实有意义的解释该模块所做的工作可能会比代码更长。
因此,您问题的答案是“不,没有这样的模块”。
使您的问题更加令人困惑的是,Python的C实施已经定义了“对象地址”。这 ID()的文档 说:
CPYTHON实现细节:这是对象的地址。
您正在寻找的是名称或对象的路径。不是“ Python对象地址”。