关于 Python3 元类的一些问题

Posted

技术标签:

【中文标题】关于 Python3 元类的一些问题【英文标题】:Some questions about Python3 metaclass 【发布时间】:2017-05-16 13:35:20 【问题描述】:
class UpperAttrMetaclass(type):

    var = "test"

    def __new__(upperattr_metaclass, future_class_name,
                future_class_parents, future_class_attr):
        print("hello world")
        uppercase_attr = 
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # reuse the type.__new__ method
        # this is basic OOP, nothing magic in there
        return type.__new__(upperattr_metaclass, future_class_name,
                            future_class_parents, uppercase_attr)


class Hello(object):

    __metaclass__ = UpperAttrMetaclass

    bar = "test"

obj = Hello()
print(obj.BAR)  # obj has no attribute named BAR

回溯(最近一次通话最后一次): 文件“E:\python\test.py”,第 32 行,在 打印(obj.BAR) AttributeError: 'Hello' 对象没有属性 'BAR'

为什么元类 UpperAttrMetaclass 不起作用?

【问题讨论】:

Python3 Singleton metaclass method not working的可能重复 为什么这个问题被否决了?它确实有一个完美的代码示例和一个精心设计的问题(如果取决于问题标题)。 【参考方案1】:

在 Python3 中,指定元类的方式与 Python2 发生了不兼容的变化。

从 Python 3.0 开始,指定元类的方法是使用元类名称,就好像它是 class 语句本身的命名参数一样。

因此,在上面的示例中,您应该将 Hello 类声明为:

class Hello(metaclass=UpperAttrMetaclass):
    bar = "test"

查看文档:https://docs.python.org/3.0/whatsnew/3.0.html#changed-syntax

除此之外,正如您所指出的,将 __metaclass__ 属性放在 ac alss 正文中并不是一个错误,但它什么都不做,而是用该名称声明一个属性。

在发布了几个 Python3.x 版本之后,这是唯一与 Python 2 不兼容且无法直接解决的语法更改,因此代码既是 Python 2.x 又是 Python 3 .x 同时兼容。

如果您需要在 Python 2 和 Python 3 上运行相同的代码库,则名为 six 的包会调用 with_metaclass,它使用与两个版本兼容的语法构建动态类库。 (https://pythonhosted.org/six/#syntax-compatibility)

【讨论】:

以上是关于关于 Python3 元类的一些问题的主要内容,如果未能解决你的问题,请参考以下文章

——友元函数 | 友元类 | 内部类 | 匿名对象 | 关于拷贝对象时一些编译器优化

单例类和元类

python3元类的调用顺序

深入理解Python中的元类---metaclass

Ruby 元类混淆

使用元类实现工厂设计模式