如何使用Python的__metaclass__?

时间:2014-07-27 12:55:26

标签: python class metaprogramming

Here in this IPython Notebook我找到了关于生成器和函数式编程的演示文稿。我偶然发现__metaclass__

  1. 为什么Real的{​​{1}}和float参数?现在通常有Accounting,但是需要在其中写basesReal吗?

  2. float做了什么?我无法在通常的特殊方法列表中找到它。

  3. 作者是否通过使用这两个for循环来使用其他类中的方法来丰富他的__abstractmethods__类?

  4. 为什么Accounting不会导致无限循环?与第二个版本相比,这里会发生什么?

  5. 首先,这是与我的问题相关的摘录:

    Accounting(getattr(float,meth)(*args, **kwargs))

    这是整个代码:

    class Accounting(Real, float):
        def __metaclass__(name, bases, body):
            for method in Real.__abstractmethods__:
                if method not in body:
                    body[method] = (lambda meth: lambda *args, **kwargs: Accounting(getattr(float,meth)(*args, **kwargs)))(method)
            for method in ('__ne__','__nonzero__',):
                if method not in body:
                    body[method] = (lambda meth: lambda *args, **kwargs: getattr(float,meth)(*args, **kwargs))(method)
            return Real.__metaclass__(name, bases, body)
        __new__ = float.__new__
    

    然后在这里使用代码:

    from numbers import Real
    class Accounting(Real, float):
        def __metaclass__(name, bases, body):
            for method in Real.__abstractmethods__:
                if method not in body:
                    body[method] = (lambda meth: lambda *args, **kwargs: Accounting(getattr(float,meth)(*args, **kwargs)))(method)
            for method in ('__ne__','__nonzero__',):
                if method not in body:
                    body[method] = (lambda meth: lambda *args, **kwargs: getattr(float,meth)(*args, **kwargs))(method)
            return Real.__metaclass__(name, bases, body)
        __new__ = float.__new__
        def __format__(self, fmt):        
            return { 1: ' %s'%float.__format__(self, fmt),
                     0: ' %s'%float.__format__(self, fmt).replace('0', '-'),
                    -1: '(%s)'%float.__format__(self, fmt) }[cmp(self,0)]
    

    输出:

    template = '{region:<{align}}   {profit:>14,.0f}'.format
    def output(markets, write=print, template=template):
        align = max(map(len,markets))
        for region, profit in markets.items():
            line = template(region=region, profit=profit, align=align)
            write(line)
    
    output({region:Accounting(profit) for region, profit in markets.items()})
    

1 个答案:

答案 0 :(得分:0)

答案的一部分:

for method in Real.__abstractmethods__:
           if method not in body:
               body[method] = (lambda meth: lambda *args, **kwargs: Accounting(getattr(float,meth)(*args, **kwargs)))(method)

numbers.Real是一个抽象类(即你不能证实它的一个实例,但是你可以将它用作子类.Real类有一个名为__abstractmethods__的特殊冻结集,它似乎列出了Real类期望定义的所有方法。:

在交互式解释器中:

from numbers import Real
Real.__abstractmethods__
frozenset(['__rtruediv__', '__radd__', '__truediv__', '__pow__', '__add__', '__rdiv__', '__rmul__', '__rmod__', '__eq__', '__lt__', '__float__', '__rpow__', '__mod__', '__trunc__', '__abs__', '__pos__', '__div__', '__le__', '__rfloordiv__', '__neg__', '__floordiv__', '__mul__'])

因此,这个循环确保了body(实际上是由元类创建的类)对这些方法中的每一个都有一个具体的定义。

我承认我不会完全理解嵌套的lambda定义。