Using the __call__ method of a metaclass instead of __new__?

前端 未结 5 1344
情歌与酒
情歌与酒 2020-11-30 21:40

When discussing metaclasses, the docs state:

You can of course also override other class methods (or add new methods); for example defining a custom

5条回答
  •  情书的邮戳
    2020-11-30 22:29

    I thought a fleshed out Python 3 version of pyroscope's answer might be handy for someone to copy, paste and hack about with (probably me, when I find myself back at this page looking it up again in 6 months). It is taken from this article:

    class Meta(type):
    
         @classmethod
         def __prepare__(mcs, name, bases, **kwargs):
             print('  Meta.__prepare__(mcs=%s, name=%r, bases=%s, **%s)' % (
                 mcs, name, bases, kwargs
             ))
             return {}
    
         def __new__(mcs, name, bases, attrs, **kwargs):
             print('  Meta.__new__(mcs=%s, name=%r, bases=%s, attrs=[%s], **%s)' % (
                 mcs, name, bases, ', '.join(attrs), kwargs
             ))
             return super().__new__(mcs, name, bases, attrs)
    
         def __init__(cls, name, bases, attrs, **kwargs):
             print('  Meta.__init__(cls=%s, name=%r, bases=%s, attrs=[%s], **%s)' % (
                 cls, name, bases, ', '.join(attrs), kwargs
             ))
             super().__init__(name, bases, attrs)
    
         def __call__(cls, *args, **kwargs):
             print('  Meta.__call__(cls=%s, args=%s, kwargs=%s)' % (
                 cls, args, kwargs
             ))
             return super().__call__(*args, **kwargs)
    
    print('** Meta class declared')
    
    class Class(metaclass=Meta, extra=1):
    
         def __new__(cls, myarg):
             print('  Class.__new__(cls=%s, myarg=%s)' % (
                 cls, myarg
             ))
             return super().__new__(cls)
    
         def __init__(self, myarg):
             print('  Class.__init__(self=%s, myarg=%s)' % (
                 self, myarg
             ))
             self.myarg = myarg
             super().__init__()
    
         def __str__(self):
             return "" % (
                 getattr(self, 'myarg', 'MISSING'),
             )
    
    print('** Class declared')
    
    Class(1)
    print('** Class instantiated')
    

    Outputs:

    ** Meta class declared
      Meta.__prepare__(mcs=, name='Class', bases=(), **{'extra': 1})
      Meta.__new__(mcs=, name='Class', bases=(), attrs=[__module__, __qualname__, __new__, __init__, __str__, __classcell__], **{'extra': 1})
      Meta.__init__(cls=, name='Class', bases=(), attrs=[__module__, __qualname__, __new__, __init__, __str__, __classcell__], **{'extra': 1})
    ** Class declared
      Meta.__call__(cls=, args=(1,), kwargs={})
      Class.__new__(cls=, myarg=1)
      Class.__init__(self=, myarg=1)
    ** Class instantiated
    

    Another great resource highlighted by the same article is David Beazley's PyCon 2013 Python 3 Metaprogramming tutorial.

提交回复
热议问题