第080讲:类和对象(XXIII)
0. 本节视频https://www.bilibili.com/video/BV1c4411e77t?p=81
1. 温馨提示
如果在学习本节课的过程中遇到问题,可以在这个帖子下方提问哦~
元类的应用
# 一、给所有的类添加一个属性:
class MetaC(type):
def __new__(mcls, name, bases, attrs):
attrs['author'] = 'fishc'
return type.__new__(mcls, name, bases, attrs)
class C(metaclass=MetaC):
pass
class D(metaclass=MetaC):
pass
c = C()
d = D()
print(c.author, d.author)# fishc fishc
class MetaC(type):
def __init__(cls, name, bases, attrs):
cls.author = 'fishc'
return type.__init__(cls, name, bases, attrs)
class C(metaclass=MetaC):
pass
class D(metaclass=MetaC):
pass
c = C()
d = D()
print(c.author, d.author)# fishc fishc
# 二、对类名的定义规范做限制
class MetaC(type):
def __init__(cls, name, bases, attrs):
if not name.istitle():
raise TypeError('类名必须为大写字母开头!')
type.__init__(cls, name, bases, attrs)
try:
class mycls(metaclass=MetaC):
pass
except TypeError as e:
print(e)# 类名必须为大写字母开头!
# 三、修改对象的属性值 -> 如:把对象的所有字符串属性值都变成大写
class MetaC(type):
def __call__(cls, *args, **kwargs):
new_args =
return type.__call__(cls, *new_args, **kwargs)
class C(metaclass=MetaC):
def __init__(self, name):
self.name = name
c = C('FishC')
print(c.name)# FISHC
# 当然如果传入的不是str就不显示
class C(metaclass=MetaC):
def __init__(self, *names):
self.names = names
c = C('FishC', 'Python', 1223)
print(c.names)# ('FISHC', 'PYTHON')
# 四、限制类实例化时的传参方式 -> 如:要求类在实例化对象时只能关键字参数传参
class MetaC(type):
def __call__(cls, *args, **kwargs):
if args:
raise TypeError('仅支持关键字参数~')
return type.__call__(cls, *args, **kwargs)
class C(metaclass=MetaC):
def __init__(self, name):
self.name = name
try:
c = C('fishc')
except TypeError as e:
print(e)# 仅支持关键字参数~
c = C(name='fishc')
print(c.name)# fishc
# 五、禁止一个类被实例化
class NoInstances(type):
def __call__(self, *args, **kwargs):
raise TypeError('该类禁止实例化!')
class C(metaclass=NoInstances):
pass
try:
c = C()
except TypeError as e:
print(e)# 该类禁止实例化!
# 禁止实例化对象也可以使用静态方法和类方法
class C(metaclass=NoInstances):
@staticmethod
def static_ok():
print('静态方法允许使用~')
@classmethod
def class_ok(cls):
print('类方法也允许使用~')
C.static_ok()# 静态方法允许使用~
C.class_ok()# 类方法也允许使用~
# 六、只允许实例化一个对象
class OnlyInstance(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
type.__init__(cls, *args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = type.__call__(cls, *args, **kwargs)
return cls.__instance
else:
return cls.__instance
class C(metaclass=OnlyInstance):
pass
c1 = C()
c2 = C()
print(c1 is c2)# True
# c1和c2为同一个对象
print(dir(C))
# ['_OnlyInstance__instance', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
# 对象被保存在类里边的_OnlyInstance__instance这个属性中
经历了这么久煎熬最简单的一集
元类metaclass 说白了就是类的模板,可以根据模板批量化生成类。
讲的元类应用包括:给类设置统一的属性、给类的命名做规范(类名统一首字母大写)、修改对象的属性值(类实例化的对象的所有属性名全大写)、限制类实例化的传递参数方式(只接受位置参数或关键字参数)、禁止一个类被实例化、只允许每个类被实例化一次。
最后一个代码如下:
class MetaC(type):
def __init__(cls,name,bases,attrs):
cls.flag = 0
return type.__init__(cls,name,bases,attrs)
def __call__(cls,*args,**kwargs):
if cls.flag:
raise TypeError('不允许实例化第二个对象')
cls.flag = 1
return type.__call__(cls,*args,**kwargs)
class C(metaclass=MetaC):
pass
class D(metaclass=MetaC):
pass
页:
[1]