Frage

(Wenn ich „Objektadresse“ sage, meine ich die Zeichenfolge, die Sie in Python zu Zugriffstyp ein Objekt, z. B. 'life.State.step'. Die meiste Zeit, alle die Objekte vor dem letzten Punkt werden Pakete / Module, sondern in In einigen Fällen können sie Klassen oder andere Objekte sein.)

In meinem Python Projekt ich oft das Bedürfnis haben, mit Objektadressen zu spielen, um. Einige Aufgaben, die ich tun:

  1. ein Objekt gegeben, erhält seine Adresse.
  2. eine Adresse gegeben, erhalten Sie das Objekt, alle erforderlichen Module auf dem Weg zu importieren.
  3. Shorten eine Adresse des Objekts durch redundante Zwischenmodule loszuwerden. (Zum Beispiel 'life.life.State.step' kann die offizielle Adresse eines Objekts sein, aber wenn 'life.State.step' Punkte auf das gleiche Objekt, möchte ich würde es verwenden, anstatt, weil es kürzer ist.)
  4. Shorten eine Adresse des Objekts durch „Verwurzelung“ angegebenen Moduls. (Zum Beispiel 'garlicsim_lib.simpacks.prisoner.prisoner.State.step' kann die offizielle Adresse eines Objekts sein, aber ich nehme an, dass der Benutzer weiß, wo das prisoner Paket ist, so möge ich würde 'prisoner.prisoner.State.step' als die Adresse verwenden.)

Gibt es ein Modul / framework dass Griffe Dinge wie das? Ich schrieb ein paar Dienstprogramm Module, diese Dinge zu tun, aber wenn jemand schon geschrieben hat ein reiferen Modul, das dies tut, ich würde es vorziehen, dass zu verwenden.

Eine Anmerkung: Bitte versuchen Sie nicht, mir eine schnelle Umsetzung dieser Dinge zu zeigen. Es ist komplizierter, als es scheint, gibt es viele Fallstricke sind, und jede Schnell n-dirty-Code wird wahrscheinlich für viele wichtige Fälle scheitern. Diese Art von Aufgaben erfordern kampferprobten Code.

UPDATE: Wenn ich "Objekt" sagen, dass ich meist mittleren Klassen, Module, Funktionen, Methoden, Sachen wie diese. Es tut uns nicht machen dies deutlich vor.

War es hilfreich?

Lösung 2

I released the address_tools module which does exactly what I asked for.

Here is the code. Here are the tests.

It's part of GarlicSim, so you can use it by installing garlicsim and doing from garlicsim.general_misc import address_tools. Its main functions are describe and resolve, which are parallel to repr and eval. The docstrings explain everything about how these functions work.

There is even a Python 3 version on the Python 3 fork of GarlicSim. Install it if you want to use address_tools on Python 3 code.

Andere Tipps

Short answer: No. What you want is impossible.

The long answer is that what you think of as the "address" of an object is anything but. life.State.step is merely one of the ways to get a reference to the object at that particular time. The same "address" at a later point can give you a different object, or it could be an error. What's more, this "address" of yours depends on the context. In life.State.step, the end object depends not just on what life.State and life.State.step are, but what object the name life refers to in that namespace.

Specific answers to your requests:

  1. The end object has no way whatsoever of finding out how you referred to it, and neither has any code that you give the object to. The "address" is not a name, it's not tied to the object, it's merely an arbitrary Python expression that results in an object reference (as all expressions do.) You can only make this work, barely, with specific objects that aren't expected to move around, such as classes and modules. Even so, those objects can move around, and frequently do move around, so what you attempt is likely to break.

  2. As mentioned, the "address" depends on many things, but this part is fairly easy: __import__() and getattr() can give you these things. They will, however, be extremely fragile, especially when there's more involved than just attribute access. It can only remotely work with things that are in modules.

  3. "Shortening" the name requires examining every possible name, meaning all modules and all local names, and all attributes of them, recrusively. It would be a very slow and time-consuming process, and extremely fragile in the face of anything with a __getattr__ or __getattribute__ method, or with properties that do more than return a value.

  4. is the same thing as 3.

For points 3 and 4, I guess that you are looking for facilities like

from life import life  # life represents life.life
from garlicsim_lib.simpacks import prisoner

However, this is not recommended, as it makes it harder for you or people who read your code to quickly know what prisoner represents (where module does it come from? you have to look at the beginning of the code to get this information).

For point 1, you can do:

from uncertainties import UFloat

print UFloat.__module__  # prints 'uncertainties'

import sys
module_of_UFloat = sys.modules[UFloat.__module__]

For point 2, given the string 'garlicsim_lib.simpacks.prisoner', you can get the object it refers to with:

obj = eval('garlicsim_lib.simpacks.prisoner')

This supposes that you have imported the module with

import garlicsim_lib  # or garlicsim_lib.simpacks

If you even want this to be automatic, you can do something along the lines of

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()

This works only in the simplest cases (garlicsim_lib.simpacks need to be available in garlicsim_lib, for instance).

Coding things this way is, however, highly unusual.

Twisted has #2 as twisted/python/reflect.py . You need something like it for making a string-based configuration system, like with Django's urls.py configuration.

Take a look at the code and the version control log to see what they had to do to make it work - and fail! - the right way.

The other things you are looking for place enough restrictions on the Python environment that there is no such thing as a general purpose solution.

Here's something which somewhat implements your #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'
>>> 

Your #3 is underdefined. If I do

__builtin__.step = path.to.your.stap

then should the search code find it as "step"?

The simplest implementation I can think of simply searches all modules and looks for top-level elements which are exactly what you want

>>> 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'
>>> 

Here you can see that 'handler' was actually in _ from the previous expression return, making it the shortest name.

If you want something else, like recursively searching all members of all modules, then just code it up. But as the "_" example shows, there will be surprises. Plus, this isn't stable, since importing another module might make another object path available and shorter.

That's why people say over and over again that what you want isn't actually useful for anything, and that's why there's no modules for it.

And as for your #4, how in the world will any general package cater to those naming needs?

In any case, you wrote

Please, don't try to show me a quick implementation of these things. It's more complicated than it seems, there are plenty of gotchas, and any quick-n-dirty code will probably fail for many important cases. These kind of tasks call for battle-tested code.

so don't think of my examples as solutions but as examples of why what you're asking for makes little sense. It's such a fragile solution space adn the few who venture there (mostly for curiosity) have such different concerns that a one-off custom solution is the best thing. A module for most of these makes no sense, and if it did make sense the explanation of what the module does would probably be longer than the code.

And hence the answer to your question is "no, there are no such modules."

What makes your question even more confusing is that the C implementation of Python already defines an "object address". The docs for id() say:

CPython implementation detail: This is the address of the object.

What you're looking for is the name, or the path to the object. Not the "Python object address."

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top