常用魔法方法和元类
1.流程控制语句2.计算机基础3.编程语言介绍4.python语言介绍5.python解释下载与安装6.python知识补充+语法入门7.基本数据类型8.基本运算符9.用户交互 输入输出方法10.字符编码11.可变与不可变数据类型12.文件操作的基本流程13.文件的基本操作14.异常处理15.深浅拷贝16.函数定义和调用17.函数的调用18.名称空间和作用域19.装饰器20.迭代器和三元运算符21.模块与包22.random、os、json模块23.hashlib、time模块24.正则25.datetime、sys、logging模块26.正则re模块27.常用的内置函数28.初识面向对象29.面向对象进阶30.封装、继承、多态
31.常用魔法方法和元类
32.网络编程初识33.网络编程进阶34.并发编程之多进程35.并发编程之多线程36.并发编程之协程常用魔法方法和元类
1.常用魔法方法
__init__ :初始化类时触发
__del__ :删除类时触发
__new__ :构造类时触发
__str__ :str函数或者print函数触发
__repr__ :repr或者交互式解释器触发
__doc__ :打印类内的注释内容
__enter__ :打开文档触发
__exit__ :关闭文档触发
__getattr__ : 访问不存在的属性时调用
__setattr__ :设置实例对象的一个新的属性时调用
__delattr__ :删除一个实例对象的属性时调用
__setitem__ :列表添加值
__getitem__ :将对象当作list使用
__delitem__ :列表删除值
__call__ :对象后面加括号,触发执行
# 面向中的魔法方法 就是 双下换线 __init__ 这种方法
# 魔法方法:因为这是在类中会自动触发的方法
class Person(object):
# 1. __init__:初始化对象方法,在初始化对象的属性的时候会触发
def __init__(self, name):
self.name = name
# 2. __str__ : 在打印对象的时候会触发,,返回值必须是字符串
# 用处就是用来定制打印对象时候显示的对象的信息的
def __str__(self):
print(f'打印的时候触发')
return f'当前是 {self.name} 的信息!'
# 3. __getattr__ : 获取不存在的属性会触发,他不会报错
def __getattr__(self, item):
# item 就是我们在 对象.属性 的哪个属性名字
print(f'触发了')
print(item)
return f'当前键 {item} 不存在 !'
# 4. __getattribute__ : 如果类里面定义了这个方法,在获取属性,不存在的属性时会先触发 __getattribute__,再触发__getattr__
# 不仅可以对不存在的键进行处理,还可以对存在的键进行处理
def __getattribute__(self, item):
return getattr(self, item)
print(item,type(item))
if hasattr(self, item):
return self.item
else:
raise ValueError(f"当前键 {item} 不存在!")
# 5. __delattr__ : 在删除对象中的某个属性的时候会触发,item就是想要删除的属性名
# 在这里我们可以对想要删除的属性名继续过滤,将敏感数据保留
def __delattr__(self, item):
# 这里你可以对敏感数据进行拦截 HOST PORT
print(item)
print(f'删除触发')
if item == 'HOST':
raise Exception("不能删除端口号!")
# 6. __call__ 方法 : 当想把对象当函数代用的时候可以给我们的类加一个 __call__ 方法,让他能被调用
def __call__(self, *args, **kwargs):
print(args)
print(kwargs)
print(f'对象() 会触发我! ')
...
# 7. __new__
# 8.基于父类的方法重写父类的方法 :派生
# 设置键会触发
def __setattr__(self, key, value):
...
# 删除键会触发
def __delattr__(self, item):
...
# __getattr__ : 没有才会触发
def __getattr__(self, item):
...
p = Person(name='serein')
p(name='formerly')
2. 练习
# 基于所学知识实现字典可以 .属性取值和放值
class MyDict(dict):
# 不写就会加载父类中的方法
# def __init__(self, seq=None, **kwargs):
# super().__init__(self, seq=seq, **kwargs)
# 获取值
def __getattr__(self, item):
# item : 需要取的键
# self.get(item): 根据键取值
# print(item)
return self.get(item)
# 设置值
def __setattr__(self, key, value):
self[key] = value
data_dict = MyDict({'name': 'serein'})
print(data_dict, type(data_dict))
# print(data_dict)
print(data_dict.name)
# 这里放进去的是 数据属性而不是原来的 k:v 键值对了
data_dict.age = 18
print(data_dict.age)
# user_data = {"name":"serein"}
# # print(user_data.name)
# user_data.age = 18
3. 元类
- 元类其实就是创建出类的类 -- type
class Student(object):
...
s = Student()
# 查看对象的类型
print(type(s)) # <class '__main__.Student'>
print(type(Student)) # <class 'type'>
print(type(object)) # <class 'type'>
# 创建类的两种方式
# 方式一:直接用关键字声明
class Student(object):
school = "清华大学"
def read(self):
...
print(type(Student)) # <class 'type'>
print(Student.__dict__) # {'__module__': '__main__', 'school': '清华大学', 'read': <function Student.read at 0x100eaf370>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
print(Student.__bases__) # (<class 'object'>,)
# 方式二:直接用 type 这个类创建一个新的类
Student = type('Student', (object,), {'school': "清华大学"})
print(type(Student)) # <class 'type'>
print(Student.__dict__) #{'school': '清华大学', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
print(Student.__bases__) # (<class 'object'>,)
# 总结 type 语法 :
# 类名 = type(类名,(父类1,父类2...),{类里面的数据属性})
# 【四】如何使用元类?
# 【1】基本语法
# 最基础最开始的元类
class MyMeta(type):
def __init__(cls, class_name, class_bases, class_dict):
print(f'这是 MyMeta 中的init方法被触发了')
if not class_name.istitle():
raise f'{class_name}必须开头字母大写'
# print(class_name) # MyClass
# print(class_bases) # (<class 'object'>,)
# print(class_dict) # {'__module__': '__main__', '__qualname__': 'MyClass', '__init__': <function MyClass.__init__ at 0x000002A251540360>}
super().__init__(class_name, class_bases, class_dict)
def __call__(self, *args, **kwargs):
print(f'这是 MyMeta 中的 __call__ 方法被触发了')
print(f'这是 MyMeta 中的 {args}')
print(f'这是 MyMeta 中的 {kwargs}')
obj = super().__call__(*args, **kwargs)
print(f'这是 MyMeta 中的 {obj}')
return obj
# 创建一个新的类:继承元类区别于继承父类
# class MyClass(类名)
class Myclass(object, metaclass=MyMeta):
def __init__(self, name):
print(f'这是 MyClass 中的init方法被触发了')
self.name = name
def __call__(self, *args, **kwargs):
print(f'这是 MyClass 中的 __call__ 方法被触发了')
print(args)
print(kwargs)
# 对象() ---> 触发了实例化得到自己的这个类里面的 __call__ 方法
p = Myclass(name='serein')
print(p)
# 【1】首先进入到 type __init__ 里面 ---> 将一个空的类创建出来 (类的名字、类的父类,类的名称空间)
# 【2】类() 触发了 type 中的 __call__ 方法
# 【需求】:定义一个类的时候,我这个类的名字只能大写字母开头,小写不行
# 【1】创建一个元类
# 【2】重写 type的 __init__ 方法
# 【3】类的名字、类的父类、类的名称空间
# 【4】对类的名字进行校验 调用父类 type 里面的 __init__ 方法 将需要的参数全都传进去
# 【5】创建一个自己的类 , metaclass=元类名字
print('-----')
class_name = 'Myclass'
if not class_name.istitle():
raise Exception("类的名字必须大写!")
else:
class_name = type(class_name, (), {})
print(class_name)
元类控制类初始化只能按关键字传参数
class MyMeta(type):
def __init__(cls, class_name, class_bases, class_dict):
print(f'这是 MyMeta 中的init方法被触发了')
if not class_name.istitle():
raise f'{class_name}必须开头字母大写'
# print(class_name) # MyClass
# print(class_bases) # (<class 'object'>,)
# print(class_dict) # {'__module__': '__main__', '__qualname__': 'MyClass', '__init__': <function MyClass.__init__ at 0x000002A251540360>}
super().__init__(class_name, class_bases, class_dict)
def __call__(self, *args, **kwargs):
print(f'这是 MyMeta 中的 __call__ 方法被触发了')
print(f'这是 MyMeta 中的 {args}')
if args:
raise Exception(f'参数只能按照关键字传参')
print(f'这是 MyMeta 中的 {kwargs}')
obj = super().__call__(*args, **kwargs)
print(f'这是 MyMeta 中的 {obj}')
return obj
# 创建一个新的类:继承元类区别于继承父类
# class MyClass(类名)
class Myclass(object, metaclass=MyMeta):
def __init__(self, name):
print(f'这是 MyClass 中的init方法被触发了')
self.name = name
def __call__(self, *args, **kwargs):
print(f'这是 MyClass 中的 __call__ 方法被触发了')
print(args)
print(kwargs)
# 对象() ---> 触发了实例化得到自己的这个类里面的 __call__ 方法
p = Myclass(name='serein')
p1 = Myclass('formerly')
print(p)
print(p1)
# __new__ 方法 :如果在元类里面就是产生空对象
# __init__ 方法 :往里面添加血和肉
class MyMeta(type):
# 填充血肉
def __init__(cls, class_name, class_bases, class_dict):
print(f'MyType 中的 init 方法 我被触发了')
super().__init__(class_name, class_bases, class_dict)
# 生成骨架
def __new__(cls, *args, **kwargs):
print(f'MyType 中的 new 方法 我被触发了')
print(args)
print(kwargs)
obj = type.__new__(cls, *args, **kwargs)
return obj
def __call__(self, *args, **kwargs):
print(f'MyType 中的 call 方法 我被触发了')
print(f'args: {args}, kwargs: {kwargs}')
# 创建对象并初始化参数
obj = super().__call__(*args, **kwargs)
# print(obj)
# 将产生的对象返回出去
return obj
class MyClass(object, metaclass=MyMeta):
def __init__(self, name):
print(f' MyClass 中的 init 方法 我被触发了')
self.name = name
def __call__(self, *args, **kwargs):
print(f' MyClass 中的 call 方法 我被触发了')
return 'call 方法返回的值'
def __new__(cls, *args, **kwargs):
print(f' MyClass 中的 new 方法 我被触发了')
print(args, kwargs)
# return super().__new__(cls)
obj = object.__new__(cls)
# obj.__init__(*args, **kwargs)
return obj
p = MyClass(name='serein')
p()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)