面向对象魔法方法与元类
作者:互联网
反射实战案例
1.加载配置文件中所有纯大写的配置
import src # AA = '是大写', aa = '是小写'
new_dict = {}
print(dir(src)) # dir用于获取括号中对象可以调用的名字
# ['AA', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'aa']
for i in dir(src):
if i.isupper(): # 判断名字是不是纯大写
v = getattr(src, i)
new_dict[i] = v # 将纯大写的名字加入字典
print(new_dict)
# {'AA': '是大写'}
2.模拟操作系统cmd终端执行用户命令
class WinCmd(object):
def dir(self):
print('dir获取当前目录下所有的文件名称')
def ls(self):
print('ls获取当前路径下所有的文件名称')
def ipconfig(self):
print('ipconfig获取当前计算机的网卡信息')
obj = WinCmd()
while True:
cmd = input('输入命令>>>:').strip()
if hasattr(obj, cmd): # 判断对象是否含有字符串对应的属性
cmd_name = getattr(obj, cmd) # 获取对象字符串对应的属性
cmd_name()
else:
print(f'{cmd}不是内部或外部命令,也不是可运行的程序或批处理文件')
面向对象魔法方法
'''
魔法方法其实就是类中定义的双下方法,之所以叫魔法方法是因为这些方法都是达到某个条件就会自动触发,也就是对象实例化
eg:__init__
'''
class MyClass(object):
def __init__(self):
'实例化对象的时候触发'
print('触发__init__')
# self.name = name
pass
def __str__(self):
'''对象被执行打印操作的时候会触发
该方法必须返回一个字符串
返回什么字符串打印对象之后就展示什么字符串'''
print('触发__str__')
return ''
def __call__(self, *args, **kwargs):
'对象加括号调用时自动触发'
print('触发__call__')
print(args)
print(kwargs)
def __getattr__(self, item):
'''对象获得一个不存在的属性名时自动触发
对象获取的不存在的属性名会获取该方法的返回值
形参item就是对象获取的不存在的属性名'''
print('触发__getattr__')
return f'属性名:{item}不存在'
def __setattr__(self, key, value):
'对象操作属性值时自动触发(对象.属性名=属性值)'
print('触发__setattr__')
def __del__(self):
'对象在被删除的时候自动触发触发'
print('触发__del__')
def __getattribute__(self, item):
'''对象获取属性的时候自动触发
无论这个属性存不存在
当类中既有__getattr__又有__getattribute__时只会走后者'''
print('触发__getattribute__')
def __enter__(self):
'对象被with语法执行时自动触发,该方法返回什么,as关键字后面的变量名就能得到什么'
print('触发__enter__')
return '对象被with语法执行'
def __exit__(self, exc_type, exc_val, exc_tb):
'对象被with语法执行并运行子代码之后自动触发'
print('触发__exit__')
res = MyClass() # 触发__init__
print(res) # 触发__str__
res(1, 2, name='barry', age=20) # 触发__call__
# (1, 2)
# {'name': 'barry', 'age': 20}
print(res.name) # 触发__getattr__
# 属性名:name不存在
res.name = 'barry' # 触发__setattr__
del res # 触发__del__
print(res.name) # 触发__getattribute__
# None
with res as f:
print(f)
# 触发__enter__
# 对象被with语法执行
# 触发__exit__
魔法方法笔试题
class Context:
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Context() as f:
f.do_something()
"""补全以上代码 执行之后不报错"""
class Context:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def do_something(self):
pass
with Context() as f:
f.do_something()
元类简介
s1 = '字符串'
l1 = ['列表']
d1 = {'这是': '字典'}
print(type(s1)) # <class 'str'>
print(type(l1)) # <class 'list'>
print(type(d1)) # <class 'dict'>
'''
我们以前一直用type来查看数据类型
但其实查看的不是数据类型而是数据所属的类
我们定义的数据类型本质还是通过类产生的对象
class str:
pass
h = 'hello' str('hello')
可以理解为type用于查看当前对象的类是谁
'''
class MyClass:
pass
obj = MyClass()
print(type(obj)) # 查看产生对象obj的类:<class '__main__.MyClass'>
print(type(MyClass)) # 查看产生对象MyClass的类:<class 'type'>
"由此,我们可以得出结论,自定义的类都是由type类产生的,我们将产生类的类称为'元类'"
产生类的两种方式
1.class 关键字
class 类名:
pass
2.利用元类type
type(类名,类的父类,类的名称空间)
'利用元类type来产生类虽然更繁琐,但可以帮我们高度定制产生类的过程'
元类的使用
class MyMetaClass(type):
pass
'只有继承了type的类才可以称之为是元类'
class MyClass(metaclass=MyMetaClass):
pass
'使用关键字metaclass声明才可以切换产生类的元类'
'''
类中的__init__用于实例化对象
元类中__init__用于实例化类
'''
class MyMetaClass(type):
def __init__(self, what, bases=None, dict=None):
print('使用自定义的元类')
# 使用自定义的元类
print(what) # 类名
# MyClass
print(bases) # 类的父类
# ()
print(dict) # 类的名称空间
# {'__module__': '__main__', '__qualname__': 'MyClass'}
if not what.istitle(): # 判断类名首字母是否大写
raise Exception('首字母必须大写') # 首字母不是大写则报错
super().__init__(what, bases, dict) # 首字母大写则产生类
'只有继承了type的类才可以称之为是元类'
class Myclass(metaclass=MyMetaClass):
pass
class abc(metaclass=MyMetaClass):
pass
# 报错:Exception: 首字母必须大写
元类进阶
'元类不止可以控制类的产生,还可以控制对象的产生'
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
print('触发__call__')
if args:
raise Exception('必须使用关键字传参')
super().__call__(*args, **kwargs)
class Myclass(metaclass=MyMetaClass):
def __init__(self, name, age):
self.name = name
self.age = age
print('触发__init__')
obj = Myclass('barry', 20)
# 报错:Exception: 必须使用关键字传参
obj = Myclass(name='barry', age=20)
# 触发__call__
# 触发__init__
'''
我们可以操作元类里面的__call__来定制对象的产生过程
我们可以操作元类里面的__init__来定制类的产生过程
'''
双下new方法
'''
类产生对象的步骤
1.产生一个空对象
2.自动触发__init__方法实例化对象
3.返回实例化好的对象
'''
__new__方法专门用于产生空对象
__init__方法专门用于给对象添加属性
标签:__,触发,self,魔法,元类,面向对象,print,type,def 来源: https://www.cnblogs.com/riuqi/p/16535429.html