1. 基本类
在Python中,类只是创建对象的模板。
class Animal:
def speak(self):
return "some sound"
a = Animal()
print(a.speak()) # "some sound"
2.继承(重用/扩展类)
继承意味着一个类重用或扩展另一个类。
class Dog(Animal): # Dog继承自Animal
def speak(self):
return "woof!"
Dog从Animal那里获取所有内容。
如果你不重写,它就会使用父类的方法。
如果你重写(def speak),则使用你的新版本。
d = Dog()
print(d.speak()) # "woof!"
🔹 多重继承
Python 允许一个类从多个类继承。
class Walker:
def move(self):
return "walking"
class Swimmer:
def move(self):
return "swimming"
class Duck(Walker, Swimmer):
pass
那么,Duck 使用哪个 move() 方法呢?
Python 使用方法解析顺序(MRO)来解决这个问题 → 一种确定性的查找顺序。
duck = Duck()
print(duck.move())
# "walking",因为 Walker 被列在前面
print(Duck.__mro__)
# (<class '__main__.Duck'>, <class '__main__.Walker'>, <class '__main__.Swimmer'>, <class 'object'>)
3. 构造函数 (__init__)
当你执行 `obj = ClassName(…)` 时,Python 会调用该类的 `__init__` 方法。
父类的构造函数可以通过 `super()` 调用。
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 调用父类的 __init__
self.breed = breed
d = Dog("Rex", "Labrador")
print(d.name, d.breed) # Rex Labrador
4. 元类(类的类)
现在进入棘手的部分:
在 Python 中,一切都是对象,甚至类本身。
如果对象是由类创建的……那么类又是由什么创建的呢?
→ 答案是:元类。
默认情况下,Python 使用 `type` 作为元类。
# "Animal" 本身是由 "type" 创建的对象
print(type(Animal)) # <class 'type'>
所以:
普通对象是类的实例。
类是元类的实例(通常是 `type`)。
🔹 自定义元类
您可以定义自己的 metaclass 来控制类的构建方式。
class Meta(type): # 继承自 'type'
def __new__(cls, name, bases, dct):
print(f"创建类 {name}")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta):
pass
输出:
创建类 MyClass
在这里,Meta.__new__ 在类定义时运行,而不是在实例化时运行。Metaclass 就像是类的蓝图。
5. 何时使用继承与 Metaclass
继承 = 在对象之间组织和重用代码。
Metaclass = 控制或修改类本身的行为(罕见,进阶用例)。
示例 metaclass 使用:
强制编码标准(例如,所有方法必须为小写)。
自动注册类到插件系统中。
自动向类添加方法/属性。
6. 总结
继承:
在类之间重用代码。
支持多个父类。
遵循 MRO 进行查找。
构造函数(__init__):
定义类实例接受的参数。
super() 允许链式调用父类构造函数。
Metaclass:
类是对象,由 metaclass 创建(默认是 type)。
自定义 metaclass 允许您拦截或修改类的创建。
功能强大,但应用场景较窄 — 通常在构建框架/库时才需要。
对于 super() 和 metaclass 的使用我不是很确定,所以我继续研究:
1. type 作为“类的元类” 在 Python 中: 通常,当你调用一个类,比如 Dog(“Rex”),发生的事情并不是简单的函数调用。 在内部,Python 做了如下操作: obj = Dog.__call__(*args, **kwargs) 但 Dog.__call__ 来自它的元类(默认是 type)。 所以整个流程是:
Dog(...)
→ Dog.__class__ 是 type
→ type.__call__(Dog, *args, **kwargs)
→ Dog.__new__(Dog, *args, **kwargs) # 分配内存
→ Dog.__init__(self, *args, **kwargs) # 初始化字段
→ 返回实例
2. 那么 super() 实际上做了什么?
super() 并不意味着“父类”。它的意思是:
“在我的当前类之后,去 MRO 中的下一个类。”
示例:
class A:
def greet(self):
print("A")
class B(A):
def greet(self):
print("B")
super().greet()
class C(A):
def greet(self):
print("C")
super().greet()
class D(B, C):
def greet(self):
print("D")
super().greet()
MRO:
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
执行:
D().greet()
# D
# B
# C
# A
注意,super() 遵循了 MRO,而不仅仅是“父类”。
3. 元类的实际应用
如果你给一个类指定 metaclass=Meta,那么类对象本身的创建就会被拦截。
class Meta(type):
def __call__(cls, *args, **kwargs):
print(f"正在创建 {cls.__name__} 的实例")
return super().__call__(*args, **kwargs)
class MyClass(metaclass=Meta):
def __init__(self, x):
self.x = x
现在:
obj = MyClass(42)
执行顺序:
Meta.__call__(MyClass, 42) 被调用
内部,super().__call__ 委托给 type.__call__
然后调用 MyClass.__new__
接着调用 MyClass.__init__
4. 为什么看起来“硬编码”
是的——你必须声明 metaclass=Meta,因为只有一个元类控制类的创建。
但请注意:
class Foo: pass → 自动使用 type。
class Foo(metaclass=Meta): pass → 使用你的 Meta。
由于元类本身是 type 的子类,你可以扩展 type.__call__、type.__new__ 等的逻辑。
5. 类比
可以将其视为一个工厂系统:
对象 = 产品(你实际使用的实例)。
类 = 工厂(产品的蓝图)。
元类 = 工厂设计师(工厂的蓝图)。
当你执行以下代码时:
p = Product()
这就像是:
调用工厂设计者(元类)来创建一个工厂(类)→ 这在定义时只发生一次。
调用工厂(类)来生成一个产品(对象)→ 每次实例化时都会发生。
我希望你也学到了些什么。
- 使用 Class.mro 来遍历继承关系。
- 如果在本地未解决,则解析导入以解决基类。
- 一旦你有了类定义,检查 init / new 的签名 → 收集它们的参数要求。
- 检测 metaclass= 作为类型类检测的“入口点”,并且只能有一个声明。