-4

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

在我的Python 项目中,我经常需要处理对象地址。我必须做的一些任务:

  1. 给定一个对象,获取它的地址。
  2. 给定地址,获取对象,在途中导入任何需要的模块。
  3. 通过去掉冗余的中间模块来缩短对象的地址。(例如,'life.life.State.step'可能是一个对象的官方地址,但如果'life.State.step'指向同一个对象,我想用它来代替,因为它更短。)
  4. 通过“生根”指定模块来缩短对象的地址。(例如,'garlicsim_lib.simpacks.prisoner.prisoner.State.step'可能是一个对象的官方地址,但我假设用户知道prisoner包裹在哪里,所以我想'prisoner.prisoner.State.step'用作地址。)

是否有处理此类事情的模块/框架?我写了一些实用模块来做这些事情,但是如果有人已经写了一个更成熟的模块来做这些事情,我更愿意使用它。

请注意:请不要试图向我展示这些东西的快速实现。它比看起来更复杂,有很多陷阱,任何快速-n-脏代码都可能在许多重要情况下失败。这类任务需要经过实战测试的代码。

更新:当我说“对象”时,我主要指的是类、模块、函数、方法等。很抱歉之前没有说清楚。

4

4 回答 4

5

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

长答案是,您认为对象的“地址”绝不是。life.State.step只是在特定时间获取对对象的引用的方法之一。稍后相同的“地址”可以给你一个不同的对象,或者它可能是一个错误。更何况,你的这个“地址”还要看上下文。在life.State.step中,最终对象不仅取决于什么life.Statelife.State.step是,还取决于名称在该名称空间中所指的对象life

对您的要求的具体答复:

  1. 最终对象无法找出您是如何引用它的,也没有任何您将对象提供给的代码。“地址”不是一个名称,它与对象无关,它只是一个导致对象引用的任意 Python 表达式(就像所有表达式一样。)你只能勉强使用特定的对象来完成这项工作。 t 期望移动,例如类和模块。即便如此,这些物体还是可以四处移动,并且经常四处移动,所以尝试的东西很可能会破裂。

  2. 如前所述,“地址”取决于很多东西,但这部分相当容易:__import__()并且getattr()可以给你这些东西。然而,它们将非常脆弱,尤其是当涉及的不仅仅是属性访问时。它只能远程处理模块中的东西。

  3. “缩短”名称需要反复检查每个可能的名称,这意味着所有模块和所有本地名称,以及它们的所有属性。这将是一个非常缓慢且耗时的过程,并且在面对任何带有__getattr__or__getattribute__方法的东西或具有不仅仅是返回值的属性时都非常脆弱。

  4. 和3是一样的。

于 2010-09-10T11:37:50.743 回答
4

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

这是代码这是测试

它是GarlicSim的一部分,因此您可以通过安装garlicsim和执行来使用它from garlicsim.general_misc import address_tools。它的主要功能是describe和,与和resolve平行。文档字符串解释了有关这些函数如何工作的所有内容。repreval

GarlicSim的 Python 3 分支上甚至还有一个 Python 3 版本。如果您想address_tools在 Python 3 代码上使用,请安装它。

于 2010-12-23T22:52:24.527 回答
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)。

然而,以这种方式编码是非常不寻常的。

于 2010-09-10T11:34:06.463 回答
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,世界上任何通用包将如何满足这些命名需求?

无论如何,你写了

请不要试图向我展示这些东西的快速实现。它比看起来更复杂,有很多陷阱,任何快速-n-脏代码都可能在许多重要情况下失败。这类任务需要经过实战测试的代码。

因此,不要将我的示例视为解决方案,而是将其视为您所要求的示例毫无意义的示例。这是一个如此脆弱的解决方案空间,很少有人冒险(主要是出于好奇)有如此不同的担忧,以至于一次性定制解决方案是最好的选择。其中大多数的模块是没有意义的,如果它确实有意义,那么对模块作用的解释可能会比代码更长。

因此,您的问题的答案是“不,没有这样的模块”。

让您的问题更令人困惑的是 Python 的 C 实现已经定义了一个“对象地址”。id()的文档说:

CPython 实现细节:这是对象的地址。

您要查找的是对象的名称或路径。不是“Python 对象地址”。

于 2011-01-27T20:05:58.463 回答