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代码以供以后使用(有点像原始脚本语言,可以在使用时评估的程序中进行更改)

例如:

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

打印 p 导致 (0,0),然后对 x 和 y 执行某些操作导致

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

打印 p 变为 (124,-32)。

最简单的方法是使用

p = ( 'x', 'y' )

但是在这种情况下,我们怎么知道'x'是变量的名称而不是字符串'x'

我已经尝试为此目的编写一种简单的脚本语言,但工作量很大,如果上述方法可行,那么整个 python 语言都可以在脚本中使用。

我正在尝试为我的问题找到一个简单灵活的解决方案。

提前感谢您的帮助。

4

2 回答 2

1

我设法使用__ prepare __在 Python 3.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可以访问当前堆栈帧上方的堆栈帧并选择具有给定名称的变量。您可以使用检查模块来执行此操作,如下所示:

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 回答