开发者

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