Python面向对象之魔法方法、元类
反射实战案例
-
加载配置文件纯大写的配置
# 配置文件加载:获取配置文件中所有大写的配置 小写的直接忽略 组织成字典 import settings new_dict = {} # print(dir(settings)) # dir获取括号中对象可以调用的名字 # ['AGE', 'INFO', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'name'] for i in dir(settings): if i.isupper(): # 如果名字是纯大写 那么获取该大写名字对应的值 'AGE' 'INFO' v = getattr(settings, i) new_dict[i] = v print(new_dict) -
模拟操作系统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('请输入您的命令>>>:')
if hasattr(obj, cmd):
cmd_name = getattr(obj, cmd)
cmd_name()
else:
print('%s 不是内部或外部命令,也不是可运行的程序或批处理文件' % cmd)
面向对象魔法方法
概念
魔法方法其实就是类中定义的双下方法
这些双下方法不需要刻意调用,到达某个条件会自动触发
eg:
__init__方法在给对象设置独有数据的时候自动触发(实例化)
常用的魔法方法
| 方法 | 触发条件 | 描述 |
|---|---|---|
__init__ |
实例化对象之后立即触发 | 初始化对象的成员 |
__new__ |
实例化对象时自动触发(在__init__之前触发) | 实例化对象 |
__del__ |
当该类对象被销毁时,自动触发 | 关闭或释放对象创建时资源 |
__call__ |
将对象当作函数调用时触发,方式: 对象() | 可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用 |
__str__ |
使用print(对象)或者str(对象)的时候触发 | print(对象时)进行操作,得到字符串,通常用于快捷操作 |
与属性操作相关的魔法方法
| 方法 | 触发条件 | 描述 |
|---|---|---|
__getattr__ |
获取不存在的对象成员时触发 | 为访问不存在的属性设置值 |
__setattr__ |
设置对象成员值的时候触发 | 接管设置操作,可以在设置前之前进行判断验证等行为 |
__getattribute__ |
使用对象成员时触发,无论成员是否存在 | 在具有封装操作(私有化时),为程序开部分访问权限使用 |
上下文管理相关魔法方法(with)
| 方法 | 触发条件 | 描述 |
|---|---|---|
__enter__ |
对象被with 语法执行上下文操作的时候自动触发 | enter 的返回值被 with 语句的目标或者 as 后的名字绑定 |
__exit__ |
对象被with语法执行并运行完with子代码后 自动触发 | 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作 |
魔法方法笔试题
"""补全以下代码 执行之后不报错"""
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()
元类
即产生类的类
print(type(123)) # <class 'int'>
print(type([12, 33, 44])) # <class 'list'>
print(type({'name':'jason','pwd':123})) # <class 'dict'>
'''type查看的其实是当前对象所属的类名称'''
class MyClass(object):
pass
obj = MyClass()
print(type(obj))
print(type(MyClass)) # <class 'type'>
class Student:
pass
print(type(Student)) # <class 'type'>
class Teacher(MyClass):
pass
print(type(Teacher)) # <class 'type'>
'''type就是所有类默认的元类!!!'''
产生类的两种方式
1. class关键字
class MyClass:
pass
2. 利用元类type
type(类名,类的父类,类的名称空间)
学习元类其实就是掌握了类的产生过程 我们就可以在类的产生过程中高度定制化类的行为
eg:
类名必须首字母大写
'''上述需求就需要使用元类来控制类的产生过程 在过程中校验'''
元类基本使用
元类是不能通过继承的方式直接指定的,需要通过关键字参数的形式修改
class MyClass(metaclass=MyMetaClass):
pass
例
class MyMetaClass(type):
def __init__(self,what, bases=None, dict=None):
# print('迷茫')
# print('what', what) 类名
# print('bases', bases) 类的父类
# print('dict', dict) 类的名称空间
if not what.istitle():
# print('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
raise Exception('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
super().__init__(what, bases, dict)
"""如果想要切换产生类的元类不能使用继承 必须使用关键字metaclass声明"""
class aaa(metaclass=MyMetaClass):
pass
元类进阶
元类不单单可以控制类的产生过程,也可以控制对象
- 对象加括号执行产生该对象类里面的
__call__ - 类加括号执行产生该类的元类里面的
__call__
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__')
- 若要高度定制对象的产生过程,可以操作元类里面的
__call__- 若要想高度定制类的产生过程,可以操作元类里面的
__init__
双下new方法
__new__用于产生空对象(类),相当于骨架
__init__用于实例化对象(类),相当于血肉
类产生对象的步骤
- 产生一个空对象
2. 自动触发__init__方法实例化对象
3. 返回实例化好的对象

浙公网安备 33010602011771号