- 反射实战案列
- 面向对象魔法方法
- 魔法方法笔试题
- 元类简介
- 产生类的两种方式
- 元类的基本使用
- 元类进阶
- 双下new方法
1.加载配置文件纯大写的配置
# 配置文件加载:获取配置文件中所有大写的配置 小写的直接忽略 组织成字典
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)
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('%s 不是内部或外部命令,也不是可运行的程序或批处理文件' % cmd)
'''
请输入你的指令:xxx
xxx 不是内部或外部命令,也不是可运行的程序或批处理文件
请输入你的指令:ls
ls获取当前路径下所有的文件名称
请输入你的指令:dir
dir获取当前目录下所有的文件名称
请输入你的指令:ipconfig
ipconfig获取当前计算机的网卡信息
'''
面向对象魔法方法
-
理解
魔法方法其实就是类中定义的双下方法,之所以会叫魔法方法原因是这些方法都是到达某个条件自动触发 无需调用 eg:__init__方法在给对象设置独有的数据值的时候会自动触发(实例化)
方法 解释 __ init__ 给对象设置独有的数据的时候会自动触发 __ str__ 对象被执行打印(print、前端展示)操作的时候自动触发,该方法必须返回字符串类型的数据,很多时候用来更加精准的描述对象 __ del__ 对象被执行(被动、主动)删除操作之后自动执行 __ getattr__ 对象查找不存在的名字 __ setattr__ 对象在执行添加属性操作的时候自动触发 >>> obj.变量名=变量值 __ call__ 对象被加括号调用的时候自动触发 __ enter__ 开始进行with操作的时候 __ exit__ with操作结束的时候 __ getattribute__ 查找存不存在的时名字候都会触发,如果类中有__getattribute__方法 那么就不会去执行__getattr__方法 __ new__ 在类被实例化前,最先被执行的方法,主要用来去创建一个完全空白的对象;先走new,再走init -
举例说明(部分)
__call__方法
class MyClass(object):
def __init__(self, name):
"""实例化对象的时候自动触发"""
# print('__init__方法')
# pass
self.name = name
def __call__(self, *args, **kwargs):
"""对象加括号调用 自动触发该方法"""
print('__call__方法')
print(args)
print(kwargs)
'''
__call__方法
(1, 2)
{'a': 123}
'''
__getattr__方法
class MyClass(object):
def __init__(self, name):
"""实例化对象的时候自动触发"""
# print('__init__方法')
# pass
self.name = name
def __getattr__(self, item):
"""当对象获取一个不存在的属性名 自动触发
该方法返回什么 对象获取不存在的属性名就会得到什么
形参item就是对象想要获取的不存在的属性名
"""
print('__getattr__', item)
return '您想要获取的属性名:%s不存在' % item
obj = MyClass('jason')
print(obj.age) # age是不存在的
'''
__getattr__ age
您想要获取的属性名:age不存在
'''
class MyClass(object):
def __init__(self, name):
"""实例化对象的时候自动触发"""
# print('__init__方法')
# pass
self.name = name
def __del__(self):
"""对象在被删除(主动 被动)的时候自动触发"""
print('__del__') # 代码运行结束后会清空,所以会自动执行
obj = MyClass('jason')
'''
__del__
'''
class MyClass(object):
def __init__(self, name):
"""实例化对象的时候自动触发"""
# print('__init__方法')
# pass
self.name = name
def __setattr__(self, key, value):
"""对象操作属性值的时候自动触发>>>: 对象.属性名=属性值"""
print("__setattr__")
print(key)
print(value)
obj = MyClass('jason') # 执行一次
obj.name = 666 # 执行第二次
'''
__setattr__
name
jason
__setattr__
name
666
'''
魔法方法笔试题
要求:补全以下代码 执行之后不报错
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()
元类简介
- 简介
元类即产生类的类
- 引入
基础阶段我们使用type来查找数据的数据类型
但是学了面向对象之后 发现查看的不是数据类型 而是数据所属的类
我们也可以理解为type用于查看产生当前对象的类是谁
#type查看的其实是当前对象所属的类名称
print(type(123))
print(type([12, 33, 44]))
print(type({'name':'jason','pwd':123}))
'''
# 执行结果
'''
class MyClass:
pass
obj = MyClass()
print(type(obj)) # 查看产生对象obj的类:
print(type(MyClass)) # 查看产生对象MyClass的类:
通过上述推导 得出结论 自定义的类都是由type类产生的
我们将产生类的类称之为 '元类'
type就是所有类默认的元类!!!
产生类的两种方式方法一
1.class关键字
class MyClass:
pass
class C1(object):
pass
print(C1) #
方法二
2.利用元类type
type(类名,类的父类,类的名称空间)
type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res) #
元类的基本使用
元类是不能通过继承的方式直接指定的,需要通过关键字参数的形式修改
如果想要切换产生类的元类不能使用继承 必须使用关键字metaclass声明
举例说明(限制类的创建必须首字母大写)
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)
class Myclass(metaclass=MyMetaClass):
pass
元类进阶
元类不单单可以控制类的产生过程 其实也可以控制对象的!!!
我们回想双下call方法
对象加括号会自动执行产生该对象的类里面的__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__')
# 需求:实例化对象 所有的参数都必须采用关键字参数的形式
obj = MyClass('jason', 18)
# obj = MyClass(name='jason', age=18)
'''
__call__
Traceback (most recent call last):
File "D:/pythonProject/day33/01 反射的实战演练.py", line 115, in
obj = MyClass('jason', 18)
File "D:/pythonProject/day33/01 反射的实战演练.py", line 103, in __call__
raise Exception('必须用关键字参数传参')
Exception: 必须用关键字参数传参
'''
如果你想高度定制类的产生过程
那么编写元类里面的__init__方法
如果你想高度定制对象的产生过程
那么编写元类里面的__call__方法
类产生对象的步骤
1.产生一个空对象
2.自动触发__init__方法实例化对象
3.返回实例化好的对象先走new方法产生空对象,再走init方法实例化
__new__方法专门用于产生空对象 骨架
__init__方法专门用于给对象添加属性 血肉



