魔法方法
魔法方法就是面向对象的一些内置方法,在达到某个条件的时候会自动触发,不需要调用!
init
# 在对象实例化的时候会自动触发
# __init__方法
class Person:
def __init__(self):
print('实例化之后触发')
res = Person()
str
# 执行打印操作的时候会触发,并且有返回值,返回值只能是字符串类型,没有的话返回None
class Person:
def __init__(self):
print('')
def __str__(self):
print('执行打印操作的时候触发')
return '我必须是字符串'
res = Person()
print(res)
call
# 对象加括号的时候就可以触发,并且可以在括号里加参数
class Person:
def __call__(self, *args, **kwargs):
print('对象加括号就可以触发')
print(args)
print(kwargs)
res = Person()
res(1 , name='summer')
getattr
# 在对象获取属性名不存在的时候会触发,有返回值
class Person:
def __getattr__(self, item):
print('获取不存在的属性名的时候会触发')
print(item) # 对象获取的不存在的属性 name
return '我是getattr'
res = Person()
print(res.name)
getattribute
# 在对象用句点符获取属性的时候会自动触发,无论是否有这个属性。当类内同时有__getattr__ 和 __getattribute__ 会自动选择用__getattribute__方法
class Person:
def __getattr__(self, item):
print('获取不存在的属性名的时候会触发')
print(item) # 对象获取的不存在的属性 name
return '我是getattr'
def __getattribute__(self, item):
print('获取属性的时候会触发')
return '我是getattribute'
res = Person()
print(res.age)
![image]()
setattr
# 对象操作属性的时候会触发,eg:对象.name = summer
class Person(object):
def __init__(self,name):
self.name = name
def __setattr__(self, key, value):
print('我是setattr')
print(key) #name
print(value) #summer
res = Person('summer')
del
# 对象在删除操作的时候或者程序结束释放内存的时候会触发
class Person(object):
def __del__(self):
print('我是删除功能')
res = Person()
del res
enter 和 __exit——
# __enter__对象被with语法执行的时候会触发,该方法返回什么,as关键字后面的f就打印什么。
# __exit—— 对象被with语法执行并完成with语法子代码,才会触发
class Person(object):
def __enter__(self):
print('打印我')
return 666
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit')
res = Person()
with res as f:
print(f)
魔法方法笔试题
# 题目看下图 如何补全代码 让系统不报错????
class Context:
# 第一步 with语法执行了类名加括号 那么肯定有__enter__和__exit__方法
def __enter__(self):
return self
# 第二步 __enter__ 被with执行的时候 返回的是什么 f就打印什么
def __exit__(self, exc_type, exc_val, exc_tb):
pass
# 第三步 f.do_something() 其实就是对象.do_something() ,那么我们设置一个给对象的方法
def do_something(self):
pass
with Context() as f:
f.do_something()
![image]()
![image]()
元类
元类推导过程
# 元类推导过程
l1 = [1, 3, 4, 5, 6, 7, 8, 9, 10]
s1 = '充满元气的一天!!!冲冲冲'
d1 ={'name':'summer'}
print(type(l1)) # <class 'list'>
print(type(s1)) # <class 'str'>
print(type(d1)) # <class 'dict'>
# 通过type查看数据类型可以得出一个结论 这些数据类型是类产生的一个个对象
class P:
pass
res = P()
print(res,type(res)) # <class '__main__.P'>
# 用一切皆对象的编程思想我们是不是可以大胆的猜测一下,类名P是否也是一个对象
print(type(P)) # <class 'type'>
# 通过查看type源码 发现我们自定义的类是由type产生的类
****由此可得出结论:元类简单点讲就是产生类的类,可以产生类也可以控制对象的参数!!
![image]()
产生类的两种方式
# 方式一
class 类名:
pass
------------
# 方式二
# 利用元类 type
type (类名,类的父类,类的名称空间):
res = type ('cla',(),{})
print(res) # <class '__main__.cla'>
**我们学习元类是为了更好的高度定制类,就相当于我学会了怎么制造电脑,那么我就可以通过自己的需求去修改定制我想要的电脑
元类基本使用
# 只由继承了type的类才可以称之为元类!!!
class Myclass(type):
pass
class Iclass(metaclass=Myclass):
pass
# 如果想要继承自定义的类 需要使用关键字metaclass等于类名才可以实现 否则的话继承的是type
# __init__ 在类里面是实例化对象的 那么在元类里就是实例化类的
class Myclass(type):
def __init__(self, what, bases=None, dict=None):
print(what) # 类名 Iclass
print(bases) # 类的父类 ()
print(dict) # 类的名称空间 {'__module__': '__main__', '__qualname__': 'Iclass'}
# 如果我们想定制类 就可以直接在这里操作相应的方法了
# 比如想要类名首字母大写的话
if not what.istitle():
# 如果继承的类名字母没有大写的话就会打印
print('首字母必须大写!!!')
super().__init__(what, bases, dict)
class Iclass(metaclass=Myclass):
pass
元类进阶
# 元类定制对象参数案例
# 对象加括号触发的是产生这个对象的类的__call__方法
# 类名加括号触发的是产生这个类的__call__方法
# 可以定制对象的参数 要求是必须是关键字参数
class Myclass(type):
def __call__(self, *args, **kwargs):
print('我是元类里的call')
# print(args) # ('summer', '18')
# print(kwargs) # {}
if args:
raise Exception('参数必须采用关键字形式')
super().__call__(*args,**kwargs)
class Yclass(metaclass=Myclass):
def __init__(self, name, age):
# 在执行双下init方法之前 需要先执行元类的双下call方法
self.name = name
self.age = age
print('我是双下call执行完以后才执行的双下init')
res = Yclass(name = 'summer',age = '18')
双下new方法
class Myclass(type):
def __call__(self, *args, **kwargs):
print('')
obj = self.__new__(self,*args, **kwargs)
print(obj) # <__main__.Yclass object at 0x000002A5225BB1D0>
class Yclass(metaclass=Myclass):
def __init__(self, name, age):
# 在执行双下init方法之前 需要先执行元类的双下call方法new完对象以后开始执行init
self.name = name
self.age = age
print('')
res = Yclass()
反射实战案例
# 加载配置文件中的大写 组织成字典
import settings
path = dir(settings)
d1 = {}
for i in path:
if i.isupper():
# 有字符串和对象这两个关键字就可以用反射了
a = getattr(settings,i)
d1[i] = a
print(d1) # {'A': '现在好好敲代码是为了上班更好的摸鱼!!!', 'AGE': '18', 'NAME': 'summer'}