元类

今日内容概要

  • 面向对象的魔法方法
  • 魔法方法笔试题
  • 元类简介
  • 创建类的两种方式
  • 元类定制类的产生行为
  • 元类定制对象的产生行为
  • 魔法方法下之双下new
  • 设计模式简介

面向对象的魔法方法

魔法方法:类中定义的双下方法都称之为魔法方法

不需要人为调用 在特定的条件下回自动调用

  1. _init_

    """
    1.__init__
    当类名加括号的时候 会自动调用 __init__ 方法
    """
    
    class A:
        def __init__(self, name):
            print("我是__init__哦")
            self.name = name
    
    
    A("jason")
    
    

  2. _str_

    """
    1.__str__
    
    当对象被打印的时候会自动执行,产生该对象的类里面的__new__方法
    打印出__new__ 的返回值。 返回值只能是字符串类型
    """
    
    
    class A:
        def __init__(self):
            pass
    
        def __str__(self):
            return "哈哈"
    
    
    obj = A()
    print(obj)
    

  1. _call_

    """
    3.__call__
    就是能不能加括号, 如果对象加括号就是在调用类里面的__call__方法
    类加括号就是在调用元类里面的__call__ 方法
    
    """
    
    class A:
        pass
    
    obj = A()
    obj()
    

    class A:
        def __call__(self, *args, **kwargs):
            pass
    
    obj = A()
    obj()
    

  2. _getattr_

    """
    4.__getattr__
    当对象点不存在的名字的时候回自动调用__getattr__
    如果点的名字存在则不会调用__getattr__
    
    """
    
    class A:
        def __init__(self, name):
            self.name = name
    
        def __getattr__(self, item):
            print(item)
            print("我是__getattr__")
            return 123
    
    obj = A("jason")
    print(obj.name)
    
    

    class A:
        def __init__(self, name):
            self.name = name
    
        def __getattr__(self, item):
            print(item)
            print("我是__getattr__")
            return 123
    
    obj = A("jason")
    print(obj.age)
    
    

  3. _getattribute_

    """
    5.__getattribute__
    不管对象点的名字存在不存在 则都会执行__getattribute__方法
    
    """
    class A:
        def __init__(self, name):
            self.name = name
    
        def __getattribute__(self, item):
            print(item)
            return 123
    
    obj = A("jason")
    print(obj.name)
    print(obj.age)
    

  4. _setattr_

    """
    6.__setattr__
    只要 是 对象.名字 = 数据值
    给对象添加或者修改数据的时候自动调用 对象.名字 = 数据值
    
    """
    class A:
        def __init__(self, name):
            self.name = name
    
        def __setattr__(self, key, value):
            print("我是 __setattr__")
    
    obj = A("jason")
    obj.name = "set"
    

  5. _enter_,_exit_

    """
    7.__enter__ , __exit__
    __enter__当对象被当作with上下文管理操作的对象开始自动触发
    并且该方法返回什么 as 后面的变量名就会接收到什么
    __exit__当对象被当作with上下文管理操作的对象结束自动触发
    
    """
    class A:
        def __enter__(self):
            return 123
        def __exit__(self, exc_type, exc_val, exc_tb):
            print(456)
    
    
    obj = A()
    with obj as f:
        print(f)
    
    

魔法方法笔试题

"""
1.补全下列代码使得运行不报错即可


分析: Context 加括号产生对象 with 了一个对象
所以类里面有个

因为__enter__ 返回什么 f接收什么
"""
class Context:
    def do_sonmething(self):
        pass
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


with Context() as f:
    f.do_sonmething()

"""
2.自定义字典类型并让字典能够通过句点符的方式操作键值对

分析: 自定义字典 那么先继承字典
能够点名字 __getattr__
也能点名字 修改 对象.名字 = 数据值 __setattr__
"""
class Mydict(dict):
    def __getattr__(self, item):
        return self.get(item)

    def __setattr__(self, key, value):
        # 因为 实例化的对象是字典 所以 我们直接按字典来就行
        self[key] = value


