Frage

I'm writing a python (3.2+) plugin library and I want to create a function which will create some variables automatically handled from config files.

The use case is as follows (class variable):

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

(instance variable):

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

the option draft code is as follows:

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. Is it possible to somehow get reference to the class in which this function was used (in example to class X)?

War es hilfreich?

Lösung

You cannot get a reference to the class, because the class has yet to be created. Your parent frame points a temporary function, whose locals() when it completes will be used as the class body.

As such, all you need to do is add your variables to the parent frame locals, and these will be added to the class when class construction is finished.

Short demo:

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

Andere Tipps

It seems to me that a metaclass would be suitable here:

python2.x syntax

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 syntax

It seems that python3 uses a metaclass keyword in the class definition:

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

Or, more along the lines of what you have in your question:

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) )
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top