QQ登录

只需一步,快速开始

开启左侧

Python学习第七十四天—类和对象23-元类的应用

[复制链接]
15271953841 发表于 2024-4-20 06:49:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 15271953841 于 2024-4-20 06:52 编辑

元类的应用

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
一、对类动手动脚,给所有的类添加一个作者的属性
class MetaC(type):                 (创建一个元类,继承自type)
    def __new__(mcls,name,bases,attrs): (类完成定义的时候,它会执行元类的__new__方法)
        attrs["author"] = "FishC"        (类的属性里添加一对键值对)
        return type.__new__(mcls,name,bases,attrs)

class C(metaclass=MetaC):
    pass

class D(metaclass=MetaC):
    pass

c = C()
d = D()
c.author
'FishC'
d.author
'FishC'
元类,两种方法都可以实现添盐加醋,因为__new__和__init__都是在类完成定义的时候被调用的。
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()
c.author
'FishC'
d.author
'FishC'
二、对类名的定义规范做限制,比如:让类名支持大写字母开头,小写报错
class MetaC(type):
    def __init__(cls,name,bases,attrs):
        if not name.istitle():
            raise TypeError("类名必须是大写字母开头~")
        type.__init__(cls,name,bases,attrs)

        
class mycls(metaclass=MetaC):
    pass

Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    class mycls(metaclass=MetaC):
  File "<pyshell#28>", line 4, in __init__
    raise TypeError("类名必须是大写字母开头~")
TypeError: 类名必须是大写字母开头~

class Mycls(metaclass=MetaC):
    pass

三、修改对象的属性值,比如:把对象的所有字符串属性值全部变成大写
class MetaC(type):
    def __call__(cls,*args,**kwargs):   (__call__影响类实例化的过程,对类的属性,把它在实例化过程的传入的属性值变成大写,而不是改这个类属性,改的是属性值)
        new_args = [each.upper() for each in args if isinstance(each,str)]    (参考第19课时最后的列表高阶表达式,其中的isinstance()函数参考第53课时)
        return type.__call__(cls,*new_args,**kwargs)

   
class C(metaclass=MetaC):
    def __init__(self,name):
        self.name = name

        
c =C("FishC")
c.name
'FISHC'
四、限制类实例化时的传参方式,比如:要求类在实例化对象时传入的参数只能够通过关键字参数传参,如果传入的位置参数,那么报错
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

        
c = C("FishC")
Traceback (most recent call last):
  File "<pyshell#56>", line 1, in <module>
    c = C("FishC")
  File "<pyshell#51>", line 4, in __call__
    raise TypeError("仅支持关键字参数")
TypeError: 仅支持关键字参数

c = C(name="FishC")
c.name
'FishC'
五、禁止一个类被实例化
class NoInstances(type):
    def __call__(cls,*args,**kwargs):
        raise TypeError("该类不允许直接实例化对象!")

   
class C(metaclass=NoInstances):
    pass

c = C()
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    c = C()
  File "<pyshell#3>", line 3, in __call__
    raise TypeError("该类不允许直接实例化对象!")
TypeError: 该类不允许直接实例化对象!

class C(metaclass= NoInstances):
    @staticmethod
    def static_ok():
        print("静态方法直接访问是允许的~")

        
C.static_ok()
静态方法直接访问是允许的~
c = C()
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    c = C()
  File "<pyshell#3>", line 3, in __call__
    raise TypeError("该类不允许直接实例化对象!")
TypeError: 该类不允许直接实例化对象!

class C(metaclass=NoInstances):
    @classmethod
    def class_ok(cls):
        print("类方法直接访问是允许的~")

        
class C(metaclass=NoInstances):
    @classmethod
    def class_ok(cls):                   (类方法要传入一个类)
        print("类方法直接访问是允许的~")

        
C.class_ok()
类方法直接访问是允许的~
六、只允许实例化一个对象,就是说,我们让这个类把它给多个实例,但其实它背后那个对象都是同一个,“计划生育”
class SimpleInstance(type):
    def __init__(cls,*args,**kwargs):
        cls.__instance = None         (两个__表示私有变量,参考第58课时)
        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=SimpleInstance):
    pass

c1 = C()
c2 = C()
c1 is c2
True
dir(C)
['_SimpleInstance__instance', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
客服热线
400-1234-888 周一至周日:09:00 - 21:00
公司地址:襄阳市樊城区长虹路现代城5号楼188

创客帮MAKER.BAND青少年创客创意社区是一个融教育、科技、体育资讯为一体的综合服务平台,专注于教育创新、专注于科技体育、专注于教育资讯。

Powered by Discuz! X3.4 © 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表