误解对象的“引用名”跟对象的“名称属性”(`__name__`)引发的一则错误

误解对象的“引用名”跟对象的“名称属性”(`__name__`)引发的一则错误
class MyMetaclass(type):def __new__(cls,*args,**kwargs):print("MyMetaclass中的new被执行")return super().__new__(cls,*args,**kwargs)def __init__(self,*args,**kwargs):print("MyMetaclass中的init被执行")self.__instance=Nonedef __call__(self,*args,**kwargs):print("MyMetaclass中的call被执行")if self.__instance is None:self.__instance=super().__call__()return self.__instance
#下面是由自定义元类构造出来的普通类,父类是object
a=MyMetaclass("MClass",(object,),dict())
MClass()#报错

MClass()为什么报错?

MClass() 报错的核心原因是:Python 找不到名为 MClass 的引用,因为你创建的类对象并没有绑定到 MClass 这个引用名上。

具体拆解:

  1. 类的创建过程
    当你执行 a = MyMetaclass("MClass", (object,), dict()) 时,确实通过元类 MyMetaclass 创建了一个类对象。

    • 这个类对象的“名称属性”(__name__)是 "MClass"(由第一个参数指定,仅用于标识类的名字)。
    • 但这个类对象被绑定到了 a 这个引用名上(即 a 指向这个类对象)。
  2. 为什么 MClass() 会报错?
    Python 中调用类(如 XXX())时,会去查找名为 XXX 的引用,看它是否指向一个类对象。

    • 你创建的类对象虽然“名称属性”是 "MClass",但并没有任何引用名叫做 MClass(唯一的引用是 a)。
    • 因此,当你写 MClass() 时,Python 会报 NameError: name 'MClass' is not defined——因为找不到名为 MClass 的引用。
  3. 举个生活例子
    假设你买了一辆车,车的出厂名称是“特斯拉”(对应类的 __name__ 属性),但你给它上的车牌是“京A12345”(对应引用名 a)。

    • 如果你站在路边喊“特斯拉,启动!”,车不会理你(因为没有这个“标识”)。
    • 但喊“京A12345,启动!”,车才会响应(因为“京A12345”是绑定到这辆车的标识)。

如何解决?

让引用名与类的“名称属性”一致即可:

# 将类对象绑定到 MClass 这个引用名上
MClass = MyMetaclass("MClass", (object,), dict())
MClass()  # 此时不会报错,因为 MClass 是有效的引用名

总结:

类的“名称属性”(__name__)只是类的一个标识字符串,而引用名是 Python 查找对象的“钥匙”。二者可以不同(如 a 指向名称为 MClass 的类),但只有通过有效的引用名才能调用类。