从Python中的函数获取类引用

时间:2013-01-04 16:12:04

标签: python introspection inspect

我正在编写一个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)

第一种情况我有问题,当选项被声明为类变量时。是否有可能以某种方式引用使用此函数的类(例如在类X中)?

2 个答案:

答案 0 :(得分: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'

答案 1 :(得分: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语法

似乎python3在类定义中使用metaclass关键字:

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