1

次のことができるようになりたいです。

class PrintName:
    def __init__( self, obj ):
        print obj._name

class SetName:
    def __init__( self, name = None ): # Default name is None
        self._name = name

class Test:
    f = SetName( ) # No explicit name given
    g = PrintName( f )

この時点で、Python に 'f' を出力させたいので、PrintName( f ) が実行されるまでに、f はその名前を認識しているはずです。

私が見つけたすべての自動命名ソリューションは、作成後に属性に名前を付けました。これをメタクラスで解決しようとしましたが、それでもうまくいかないようです。

後で使用するために Python コードを「保存」および「リロード」できるようにするために、これを実行したいと思います (on-use-evaluation を使用してプログラムで変更できる原始的なスクリプト言語のようなものです)。

例えば:

x = 0
y = 0
p = ( x, y )

p を出力すると (0,0) になり、x と y で何かを実行すると、

x = 124
y = -32
p = ( x, y )

print p は (124,-32) になります。

これを行う最も簡単な方法は、

p = ( 'x', 'y' )

しかし、この場合、「x」が文字列「x」ではなく変数の名前であることをどのように知ることができますか

この目的のために単純なスクリプト言語を作成しようとしましたが、それは大変な作業であり、上記が機能する場合、Python 言語全体をスクリプトで使用できます。

私の問題に対するシンプルで柔軟な解決策を見つけようとしています。

助けてくれてありがとう。

4

2 に答える 2

1

__prepare__を使用してPython3.xで解決策を見つけることができました。これが私がやりたかったことを説明する実用的なコードです。

from collections import MutableMapping

class MDict(MutableMapping):
    def __init__(self, *args, **kwargs):
        self._d = dict(*args, **kwargs)
    def __getitem__(self, key):
        return self._d[key]
    def __setitem__(self, key, value):
        self._d[key] = value
        try:
            self._d[key]._key = key # Let's set the name of the object
        except AttributeError: # Not a good way to handle immutable objects
            pass
    def __delitem__(self, key):
        del self._d[key]
    def __iter__(self):
        return iter(self._d)
    def __len__(self):
        return len(self._d)

class MBase(type):
    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        return MDict()
    def __new__(metacls, name, bases, mdct):
        return super().__new__(metacls, name, bases, dict(mdct))
    def __str__( self ):
        return "class {0}(CSub, metaclass=MBase):".format( self.__name__ )

class CSub: # An empty class so we know when to go deeper int print_code
    pass

class Integer:
    def __init__( self, value ):
        self._value = value
    def __str__( self ):
        try: # See if it's a reference
            return "{0} = Integer( {1} )".format( self._key, self._value._key )
        except: # Not it's a number
            return "{0} = Integer( {1} )".format( self._key, self._value )

class Point:
    def __init__( self, x, y ):
        if type( self ) == type( x ): # Check to see if initializing with a reference
            self._x, self._y = x._key, y._key
        else: # It's not reference
            self._x, self._y = x, y
    def __str__( self ):
        try:
            return "{0} = Point( {1}, {2} )".format( self._key, self._x._key, self._y._key )
        except:
            return "{0} = Point( {1}, {2} )".format( self._key, self._x, self._y )


def print_code( cls, indent = 2 ):
    # Print the header
    if indent == 2:
        print( "class Main(metaclass=MBase):" )
    for attr, value in cls.__dict__.items():
        if not attr.startswith( "_" ): # Ignore hidden attributes
            print( " " * indent + str( value ) ) # Use indentation
            if isinstance( value, CSub.__class__ ): # If it's a subclass then process that too
                print_code( value, indent + 2 )

class Main(metaclass=MBase):
    x = Integer( 0 )
    y = Integer( 100 )
    z = Integer( x )
    p1 = Point(x,x)
    p2 = Point(y,y)
    class Sub(CSub, metaclass=MBase):
        p = Point(1,1)
print_code( Main )

このように、オブジェクトxを変更すると、xを参照する他のすべてのオブジェクトも変更されます。さらに、後で使用するためにコードをテキストファイルに簡単に保存できます。

これにはまだ作業が必要ですが、良いスタートです。これが、似たようなものを探している他の人の助けになることを願っています。

于 2013-02-03T08:32:20.403 に答える
0

オブジェクトからそれを保持する変数の名前までさかのぼって作業することはできません。ただし、現在のコンテキスト内のすべての変数を反復処理し、指定されたオブジェクトと等しい値を持つ変数がある場合はどれかを確認する場合を除きます。それは比較的遅く、面倒です。

おそらく、より良い代替手段は(あなたの目的のために機能するかどうかはわかりませんが)、名前自体を操作することです。たとえば、fPrintName(または何でも)渡す代わりに'f'、文字列を渡します。コンストラクターで変数の値にアクセスする必要がある場合はPrintName、現在のスタック フレームの上のスタック フレームにアクセスして、指定された名前の変数を選択できます。次のように、 inspect モジュールを使用してこれを行うことができます。

class PrintName:
    def __init__(self, name):
        # of course you can just print the name
        last_frame = inspect.stack()[1]
        if name in last_frame.f_locals:
            value = last_frame.f_locals[name]
        elif name in last_frame.f_globals:
            value = last_frame.f_globals[name]
        # do stuff with value

言うまでもなく、これは非常にハックであり、通常のプログラムで行うべきことではありません。デバッガーのようなもので使用するためのものです。

于 2013-02-03T00:21:26.890 に答える