是否有用于处理Python对象地址的Python模块?

时间:2010-09-10 11:15:18

标签: python object namespaces object-address

(当我说“对象地址”时,我的意思是你在Python中键入的用于访问对象的字符串。例如'life.State.step'。大多数时候,最后一个点之前的所有对象都是包/模块,但在某些情况下,它们可以是类或其他对象。)

在我的Python project中,我经常需要使用对象地址。我必须完成的一些任务:

  1. 给定一个对象,获取其地址。
  2. 给定一个地址,获取对象,在途中导入任何所需的模块。
  3. 通过删除冗余的中间模块来缩短对象的地址。 (例如,'life.life.State.step'可能是对象的官方地址,但如果'life.State.step'指向同一个对象,我会想要使用它,因为它更短。)
  4. 通过“生根”指定的模块来缩短对象的地址。 (例如,'garlicsim_lib.simpacks.prisoner.prisoner.State.step'可能是对象的官方地址,但我假设用户知道prisoner包的位置,所以我想使用'prisoner.prisoner.State.step'作为地址。)
  5. 是否有处理类似事情的模块/框架?我写了一些实用程序模块来做这些事情,但是如果有人已经编写了一个更成熟的模块来执行此操作,我宁愿使用它。

    一个注意事项:请不要试图向我展示这些事情的快速实施。它比看起来更复杂,有很多陷阱,任何快速脏代码都可能在许多重要情况下失败。这些任务需要经过实战考验的代码。

    更新:当我说“对象”时,我主要是指类,模块,函数,方法,这些东西。很抱歉没有说清楚。

4 个答案:

答案 0 :(得分:5)

简短的回答:不。你想要的是不可能的。

答案很长,你认为对象的“地址”就是这样。 life.State.step仅仅是在特定时间获取对象的引用的方法之一。稍后相同的“地址”可以给你一个不同的对象,或者它可能是一个错误。更重要的是,你的的这个“地址”取决于上下文。在life.State.step中,结束对象不仅取决于life.Statelife.State.step是什么,还取决于名称life在该命名空间中引用的对象

您的要求的具体答案:

  1. 结束对象无法找到你引用它的方式,也没有任何你给对象的代码。 “地址”不是名称,它不依赖于对象,它只是一个任意的Python表达式,导致对象引用(就像所有表达式一样。)你只能使这个工作,几乎 ,具有不期望移动的特定对象,例如类和模块。即便如此,那些的对象可以移动,并经常移动,所以你尝试的可能会破坏。

  2. 如上所述,“地址”取决于很多内容,但这部分相当简单:__import__()getattr()可以为您提供这些内容。然而,它们将非常脆弱,特别是当涉及的内容多于属性访问时。它只能远程处理模块中的内容。

  3. “缩短”名称需要检查每个可能的名称,意味着所有模块和所有本地名称,以及它们的所有属性,这些都是不可思议的。这将是一个非常缓慢且耗时的过程,面对任何使用__getattr____getattribute__方法的任何事物,或者使用不仅仅返回值的属性,都会非常脆弱。

  4. 与3相同。

答案 1 :(得分:4)

我发布了address_tools模块,它完全符合我的要求。

Here is the codeHere are the tests

它是GarlicSim的一部分,因此您可以installing garlicsim使用它并执行from garlicsim.general_misc import address_tools。其主要功能是describeresolve,它们与repreval平行。文档字符串解释了这些函数如何工作的一切。

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对象地址。”