21.面向对象【五】

【一】内置方法补充

1)__call__

# __call__:当类()或对象()调用时触发
class Eg:
    def __init__(self):
        print('执行__init__')
    def __call__(self, *args, **kwargs):
        print('执行__call__')
obj = Eg()  # 执行__init__
obj()  # 执行__call__ 
# 校验当前对象是否可被调用
# 类本身是可以被任意调用的
print(callable(Eg))  # True
# 对象本身是不具备直接被调用的功能的,想让对象也能被调用就必须重写 __call__
print(callable(obj))  # True

2)isinstance(obj,cls)

  • 判断当前对象是否是某一个类的类型
class Animal:
    ...
class Dog:
    ...
animal = Animal()
dog = Dog()
# 判断当前对象是否是指定类型的对象
res_animal = isinstance(dog, Animal)
print(res_animal)  # False
res_dog = isinstance(dog, Dog)
print(res_dog)  # True

3)issubclass(sub,super)

  • 校验一个类是否是属于另一个类的子类
class Animal:
    ...
class Dog(Animal):
    ...
class Cat:
    ...
print(issubclass(Dog, Animal))  # True
print(issubclass(Cat, Animal))  # False

【二】元类

1)概念

  • 元类是所有类的基础,包括object
  • 八大基本数据类型、类实例化得到的对象、类本身均是一种对象
  • 类就是type,即元类

2)元类的创建方法

1.直接用关键字创建

class 类名(继承的父类):
	类体代码
class Student:
    def __init__(self, name):
        self.name = name
print(type(Student))
# <class 'type'>
print(Student.__dict__)
# {'__module__': '__main__', '__init__': <function Student.__init__ at 0x000002A1E21C4400>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

2.通过type创建

类名 = type('类名',(父类1,父类2),名称空间字典)
Student = type('Student', (object,), {'name': 'diva'})
print(Student)
# <class '__main__.Student'>
print(type(Student))
# <class 'type'>
print(Student.__dict__)
# {'name': 'diva', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

3)元类使用

1.优势

  • 元类可以控制类的创建,即我们可以高度定制类的具体行为

2.元类的基本使用

# 创建元类
class MyType(type):
    def __init__(cls, class_name, class_bases, class_name_space):
        # cls 是当前类的本身
        print(f'cls:{cls}')
        # cls:<class '__main__.MyClass'>
        
        # class_name 当前类的类名
        print(f'class_name:{class_name}')
        # class_name:MyClass
        
        # class_bases 当前类的父类
        print(f'class_bases:{class_bases}')
        # class_bases:()
        
        # class_name_space 当前类的名称空间
        print(f'class_name_space:{class_name_space}')  
        # class_name_space:{'__module__': '__main__', '__qualname__': 'MyClass'}
        
        super().__init__(class_name, class_bases, class_name_space)
# 创建一个继承元类的类
# metaclass 指定元类
class MyClass(metaclass=MyType):
    ...

4)元类进阶使用(控制类名首字母大写)

# 控制当前类名必须首字母大写!首字母不大写就报错!
# 【1】创建元类
class MyType(type):
    def __init__(cls, class_name, class_bases, class_name_space):
        super().__init__(class_name, class_bases, class_name_space)
        # istitle : 首字母必须大写其他必须全小写
        if not class_name.istitle():
            raise TypeError(f'{class_name}首字母必须大写!')
# 【2】创建一个继承元类的类
class Eg(metaclass=MyType):
    ...
# 不报错
class eg(metaclass=MyType):
    ...
# 报错

5)元类__call__补充

class MyType(type):
    def __init__(cls, class_name, class_bases, class_name_space):
        print('MyType的__init__')
        super().__init__(class_name, class_bases, class_name_space)
    def __call__(self, *args, **kwargs):
        print('MyType的__call__')
        obj = super().__call__(*args, **kwargs)
        print('***')
        return obj
class Student(metaclass=MyType):
    def __init__(self, name):
        print('MyClass的__init__')
        self.name = name
    def __call__(self, *args, **kwargs):
        print('MyClass的__call__')

# MyType的__init__
st1 = Student('diva')
# MyType的__call__
# MyClass的__init__
# ***
print(st1())
# MyClass的__call__
# None
print(st1.name)
# diva
  • 高度定制 类的产生过程
    • 编写元类里面的__init__
  • 高度定制 对象的产生过程
    • 编写元类里面的__call__

【三】元类结合__new__

__new__ : 产生空对象(类),用来生成骨架
__init__ : 实例化对象(类),骨架添加血和肉

1)类中的__new__

