python 元类
时间: 2021-2-1 , python==3.7
Python中实例对象时由类对象实例化的,而类对象是由元类实例化的。
文章目录
一、 重新认识type
1.1 所有的类对象都是基于type类来创建的
a = 100
type(a)
type(type(a))
type
d = {"test": "cdefg"}
print(type(d))
print(type(type(d)))
<class 'dict'>
<class 'type'>
class Dog(object):
name = "旺财"
d_ = Dog()
print(type(Dog))
<class 'type'>
print(type(d_))
print(type(type(d_)))
<class '__main__.Dog'>
<class 'type'>
可以看到,当使用了多次type函数时, 所有的结果最终都等于 class type.
1.2使用type动态的创建一个类对象
# type 第一个参数字符串,类名Dog, 第二个参数元组,继承object,第三个参数字典,定义类的属性、方法
D = type("Dog", (object,), {"name": "旺财", "say": lambda self: print("旺!旺!")})
dog = D()
print(dog.name)
dog.say()
旺财
旺!旺!
type(dog)
__main__.Dog
在这里可以看到,type可以创建一个类对象, 也就是说type是一个元类
二、 元类
type是一个元类,默认元类都是使用type, 除非指定 metaclass
2.1 自定义一个原类
# 重写new方法, new方法是用来实例化一个类对象的
class FishType(type):
def __new__(mcs, name, bases, attrs):
if not (attrs.get("eat") and attrs.get("swim")):
# 规定Fish必须拥有 eat 与 swim, 否则抛出异常
raise Exception("鱼必必须拥有eat与swim两个方法")
# 调用父类即,type的 __new__ 创建一个类对象
return super().__new__(mcs, name, bases, attrs)
def __setattr__(cls, name, value):
raise Exception("不允许修改类属性")
# class Fish(object, metaclass=FishType):
# pass
# 直接class定义Fish抛出异常
class Fish(object, metaclass=FishType):
name = "fish"
def eat():
print("eating")
def swim():
print("swimming")
f = Fish()
f.swim
print(f)
print(type(f))
print(type(type(f)))
print(type(type(type(f))))
<__main__.Fish object at 0x0000018D55FB1288>
<class '__main__.Fish'>
<class '__main__.FishType'>
<class 'type'>
try:
print("原来的name: ", Fish.name)
# 试图修改类对象的属性
Fish.name = "咸鱼"
print(Fish.name)
except Exception as e:
print(e)
原来的name: fish
不允许修改类属性
2.2 class 魔法属性
# __class__ 等于type的值
fish = Fish()
print(fish.__class__)
print(fish.__class__.__class__)
print(fish.__class__.__class__.__class__)
print(fish.__class__ is type(fish))
<class '__main__.Fish'>
<class '__main__.FishType'>
<class 'type'>
True
a = 100
print(a.__class__)
d = {}
print(d.__class__)
print(a.__class__ is type(a))
print(d.__class__ is type(d))
<class 'int'>
<class 'dict'>
True
True
三、总结
- 元类用于创造类对象。
- type是默认的元类, type可以用于动态创建一个类对象。
- 自定义元类,继承type,重写 new 方法。 用途: 实现对类对象一些属性的限制,或者修改、规范类的定义, 比如类对象属性必须全部大写、禁止修改类对象值、必须拥有某些属性等等。