Есть ли модуль Python для обработки адресов объектов Python? - PullRequest
0 голосов
/ 10 сентября 2010

(Когда я говорю «адрес объекта», я имею в виду строку, которую вы вводите в 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' в качестве адреса.)

Есть ли модуль / каркас, который обрабатывает подобные вещи? Я написал несколько служебных модулей для этих целей, но если кто-то уже написал более зрелый модуль, который делает это, я бы предпочел использовать это.

Одно примечание: пожалуйста, не пытайтесь показать мне быструю реализацию этих вещей. Это сложнее, чем кажется, есть много ошибок, и любой быстрый-грязный код, вероятно, потерпит неудачу во многих важных случаях. Такие задачи требуют проверенного кода.

ОБНОВЛЕНИЕ: Когда я говорю «объект», я в основном имею в виду классы, модули, функции, методы и тому подобное. Извините, что не разъяснил это раньше.

Ответы [ 4 ]

5 голосов
/ 10 сентября 2010

Краткий ответ: Нет. То, что вы хотите, невозможно.

Длинный ответ заключается в том, что то, что вы называете «адресом» объекта, совсем не так.life.State.step - это просто один из способов получить ссылку на объект в это конкретное время .Тот же «адрес» на более позднем этапе может дать вам другой объект, или это может быть ошибкой.Более того, ваш «адрес» зависит от контекста life.State.step конечный объект зависит не только от того, что есть life.State и life.State.step, но и к какому объекту относится имя life в этом пространстве имен .

Конкретные ответына ваши запросы:

  1. Конечный объект не имеет никакого способа выяснить, как вы ссылались на него, и ни один из них не имеет кода, которому вы передаете объект.«Адрес» не является именем, он не привязан к объекту, это просто произвольное выражение Python, которое приводит к ссылке на объект (как и все выражения.) Вы можете только сделать эту работу, едва ,с конкретными объектами, которые не должны перемещаться, такими как классы и модули.Тем не менее, эти объекты могут перемещаться и часто делать перемещаться, поэтому то, что вы пытаетесь, может сломаться.

  2. Как уже упоминалось«адрес» зависит от многих вещей, но эта часть довольно проста: __import__() и getattr() могут дать вам эти вещи.Однако они будут чрезвычайно хрупкими, особенно когда речь идет не только о доступе к атрибутам.Он может только удаленно работать с вещами, которые находятся в модулях.

  3. «Сокращение» имени требует проверки каждого возможного имени , то есть всех модулей и всех локальных имен, и все их атрибуты , рекурсивно.Это был бы очень медленный и трудоемкий процесс и чрезвычайно хрупкий перед лицом всего, что связано с методом __getattr__ или __getattribute__, или со свойствами, которые не только возвращают значение.

  4. - это то же самое, что и 3.

4 голосов
/ 24 декабря 2010

Я выпустил модуль address_tools, который делает именно то, что я просил.

Вот код . Вот тесты .

Это часть GarlicSim , так что вы можете использовать его, установив garlicsim и выполнив from garlicsim.general_misc import address_tools.Его основными функциями являются describe и resolve, которые параллельны repr и eval.Строки документации объясняют все о том, как работают эти функции.

Существует даже версия Python 3 для Python 3 форка GarlicSim .Установите его, если хотите использовать address_tools в коде Python 3.

1 голос
/ 10 сентября 2010

Для пунктов 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).

Кодирование вещей таким способом весьма необычно.

0 голосов
/ 27 января 2011

В Twisted есть # 2 в виде twisted / python / refle.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, как в мире будет какой-либо общий пакет, удовлетворяющий этим потребностям в именовании?

В любом случае, вы написали

Пожалуйста, не пытайтесь показать мне быструю реализацию этих вещей.Это сложнее, чем кажется, есть много ошибок, и любой быстрый-грязный код, вероятно, потерпит неудачу во многих важных случаях.Такие задачи требуют проверенного в бою кода.

, поэтому не думайте о моих примерах как о решениях, а как о том, почему то, о чем вы просите, не имеет большого смысла.Это такое хрупкое пространство для решения, и у немногих, кто рискует там (в основном из любопытства), возникают такие разные проблемы, что одноразовое индивидуальное решение - лучшее.Модуль для большинства из них не имеет смысла, и если бы он имел смысл, объяснение того, что делает модуль, вероятно, было бы длиннее, чем код.

И, следовательно, ответ на ваш вопрос «нет, естьтаких модулей нет. "

Что делает ваш вопрос еще более запутанным, так это то, что реализация Python на C уже определяет" адрес объекта ". документы для id () говорят:

Подробности реализации CPython: Это адрес объекта.

Что вы ищетеэто имя или путь к объекту.Не "адрес объекта Python".

...