class MyClass(object):
    def __init__(self, name, age):
        print(f"给当前 MyClass 类的对象初始化属性的时候会触发 __init__")
        self.name = name
        self.age = age
    def __call__(self, *args, **kwargs):
        print(f"当前 MyClass 类的对象被调用的时候会触发 __call__")
        return f'当前 MyClass 类 的 __call__ 的返回值 :>>>> {self.name}'
    # 【三】花骨架 有了骨架才能上色
    def __new__(cls, *args, **kwargs):
        print(f"给当前 MyClass 类的对象创建骨架的时候会触发 __new__")
        # 【1】当前类本身
        print(f" MyClass 类 的 __call__ 的 cls :>>>> {cls}")
        # MyClass 类 的 __call__ 的 cls :>>>> <class '__main__.MyClass'>
        # 【2】当前类初始化传的位置参数
        print(f" MyClass 类 的 __call__ 的 args :>>>> {args}")
        # MyClass 类 的 __call__ 的 args :>>>> ('dream',)
        # 【3】当前类初始化传的关键字参数
        print(f" MyClass 类 的 __call__ 的 kwargs :>>>> {kwargs}")
        # MyClass 类 的 __call__ 的 kwargs :>>>> {'age': 18}
        # 【四】调用父类 的 object 的 __new__ 帮我搭建好骨架
        obj = object.__new__(cls)
        # 【1】查看当前返回值发现是一个对象类型
        print(f'obj :>>>> {obj}')
        # obj :>>>> <__main__.MyClass object at 0x000001984B032340>
        # 【2】发现当前对象的民称空间是空的
        print(f'obj.__dict__ :>>>> {obj.__dict__}')
        # obj.__dict__ :>>>> {}
        # 【五】调用自己的 __init__ 方法 初始化属性
        obj.__init__(*args, **kwargs)
        # 【】给自己的名称空间初始化属性
        print(f'obj.__dict__ :>>>> {obj.__dict__}')
        # obj.__dict__ :>>>> {'name': 'dream', 'age': 18}
        return obj
# MyClass 相当于给你一张纸
# 【一】类() 调用 ---> 一定会触发 __init__ 初始化对象的属性 #  __init__  给你人体骨架上个色
# 【二】在调用  __init__  之前要调用 __new__  # __new__ 相当于将你人体的骨架搭建好
m = MyClass('dream', age=18)
# 【六】完成对象属性的初始化
print(m.name)

2)元类中的__new__

class MyType(type):
    def __init__(cls, class_name, class_bases, class_name_space):
        print(f"给当前 MyType 类的对象初始化属性的时候会触发 __init__")
        super().__init__(class_name, class_bases, class_name_space)
    def __call__(self, *args, **kwargs):
        # 得到一个空的对象
        obj = super().__call__(*args, **kwargs)
        return obj
    # 【三】花骨架 有了骨架才能上色
    def __new__(cls, *args, **kwargs):
        print(f"给当前 MyType 类的对象创建骨架的时候会触发 __new__")
        # 【1】当前类本身
        print(f" MyType 类 的 __call__ 的 cls :>>>> {cls}")
        #  MyType 类 的 __call__ 的 cls :>>>> <class '__main__.MyType'>
        # 【2】当前类初始化传的位置参数
        print(f" MyType 类 的 __call__ 的 args :>>>> {args}")
        #  MyType 类 的 __call__ 的 args :>>>> ('MyClass', (), {'__module__': '__main__', '__qualname__': 'MyClass', '__init__': <function MyClass.__init__ at 0x0000016DE31ACAF0>, '__call__': <function MyClass.__call__ at 0x0000016DE31ACB80>})
        # 【3】当前类初始化传的关键字参数
        print(f" MyType 类 的 __call__ 的 kwargs :>>>> {kwargs}")
        # MyType 类 的 __call__ 的 kwargs :>>>> {}
        # 【四】让你的父类帮你大骨架
        obj = type.__new__(cls, *args, **kwargs)
        print(f'obj :>>>> {obj}')
        # obj :>>>> <class '__main__.MyClass'>
        print(f'obj.__dict__ :>>>> {obj.__dict__}')
        # obj.__dict__ :>>>> {'__module__': '__main__', '__init__': <function MyClass.__init__ at 0x0000023A62C2CB80>, '__call__': <function MyClass.__call__ at 0x0000023A62C2CC10>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}
        return obj
class MyClass(metaclass=MyType):
    def __init__(self, name, age):
        print(f"给当前 MyClass 类的对象初始化属性的时候会触发 __init__")
        self.name = name
        self.age = age
    def __call__(self, *args, **kwargs):
        print(f"当前 MyClass 类的对象被调用的时候会触发 __call__")
        return f'当前 MyClass 类 的 __call__ 的返回值 :>>>> {self.name}'
# MyClass 相当于给你一张纸
# 【一】类() 调用 ---> 一定会触发 __init__ 初始化对象的属性 #  __init__  给你人体骨架上个色
# 【二】在调用  __init__  之前要调用 __new__  # __new__ 相当于将你人体的骨架搭建好
m = MyClass('dream', age=18)
# 【六】完成对象属性的初始化
print(m.name)
posted on 2024-05-10 15:21  晓雾-Mist  阅读(10)  评论(0)    收藏  举报