Reputation: 11803
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)?
Upvotes: 4
Views: 8986
Reputation: 309891
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) )
Upvotes: 0
Reputation: 1121584
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'
Upvotes: 2