一:反射的实战演练
实战演练一:
想要实现的功能:加载配置文件纯大写的配置
- 1.先建一个settings.py文件,里面写入如下代码
name = 'zhang'
AGE = 18
def Get_money():
print('搞钱')
HOBBY = 'read'
- 2.代码实现
import settings
new_dict = {}
for i in dir(settings):
if i.isupper():
v = getattr(settings, i)
new_dict[i] = v
print(new_dict) # {'AGE': 18, 'HOBBY': 'read'}
实战演练二:
想要实现的功能:模拟操作系统cmd终端执行用户命令
- 1.代码实现
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)
二:面向对象魔法方法
1.什么是魔法方法?
- 魔法方法其实就是类中定义的双下方法
- 之所以会叫魔法方法原因是这些方法都是到达某个条件自动触发 无需调用
- eg: __ init __方法在给对象设置独有数据的时候自动触发(实例化)
2.方法
-
1 __ init__ 方法
-
实例化对象的时候自动触发
-
class MyClass(object): def __init__(self, name): self.name = name obj = MyClass('xie')
-
2 __ str __ 方法
-
对象被执行打印操作的时候会自动触发
-
该方法必须返回一个字符串
-
返回什么字符串打印对象之后就展示什么字符串
-
class MyClass(object): def __init__(self, name): self.name = name def __str__(self): return '对象:%s' % self.name obj = MyClass('xie') # 触发条件 print(obj)
-
3 __ call__ 方法
-
对象加括号调用 自动触发该方法
-
class MyClass(object): def __init__(self, name): self.name = name def __call__(self, *args, **kwargs): print('__call__方法') print(args) print(kwargs) # 触发条件 obj = MyClass('xie') obj()
-
4 __ getattr __方法
-
当对象获取一个不存在的属性名 自动触发 该方法返回什么 对象获取不存在的属性名就会得到什么 形参item就是对象想要获取的不存在的属性名
-
class MyClass(object): def __init__(self, name): self.name = name def __getattr__(self, item): print('__getattr__', item) return '您想要获取的属性名:%s不存在' % item obj = MyClass('xie') # 触发条件 obj.age
-
5 __ setattr __ 方法
-
对象操作属性值的时候自动触发>>>: 对象.属性名=属性值
-
class MyClass(object): def __init__(self, name): self.name = name def __setattr__(self, key, value): print("__setattr__") super().__setattr__(key, value) obj = MyClass('xie') # 触发条件 obj.name = 'wang'
-
6 __ del __ 方法
-
对象在被删除(主动 被动)的时候自动触发
-
class MyClass(object): def __init__(self, name): self.name = name def __del__(self): # print('__del__') pass obj = MyClass('xie') del obj
-
7 __ getattribute__ 方法
-
对象获取属性的时候自动触发 无论这个属性存不存在 当类中既有__ getattr __ 又有 __ getattribute__的时候 只会走后者
-
class MyClass(object): def __init__(self, name): self.name = name def __getattribute__(self, item): print('__getattribute__') return super().__getattribute__(item) # 简便写法 obj = MyClass('xie') # 触发方法 obj.age obj.name
-
8 __ enter __ 方法
-
对象被with语法执行的时候自动触发 该方法返回什么 as关键字后面的变量名就能得到什么
-
class MyClass(object): def __init__(self, name): self.name = name def __enter__(self): print('__enter__') obj = MyClass('xie')
-
9 __ exit __ 方法
-
对象被with语法执行并运行完with子代码之后 自动触发
-
def __exit__(self, exc_type, exc_val, exc_tb): print('__exit__')
3.魔法方法笔试题
"""补全以下代码 执行之后不报错"""
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()
三:元类
1.什么是元类?
- 我们将产生类的类称之为 ‘元类’
2.元类的推导过程
# s1 = '哈哈哈 今天下午终于可以敲代码了!!!'
# l2 = [60, 80, 100, 120, 150, 200]
# d = {'name': '死给我看', 'age': 18}
# print(type(s1)) # <class 'str'>
# print(type(l2)) # <class 'list'>
# print(type(d)) # <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类产生的
我们将产生类的类称之为 '元类'
"""
3.产生类的两种方式
1.class关键字
class MyClass:
pass
2.利用元类type
type(类名,类的父类,类的名称空间)
"""
学习元类其实就是掌握了类的产生过程 我们就可以在类的产生过程中高度定制化类的行为
eg:
类名必须首字母大写
上述需求就需要使用元类来控制类的产生过程 在过程中校验
"""
4.元类的基本使用
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', what) 类名
# print('bases', bases) 类的父类
# print('dict', dict) 类的名称空间
if not what.istitle():
# print('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
raise Exception('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
super().__init__(what, bases, dict)
"""只有继承了type的类才可以称之为是元类"""
# class Myclass(metaclass=MyMetaClass):
# pass
"""如果想要切换产生类的元类不能使用继承 必须使用关键字metaclass声明"""
class aaa(metaclass=MyMetaClass):
pass
5.元类的进阶
"""元类不单单可以控制类的产生过程 其实也可以控制对象的!!!"""
1.对象加括号执行产生该对象类里面的双下call
2.类加括号执行产生该类的元类里面的双下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__
如果我们想高度定制类的产生过程
可以操作元类里面的__init__
"""
6.双下new方法
"""
类产生对象的步骤
1.产生一个空对象
2.自动触发__init__方法实例化对象
3.返回实例化好的对象
"""
__new__方法专门用于产生空对象 骨架
__init__方法专门用于给对象添加属性 血肉