面向对象(四)
面向对象(四)
上周回顾
派生类
重写:继承一个父类,然后重新定义其功能,使用super可以重新使用父类功能。
封装
将类中的数据或方法隐藏起来,不能直接访问或使用
- 必须在类定义阶段隐藏
- 隐藏方式为双下划线加变量名函数名
- 内部其实是一种变形
- 访问或使用该数据需要对外提供访问隐藏数据的接口
伪装
将功能名伪装成数据名
@property
多态
针对多个事物不需要考虑具体的特征,只需要了解其功能
鸭子类型理论:走路像鸭子,叫声像鸭子,那么他就是鸭子。
反射方法
利用字符串操作对象
hasattr() 查找字符串对应的功能或者数据是否存在
getattr() 拿出字符串对应的功能或者数据名
setattr() 为对象增加新的键值对
delattr() 删除对象功能或者数据

今日学习内容
反射实际案例
用注释理解上课案例
# 利用面向对象编写系统终端功能
class WinCmd(object): # 定义一个类
def ls(self): # 定义ls功能
print('windows系统正在执行ls命令')
def dir(self): # 定义dirgonn
print('windows系统正在执行dir命令')
def cd(self): # 定义cd功能
print('windows系统正在执行cd命令')
class LinuxCmd(object): # 定义另外一个类
def ls(self): # 定义ls功能
print('Linux系统正在执行ls命令')
def dir(self): # 定义dirgonn
print('Linux系统正在执行dir命令')
def cd(self): # 定义cd功能
print('Linux系统正在执行cd命令')
obj = WinCmd() # 创建一个win类的对象
obj1 = LinuxCmd() # 创建一个linx类的对象
"""反射提供了一种不需要考虑代码的前提下 操作数据和功能"""
def run(obj): # 定义一个函数,需要接受一个参数,该参数作为对象名
while True:
cmd = input('请输入您的指令>>>:') # 获取用户输入
if hasattr(obj, cmd): # 如果用户输入存在于这个对象中
func_name = getattr(obj, cmd) # 将他取出赋值给变量名
func_name() # 调用该功能
else:
print('cmd command not found') # 打印该功能不存在
run(obj1)
run(obj)
面向对象的双下方法
面向对象中的一部分双下方法,是达到某个条件就会自动触发的
类似于__init__ 在对象实例化的时候就会自动触发
下面我们来说一下其他双下方法的自动触发并执行
1.__str__
对对象进行打印操作时执行,必须返回字符串类型的数据,多数用来描述对象
2.__del__
对象执行完或者被主动删除的时候会执行
3.__getattr__
查找对象不存在名字的时候执行
4.__setattr__
为对象添加属性操作的时候执行
5.__call__
对象加括号调用的时候会执行,该方法返回什么,对象加括号就会获得什么
6.__enter__
对象使用with上下文管理语法自动执行,该方法返回什么as后面的变量名就会得到什么
7.__exit__
对象被执行with上下文管理语法结束之后自动触发,与__enter__配套使用
8.__getattribute__
查找对象名字就会触发,不管是否存在

笔试题讲解
1.让字典具备句点符查找值的功能
class MyDict(dict): # 定义一个类继承字典父类
def __getattr__(self, item): # __getattr__功能获取用户输入
return self.get(item) # 使用点get的方法获取字典数据的k值
def __setattr__(self, key, value): #__setattr__增加键值对
self[key] = value # 根据字典内置方法,k值存在修改,不存在增加键值对
obj = MyDict({'name':'jason','age':18})
obj.pwd = 123 # 给字典名称空间添加名字 不是数据k:v
print(obj)
2.补全下列代码 使其运行不报错
"""
class Context:
pass
with Context() as ctx:
ctx.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 ctx:
ctx.do_something()
元类简介
即产生类的类 type
type查看的其实是当前对象所属的类名称
<class 'type'>
'''type就是所有类默认的元类!!!'''
产生类的两种表现形式
一直以来使用的
1.class关键字
class C1(object):
pass
print(C1) # <class '__main__.C1'>
本质上class也是第二种方式
2.type元类
type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res) # <class '__main__.C1'>
掌握了类产生我们就可以高度定制类的产生行为
元类的基本使用
元类不能通过继承的方式直接指定。需要关键字参数的形式进行修改
class C1(metaclass=MyTypeClass):
pass
元类的进阶操作
根据__call__的触发条件
5.__call__
对象加括号调用的时候会执行,该方法返回什么,对象加括号就会获得什么
推导:类其实也有__call__方法,类加括号会执行元类的里面的__call__该方法返回什么其实类加括号就会得到什么
"""类里面的__init__方法和元类里面的__call__方法执行的先后顺序"""
class MyTypeClass(type): # 定义一个类继承type
def __call__(self, *args, **kwargs): # 重写__call__方法
print('__call__ run') # 查看__call__什么时候执行
super().__call__(*args, **kwargs) # 使用原本功能
class MyClass(metaclass=MyTypeClass): # 使用关键字继承
def __init__(self, name): # 重写__init__方法
print('__init__ run') # 查看__init__什么时候执行
self.name = name # 接受参数
obj = MyClass('eason')
结果:__call__ run
__init__ run
说明先产生一个对象先调用了__call__再调用了__init__产生对象。
# 定制对象的产生过程
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
if args:
raise Exception('必须以参数相等的方式使用所有关键字参数')
super().__call__(*args, **kwargs) # 正常产生
class MyClass(metaclass=MyTypeClass):
def __init__(self, name, age):
self.name = name
self.age = age
obj2 = MyClass(name='eason',age=21)
如果你想高度定制类的产生过程,那么编写元类里面的__init__方法。
如果你想高度定制对象的产生过程,那么编写元类里面的__call__方法。
双下new方法
__new__用于产生空对象(类) 骨架
__init__用于实例化对象(类) 血肉
注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
如果是在元类的__new__里面 可以直接调用
class Meta(type):
def __new__(cls, *args, **kwargs):
obj = type.__new__(cls,*args,**kwargs)
return obj
如果是在元类的__call__里面 需要间接调用
class Mate(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self) # 创建一个空对象
self.__init__(obj,*args,**kwargs) # 让对象去初始化
return obj
现在产生一个对象我们可以知道到底自动调用了几个双下方法
1.__new__
2.__call__
3.__init__
作业
编写元类规定对象的所有数据值转大写
class MyTypeClass(type): # 定义一个接受type的类
def __init__(self,name,bases,dic):
# 重写双下init方法,写入产生类的默认参数
if not name.isupper(): # 加上判断条件
raise Exception('类名必须全大写')
class EASON(metaclass=MyTypeClass): # 正确的情况
def a(self):
print('1')
def b(self, name, age):
self.name = name
self.age = age
print(self.name, self.age)
否则在类定义阶段就会报错

浙公网安备 33010602011771号