Dynamic class field creation before metaclass machinery
I'm trying to get rid of exec
in a code similar to this:
class A(object):
for field in ['one', 'two', 'three']:
exec '%s = "%s value"' % (field, field)
...so that:
>>> A.one
'one value'
>>> A.two
'two value'
>>> A.three
'three value'
EDIT: and also the requirement mentioned in the subject is met i.e. A.one
is 'one value'
, before A
is instantiated (not to be mistaken for A()
instantiated).
Is 开发者_运维百科there a way?
>>> values = 'one', 'two', 'three'
>>> A = type('A', (object,), {i: i + ' value' for i in values})
>>> A.one
'one value'
>>> A.three
'three value'
Use the setattr
function.
class A(object):
pass
for field in ['one', 'two', 'three']:
setattr(A, field, field + ' value')
I'd just inherit from the metaclass and do it there
class MyMetaClass(MetaClass):
def __new__(meta, classname, baseclasses, classdict):
fields = classdict['__myfields__']
for field in fields:
classdict[field] = field + ' value'
del classDict['__myfields__']
MetaClass.__new__(meta, classname, baseclasses, classdict)
Then you can just do:
class A(object):
__metaclass__ = MyMetaClass
__myfields__ = ['one', 'two', 'three']
You say you want to generate something dynamically that the metaclass can process. There's a very simple way to achieve that without resorting to hackery like exec
. All you have to do is think of this in a different way: modify the metaclass so that the names are generated there.
class AutoFieldMeta(type):
def __new__(mcs, name, bases, d):
for field in d.get('AUTOFIELDS', ()):
d[field] = field + ' value'
return type.__new__(mcs, name, bases, d)
class A(object, metaclass=AutoFieldMeta):
AUTOFIELDS = ('one', 'two', 'three')
>>> A.one
'one value'
>>>
and if you don't want to modify the existing metaclass you can subclass it.
This works too and I think it's a happy end...
class A(object):
for a in ['one', 'two', 'three']:
locals().update({a: a + ' value'})
And for anyone searching for assignment expression in Python, this is in the same mood as aaronasterling answer :):
http://code.activestate.com/recipes/202234-assignment-in-expression/
Let me preface this by saying that this is incredibly hackish but eliminates the exec. We just stick the attributes on the current stack frame as the code in the class statement is being executed. It is only guaranteed to work on CPython and there are warnings against doing it in the manual. I would highly recommend that you go with duncans metaclass solution.
import sys
class A(object):
for field in ['one', 'two', 'three']:
sys._getframe().f_locals[field] = field + ' value'
精彩评论