d1 = Mydict()

d1.name = "jason"
print(d1.name)
print(d1)

""" 如果你不写__setattr__方法
他会添加到对象的名称空间里面  而不是对象里面
"""
class Mydict(dict):
    def __getattr__(self, item):
        return self.get(item)

d1 = Mydict()

d1.name = "jason"
print(d1.name)
print(d1)
print(d1.__dict__)

元类简介

元类 就是产生类的类叫元类

"""
type 其实查看的是产生对象的类名
"""
class A:
    pass


obj = A()
print(type(obj))  # <class '__main__.A'>

"""
type对象 是产生该对象的类名 那type  类呢

"""
print(type(A))  # <class 'type'>

"""
type 类 我们得到了type 
那么产生类的类是type
结论:我们定义的类其实都是由type类产生的>>>:元类(产生类的类)
"""

创建类的两种方式

"""
方式一:
class 关键字
"""
class A:
    pass

"""
方式二
利用元类type 创建

type 源码
    type(object) -> the object's type
    type(name, bases, dict) -> a new type

第一条是 type一个对象回返回 对象的类型

第二条 type里面传一个类名  类的父类元组形式 名称空间
会得到一个新类    

"""
class_name = "Student"
class_base = ()
class_dict = {}

class_info = """

school_name = '哈哈学院'
def __init__(self, name):
    self.name = name

"""
exec(class_info, {}, class_dict)

Student = type(class_name, class_base, class_dict)

print(type(Student))
obj = Student("jason")
print(obj.name)
print(obj.school_name)

元类定制类的产生行为

"""

类是由元类加括号产生的 元类加括号会执行__init__ 方法

要求 必须类名开头字母大写才可以 不然报错
"""



# 只有继承了type 才叫元类
class Mytype(type):
    def __init__(self, *args, **kwargs):
        print(args, kwargs)
        if not args[0].istitle():
            raise TypeError("类名开头必须大写")
        super().__init__(*args, **kwargs)


class student(metaclass=Mytype):
    pass

元类定制对象的产生行为

"""

对象加括号 会执行产生对象类的__call__方法
类加括号 会执行产生类的类的__call__方法


要求 给对象加独有数据的时候 必须采用关键字传参


类加括号产生对象  类加括号 调用元类的__call__
在__call__ 里操作
"""

class Mytype(type):
    def __call__(self, *args, **kwargs):
        print(args, kwargs)
        if args:
            raise TypeError("只能关键字传参")
        return super().__call__(*args, **kwargs)


class Student(metaclass=Mytype):
    def __init__(self, name, age):
        self.name = name
        self.age = age


Student("jaosn", "age")

魔法方法之双下new


class Mytype(type):
    def __call__(self, *args, **kwargs):
        """
        元类里面的__call__ 会做三件事
        1. 调用self 的__new__ 方法产生一个空对象
        2. 把空对象 当成第一个参数传给 self 下的 __init__方法
        3. 把这个被__init__ 方法操作过的 空对象(现在已经不是空对象了)
           返回出去

        """
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)
        return obj

class Student(metaclass=Mytype):
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj = Student("jaosn", "age")
print(obj.name)

设计单例模式

  1. 设计模式

    前人通过大量的验证创建出来解决一些问题的固定方法

  2. IT行业

    23种

    ​ 创建型

    ​ 结构型

    ​ 行为型

  3. 单例模式

    类加括号无论多少次永远只会产生一个对象

    目的:

    ​ 当类中后很多非常强大的方法 我们在过程中很多地方都需要使用

    ​ 如果不做单例 会产生很多无用的对象浪费存储空间

    我们想使用单例模式 整个程序就用一个对象

posted @ 2022-11-08 20:15  可否  阅读(37)  评论(0)    收藏  举报