面向对象的魔法方法
| 魔法方法:类中定义的双下方法都称为魔法方法 |
| 不需要人为调用 在特定的条件下回自动触发运行 |
| eg:__init__创建空对象之后自动触发给对象添加独有的数据 |
| |
| 1.__init__ |
| 对象添加独有数据的时候自动触发 |
| 2.___str__ |
| 对象被执行打印操作的时候自动触发 |
| 3.__call__ |
| 对象加括号调用的时候自动触发 |
| 4.__getattr__ |
| 对象点不存在的名字的时候自动触发 |
| 5.__getattribute__ |
| 对象点名字就会自动触发 有它的存在就不会执行上面的__getattr__ |
| 6.__setattr__ |
| 给对象添加或者修改数据的时候自动触发 对象.名字 = 值 |
| 7.__enter__ |
| 当对象被当做with上下文管理操作的开始自动触发 并且该方法返回什么 as后面的变量名就会接收到什么 |
| 8.__exit__ |
| with上下文管理语法运行完毕之后自动触发(子代码结束) |
| class Student: |
| def __init__(self, name, age): |
| self.name = name |
| self.age = age |
| |
| def __str__(self): |
| """打印对象则会自动触发""" |
| |
| |
| |
| def __call__(self, *args, **kwargs): |
| """对象加括号则会触发调用""" |
| |
| return self |
| |
| def __getattr__(self, item): |
| """对象点名字不存在,则会触发""" |
| |
| |
| |
| |
| """无论对象点名字是否存在,都会自动触发,一般不建议使用,建议使用上面的""" |
| |
| |
| |
| |
| """给对象添加或修改对象数据,对象.name = 数据值 会自动触发""" |
| |
| |
| |
| |
| def __enter__(self): |
| """当对象被当作上下文管理操作的开始自动触发 并且该方法返回什么 as 后面变量名就会接收到什么""" |
| return self |
| |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| """with上下文管理语法运行完毕之后自动触发(子代码结束)""" |
| pass |
| |
| |
| obj = Student('张三', 18) |
| |
| |
| |
| |
| |
| with obj as f: |
| print(f.age) |
魔法方法笔试题
| 1.补全下列代码使得运行不报错即可 |
| class Context: |
| pass |
| with Context() as f: |
| f.do_something() |
| |
| class Context: |
| def do_something(self): |
| pass |
| def __enter__(self): |
| return self |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| pass |
| with Context() as f: |
| f.do_something() |
| |
| |
| 2.自定义字典类型并让字典能够通过句点符的方式操作键值对 |
| class MyDict(dict): |
| def __setattr__(self, key, value): |
| self[key] = value |
| |
| def __getattr__(self, item): |
| return self.get(item) |
| obj = MyDict() |
| obj.name = 'jason' |
| obj.pwd = 18 |
| obj.hobby = 'read' |
| |
| print(obj.name) |
| print(obj.pwd) |
| print(obj.hobby) |
| |
| |
| |
| print(type(obj)) |
元类简介
| """推导步骤1:如何查看数据的数据类型""" |
| |
| |
| |
| |
| |
| |
| |
| |
| """推导步骤2:其实type方法是用来查看产生对象的类名""" |
| |
| |
| |
| |
| """推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么""" |
| class Student: |
| pass |
| obj = Student() |
| print(type(obj)) |
| print(type(Student)) |
| class A:pass |
| class B:pass |
| print(type(A), type(B)) |
| """结论:我们定义的类其实都是由type类产生的>>>:元类(产生类的类)""" |
| print(type(type)) |
| |
创建类的两种方式
| |
| |
| class Student: |
| pass |
| |
| |
| print(Student) |
| |
| |
| |
| cls = type('Student', (object,), {}) |
| print(cls) |
| """ |
| 了解知识:名称空间的产生 |
| 1.手动填写键值对 |
| 针对绑定方法不好定义 |
| 2.内置方法exec |
| 能够运行字符串类型的代码并产生名称空间 |
| |
| """ |
元类定制类的产生行为
| """ |
| 推导 |
| 对象是由类名加括产生的 调用类init方法 |
| 类是由元类加括号产生的 调用元类种init方法 |
| |
| """ |
| |
| class MyClass(type): |
| |
| def __init__(self, what: str, bases=None, dict=None): |
| if not what.istitle(): |
| raise TypeError("不是以大写之母开头") |
| |
| super().__init__(what, bases, dict) |
| |
| |
| class A(metaclass=MyClass): |
| pass |
| |
| obj = A() |
| |
| class aA(metaclass=MyClass): |
| pass |
| |
| obj = aA() |
元类定制对象的产生行为
| """ |
| 推导 |
| 对象加括号会执行产生该类里面的 __call__方法 |
| 类加括号会执行产生该类的元类里面的 __call__方法 |
| |
| """ |
| """给对象添加独有数据的时候 必须采用关键字参数传参""" |
| |
| class MyMetaClass(type): |
| def __call__(self, *args, **kwargs): |
| |
| |
| |
| |
| |
| if args: |
| raise TypeError("你怎么回事 Jason要求对象的独有数据必须按照关键字参数传参 我看你是不想干了!!!") |
| return super().__call__(*args, **kwargs) |
| |
| |
| class Student(metaclass=MyMetaClass): |
| def __init__(self, name, age, gender): |
| |
| self.name = name |
| self.age = age |
| self.gender = gender |
| |
| |
| |
| obj = Student(name='jason',age= 18,gender= 'male') |
| print(obj.__dict__) |
魔法方法之算个下new
| class MyMetaClass(type): |
| def __call__(self, *args, **kwargs): |
| |
| obj = self.__new__(self) |
| |
| self.__init__(obj,*args, **kwargs) |
| |
| return obj |
| |
| |
| class Student(metaclass=MyMetaClass): |
| def __init__(self, name): |
| self.name = name |
| |
| obj = Student('jason') |
| print(obj.name) |
| """ |
| __new__可以产生空对象 |
| """ |
设计模式
| 1.设计模式 |
| 前人通过大量的验证创建出来解决一些问题的固定高效方法 |
| 2.IT行业 |
| 23种 |
| 创建型:5种 |
| 结构型:7种 |
| 行为型:11种 |
| 3.单例模式 |
| 类加括号无论执行多少次永远只会产生一个对象 |
| 目的: |
| 当类中有很多非常强大的方法 我们在程序很多地方都需要使用 |
| 如果不做单例 会产生很多无用的对象浪费存储空间 |
| 我们想着使用单例模式 整个整型就用一个对象则可以节省大量内存空间 |
元类全流程
| """ |
| Author:clever-cat |
| time :2022/11/8-18:05 |
| """ |
| |
| |
| class MyClass(type): |
| |
| def __init__(self, *args, **kwargs): |
| print('init') |
| pass |
| |
| """下面的在有双下new的时候有没有都无所谓""" |
| |
| |
| |
| |
| |
| |
| |
| def __call__(cls, *args, **kwargs): |
| print("from MyClass __call__") |
| print(cls.__dict__, 'bbbbbbbb') |
| res = super().__call__(*args, **kwargs) |
| print(id(res), "from MyClass __call__", type(res), res.__dict__) |
| return res |
| |
| def __new__(cls, *args, **kwargs): |
| |
| if not args[0].istitle(): |
| raise NameError('名字必须大写') |
| """用元类type里面的双下new方法创建类""" |
| res = super().__new__(cls, *args, **kwargs) |
| print(id(res), res, type(res), res.__dict__, res.mro()) |
| |
| return res |
| |
| |
| class B: |
| pass |
| |
| |
| class T1(B, metaclass=MyClass): |
| def __init__(self, name): |
| print(id(self)) |
| self.name = name |
| print("from T1 __init__", self.__dict__) |
| |
| def __call__(self, *args, **kwargs): |
| print(args, kwargs) |
| print("from T1 __call__") |
| return self |
| |
| def __new__(cls, *args, **kwargs): |
| print("from T1 __new__") |
| """用object类创建对象""" |
| res = super().__new__(cls) |
| print(id(res), "from T1 __new__", res.__dict__) |
| |
| return res |
| |
| |
| cls = T1 |
| obj1 = cls('张三') |
| |
| |
| print(id(cls), 'T1这个类', cls, obj1) |
| obj1(1312,1231,'123123',namea='1231') |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步