4

我正在编写一个 python (3.2+) 插件库,我想创建一个函数,该函数将创建一些从配置文件自动处理的变量。

用例如下(类变量):

class X:
    option(y=0)
    def __init__(self):
        pass

(实例变量):

class Y:
    def __init__(self):
        option(y=0)

期权草案代码如下:

def option(**kwargs):
    frame   = inspect.stack()[1][0]
    locals_ = frame.f_locals
    if locals_ == frame.f_globals:
        raise SyntaxError('option() can only be used in a class definition')

    if '__module__' in locals_:
        # TODO

    else:
        for name, value in kwargs.items():
            if not name in locals_["self"].__class__.__dict__:
                setattr(locals_["self"].__class__, name, VirtualOption('_'+name, static=False))
            setattr(locals_["self"], '_'+name,value)

I have problem the first case, when option is declared as class variable. 是否有可能以某种方式获得对使用此函数的类的引用(例如对类 X)?

4

2 回答 2

2

您无法获得对该类的引用,因为尚未创建该类。您的父框架指向一个临时函数,该函数locals()完成后将用作类主体。

因此,您需要做的就是将您的变量添加到父框架局部变量,这些将在类构建完成时添加到类中。

简短演示:

>>> def foo():
...     import sys
...     flocals = sys._getframe(1).f_locals
...     flocals['ham'] = 'eggs'
... 
>>> class Bar:
...     foo()
... 
>>> dir(Bar)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__locals__', '__lt__', '__module__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'ham']
>>> Bar.ham
'eggs'
于 2013-01-04T16:36:38.077 回答
0

在我看来,元类在这里很合适:

python2.x 语法

def class_maker(name,bases,dict_):
    dict_['y']=0
    return type(name,bases,dict_)

class X(object):
    __metaclass__ = class_maker
    def __init__(self):
        pass

print X.y
foo = X()
print foo.y

python3.x 语法

似乎python3metaclass在类定义中使用了一个关键字:

def class_maker(name,bases,dict_):
    dict_['y']=0
    return type(name,bases,dict_)

class X(metaclass=class_maker):
    def __init__(self):
        pass

print( X.y )
foo = X()
print( foo.y )
print( type(foo) )

或者,更符合您的问题:

def class_maker(name,bases,dict_,**kwargs):
    dict_.update(kwargs)
    return type(name,bases,dict_)

class X(metaclass=lambda *args: class_maker(*args,y=0)):
    def __init__(self):
        pass

print( X.y )
foo = X()
print( foo.y )
print( type(foo) )
于 2013-01-04T16:21:30.590 回答