面向对象的结尾
1 > 反射的实际案例
编写利用面向对象编写系统终端功能
'''编写不同系统的终端功能'''
class WinCmd(object):
def ls(self):
print('windows系统正在执行ls命令')
def dir(self):
print('windows系统正在执行dir命令')
def cd(self):
print('windows系统正在执行cd命令')
class LinuxCmd(object):
def ls(self):
print('windows系统正在执行ls命令')
def dir(self):
print('windows系统正在执行dir命令')
def cd(self):
print('windows系统正在执行cd命令')
# 简易版本
obj = WinCmd()
obj1 = LinuxCmd()
while True:
cmd = input('请输入你想执行的指令 >>>>>:').strip()
# 利用反射判断类当中是否有该方法
if hasattr(obj, cmd):
func_name = getattr(obj, cmd)
func_name()
else:
print('cmd command not found')
# 函数版本
obj = WinCmd()
obj1 = LinuxCmd()
def run(obj1)
while True:
cmd = input('请输入你想执行的指令 >>>>>:').strip()
# 利用反射判断类当中是否有该方法
if hasattr(obj, cmd):
func_name = getattr(obj, cmd)
func_name()
else:
print('cmd command not found')
run(obj) # 进入window系统
run(obj1) # 进入Linux系统
2 > 面向对象的双下方法
面向对象的双下方法被有些人称之为是魔法方法,意思就是有些双下方法不需要刻意调用达到某个条件会自动触发,例如__init__ 就是在对象实例化的时候自动触发。
2.1 > str
该方法是当对象被执行打印(print 、前端展示)操作的时候自动触发,该方法必须返回字符串类型的数据,很多时候可以用来更加精准的描述对象,操作如下:
class MyClass(object):
def __init__(self, name):
self.name = name
del __str__(self)
return 'MyClass产生的对象%s'%self.name
obj = MyClass('bob')
print(obj)
# 打印 MyClass产生的对象:bob
2.2 > del
该方法当对象被执行(被动,主动)删除之后自动触发操作
class MyClass(object):
def __init__(self, name):
self.name = name
def __del__(self)
return '正在执行del方法'
obj = MyClass('bob')
print('打印功能执行中') # 当程序运行结束obj会被动删除
# 打印
'''
打印功能执行中
正在执行del方法
'''
print(obj) # 主动删除操作
def obj
'''
正在执行del方法
打印功能执行中
'''
2.3 > getattr
该方法当对象查找时当对象不存在名字的时候自动触发。
class MyClass(object):
def __init__(self, name):
self.name = name
del __getattr__(self, item)
return 'MyClass类中没有%s 这个名字'%item
obj = MyClass('bob')
print(obj.name) # bob
print(obj.age) # MyClass类中没有age 这个名字
2.4 > setattr
对象在执行添加属性操作的时候自动触发 例如 obj.变量名 = 变量值
class MyClass(object):
def __init__(self, name):
self.name = name
def __setattr__(slef, key, value):
print(key, value)
# 加入限制
if key == 'age':
print('你不能拥有%s属性'% key)
super().__setattr__(key, value)
obj = MyClass('bob')
obj.age = 18
print(obj__dict__)
# 打印
'''
name bob
你不能拥有age属性
{'name': 'bob'}
'''
2.5 > call
对象被加括号调用的时候自动触发
class MyClass(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **Kwargs):
print('__call__方法', *args, **kwargs)
return '开始执行call方法'
obj = MyClass('bob')
obj(123)
print(obj(123))
'''
__call__方法 (123, ) {}
开始执行call方法
'''
2.6 > enter
对象被执行with上下文管理语法开始自动触发,一般与__exit__ 一起使用。该方法返回什么as后面的变量名就会得到什么
class MyClass(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('__enter__方法')
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__ 方法')
obj = MyClass('bob')
with obj as f:
print(111)
print(222)
# 打印
'''
__enter__方法
111
__eixt__方法
222
'''
2.7 > exit
对象被执行with上下文管理语法结束之后自动触发
class MyClass(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('__enter__方法')
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__ 方法')
obj = MyClass('bob')
with obj as f:
print(111)
print(222)
# 打印
'''
__enter__方法
111
__eixt__方法
222
'''
2.8 > getattribute
只要对象查找名字无论名字是否存在都会执行该方法
如果类中有__getattribute__方法 那么就不会去执行__getattr__方法
class MyClass(object):
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('__getattr__方法')
def __getattribute__(self, item):
print('__getattribute__方法')
obj = MyClass('bob')
print(obj.name)
print(obj.age)
'''
__getattribute__方法
None
__getattribute__方法
None
'''
3 > 笔试题
3.1 > 字典具备句点符相应功能
让字典具备句点符查找名字的功能和用句点符添加键值对功能。
class MyDict(dict):
def __getattr__(self, item):
return self.item
def __setattr__(self, key, value)
self[key] = value
obj = MyDict({'name': 'bob', 'age':18})
print(obj.name)
print(obj.age)
obj.pwd = 123
print(obj.pwd)
# 打印
'''
bob
18
123
'''
3.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:
print(ctx)
ctx.do_something()
4 > 元类
4.1 > 间接
元类即产生类的类
'''前面我们学过可以用type查看数据的数据类型'''
print(type(123))
print(type([11, 22, 33, 44]))
print(type({'name': 'bob', 'pwd': 123})
'''
<class 'int'>
<class 'list'>
<class 'dict'>
'''
'''其实我们查看到的是当前对象所属的类的名称'''
class MyClass(object):
pass
obj = MyClass()
print(type(obj))
'''
<class '__main__.MyClass'>
'''
print(type(obj))
'''
<class 'type'>
'''
'''所以type就是所有类默认的元类'''
4.2 > 产生类的两种表现形式(本质是一种)
4.2.1 > class关键字
class C1(object):
pass
print(C1) # <class '__main__.C1'>
4.2.2 > type元类
type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res)
4.3 > 元类的基本使用
使用元类控制类的一些具体的行为,例如使类名的首字母必须是大写:
class MyTypeClass(type):
def __init__(cls, cls_name, cls_bases, cls_dict):
'''现在就限制了类名首字母必须是大写'''
if not cls_name.istitle():
raise Exception('类名的首字母必须是大写')
super().__init__(cls_name, cls_bases, cls_dict)
class C1(metaclass=MyTypeClass):
school = '清华大学'
''' 创建一个为a的类 '''
class a(metaclass = MyTypeClass):
pass
'''这时候执行程序就会报错'''
'''
Traceback (most recent call last):
File "D:/Py Projiect/Day_4.11/元类.py", line 22, in <module>
class a(metaclass=MyTypeClass):
File "D:/Py Projiect/Day_4.11/元类.py", line 17, in __init__
raise Exception('类名的首字母必须是大写')
Exception: 类名的首字母必须是大写
'''
4.4 > 元类进阶操作
一个对象的产生不仅仅是通过类当中的__init__ 方法 而是先通过元类当中的__call__ 方法再进入类当中的__init__ 方法产生一个对象。
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
print('__call__run')
super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
print('__init__ run')
self.name = name
obj = MyClass('bob')
元类当中的__call__ 方法当中的 args, 与Kwargs,分别是用来接收位置参数和关键字参数的,那么我们想要高度定制这个对象的产生过程,让在实例化产生对象的时候只能通过关键字来传入数据。那么我们就可以通过重新 call 方法。操作如下:
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
if args:
raise Exception('必须全部采用关键字参数')
return super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
self.name = name
obj = MyClass('bob')
'''
Traceback (most recent call last):
File "D:/Py Projiect/Day_4.11/元类进阶.py", line 11, in <module>
obj = MyClass('bob')
File "D:/Py Projiect/Day_4.11/元类进阶.py", line 4, in __call__
raise Exception('必须是关键字参数')
Exception: 必须是关键字参数
'''
obj = MyClass(name = 'bob')
print(obj.name)
'''
bob
'''
以上我们可以得出一个总结就是:
如果我们想高度定制类的产生过程:就要编写元类当中的__init__方法
如果我们想高度定制对象的产生过程:就要编写元类中的__call__方法
5 > 双下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