常见的类的内置方法
__call__方法
### 默认情况下“对象是不可调用的”————后面不能加括号 ### __call__方法可以让“对象变的可调用” class Foo: def __init__(self,name): self.name = name def __call__(self, *args, **kwargs): print(self.name) print(args) print(kwargs) if __name__ == '__main__': # 先实例化一个Foo的对象obj obj = Foo('HAHA') # 有了 __call__方法,obj后面可以“带参数调用” obj(1,2,3,a=1,b=2,c=3) ''' # 调用对象 obj() 会触发 __call__方法。类的调用其实也是一个实例化的过程 HAHA (1, 2, 3) {'a': 1, 'b': 2, 'c': 3} ''' ''' 拓展理解:元类的内部也有一个__call__方法,会在调用类Foo的时候触发 '''
__del__析构函数
这个方法是在对象就要被垃圾回收之前调用,但是调用的时间是不可预测的,应该尽量避免使用!
# __del__ ### 不调用__del__方法的话,会在程序结束后自动调用 ### 自己主动调用的话会在调用的地方执行这个析构方法 class Open: print('加载类...') def __init__(self,file_name): self.file_name = file_name print('构造函数...') def __del__(self): print('析构函数...') if __name__ == '__main__': print('main...') f = Open('whw.txt') print('do sth else...') ### 这里没有调用__del__方法,因为它会在程序执行结束自动执行! ''' 加载类... main... 构造函数... do sth else... 析构函数... '''
__getattr__与__getattribute__方法
1、__getattr__:查找不到属性的时候进入这里(不考虑继承)。
2、__getattribute__:执行查找,无条件进入该魔法函数,即使查找的属性不存在(不考虑继承)。
#__getattr__, __getattribute__ #__getattr__ 就是在查找不到属性的时候调用 class User: def __init__(self,info={}): self.info = info # 查找不到属性的时候进入这里 def __getattr__(self, item): return self.info[item] # 执行查找, 无条件进入该魔法函数, 即使所查找的属性不存在 # def __getattribute__(self, item): # return "火之影" if __name__ == "__main__": user = User(info={"company_name":"china", "name":"whw"}) ### 如果不注释__getattribute__会打印: """ 火之影 火之影 """ print(user.company_name) print(user.my_name) ### 如果注释掉_getattribute__会: """ 1.有company_name会打印china 2.没有my_name会报错 """
__getattr__、__getattribute__与继承的关系
结论:优先使用双下划线的方法中的值!
#__getattr__, __getattribute__ #__getattr__ 就是在查找不到属性的时候调用 class UserBase: def __init__(self,age): self.age = age self.my_name = "Base" class User(UserBase): def __init__(self,info={}): self.info = info super().__init__(info) # 查找不到属性的时候进入这里 def __getattr__(self, item): return self.info[item] # 执行查找, 无条件进入该魔法函数, 即使所查找的属性不存在 # def __getattribute__(self, item): # return "火之影" if __name__ == "__main__": user = User(info={"company_name":"china", "name":"whw"}) ### 如果不注释__getattribute__会打印:———— 优先会调用自己的__getattribute__方法返回的数据! """ 火之影 火之影 """ print(user.company_name) print(user.my_name) ### 如果注释掉__getattribute__会打印: """ china Base """
__item__系列
# __setitem__ __getitem__ __delitem__ class Student: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __getitem__(self, item): # return self.__dict__[item] return self.__dict__.get(item) def __setitem__(self,key,value): self.__dict__[key] = value def __delitem__(self, key): del self.__dict__[key] if __name__ == '__main__': s1 = Student('whw',22,'male') # 可以像操作字典那样操作类的对象了 print(s1['name'])#whw print(s1['age'])#22 s1['name'] = 'wanghw' print(s1['name'])#wanghw del s1['age'] print(s1.__dict__)#{'name': 'wanghw', 'sex': 'male'}
__getitem__与__len__
class Company(object): #魔法函数 def __init__(self, employee_list): self.employee = employee_list def __getitem__(self, item): return self.employee[item] def __len__(self): return len(self.employee) company = Company(["tom", "whw", "jane"]) # # for i in company.employee: # print(i) company1 = company[:2] # 调用__len__方法 print(len(company)) # 3 # 调用__getitem__方法 for em in company1: print(em) """ tom whw """
__new__方法1-1
# 在Python中,__new__是用来创造一个类的实例的,而__init__是用来初始化这个实例的 # 既然__new__用来创造实例,也就需要最后返回相应类的实例,那么如果返回的是其他类的实例,结果如何呢? # 以下代码运行后,首先打印出NoReturn __new__然后打印出other instance,最后通过type(y)可以看到t的类型是<class '__main__.Other'>, # 可以知道如果__new__中不返回本类的实例的话,是没法调用__init__方法的。 # 想要返回本类的实例,只需要把以下代码中12行的Other()改成super(NoReturn, cls).__new__(cls, *args, **kwargs)即可。 # 见1-2的代码~~ class Other(object): def __init__(self): print('other instance...') class Myinstance(object): def __init__(self): print('my instance...') def __new__(cls, *args, **kwargs): print('Myinstance__new__...') return Other() if __name__ == '__main__': my = Myinstance() print(type(my)) ''' Myinstance__new__... other instance... <class '__main__.Other'> ###### 注意这里是Other了! '''
__new__方法1-2
class Other(object): def __init__(self): print('other...') class Myinstance(object): def __init__(self): print('my instance...') def __new__(cls, *args, **kwargs): print('new...') ### 下面这三种方法都可以 # return super(Myinstance,cls).__new__(cls,*args,**kwargs) # return super().__new__(cls,*args,**kwargs) return object.__new__(cls) if __name__ == '__main__': my = Myinstance() print(type(my)) ''' new... my instance... <class '__main__.Myinstance'> '''
__new__方法2
class Person(object): def __init__(self): print('__init__...实例化对象的时候调用') def __del__(self): print('__del__...程序结束调用') def __str__(self): return '__str__...打印对象的时候调用' def __new__(cls, *args, **kwargs): print('__new__...我最先') return object.__new__(cls) if __name__ == '__main__': p = Person() print(p) ''' __new__...我最先 __init__...实例化对象的时候调用 __str__...打印对象的时候调用 __del__...程序结束调用 '''
__str__方法
# __str__方法 class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period def __str__(self): return '课程 %s 的价格为:%s,周期为:%s'%(self.name,self.price,self.period) if __name__ == '__main__': python = Course('Python',20000,'6 month') print(python.__str__()) # 课程 Python 的价格为:20000,周期为:6 month # 打印对象的时候,会自动触发实例化这个对象的类里的__str__方法 # 一般return的是self.name。 # 具体问题具体分析 print(python) # 课程 Python 的价格为:20000,周期为:6 month
__str__方法与__repr__方法
# -*- coding:utf-8 -*- class Course(object): def __init__(self,name,price): self.name = name self.price = price def __repr__(self): return f"name:{self.name},price:{self.price}" def __str__(self): return self.name if __name__ == '__main__': python = Course("Python",2500) print(python) print(f"{python}") print(repr(python)) print("详情:%r"%python)
""" # 如果str存在,repr也存在 # 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__ # 而repr(obj)和%r格式化字符串,都会调用__repr__ # 如果str不存在,repr存在 # 那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__ # 如果str存在,repr不存在 # 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__ # repr(obj)和%r格式化字符串 都会打印出内存地址 """
with上下文管理相关的方法 ***
with上下文管理
class File: def __enter__(self): print('start')
return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with File() as f_obj: print('wahaha')
自定义文件操作的类
class myopen: def __init__(self,path,mode='r'): self.path = path self.mode = mode def __enter__(self): print('start') self.f = open(self.path,mode=self.mode) return self.f def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() print('exit') with myopen('userinfo','a') as f: f.write('hello,world')
实例:pickle的dump与load的类
import pickle class MypickleDump: def __init__(self,path,mode = 'ab'): self.path = path self.mode = mode def __enter__(self): self.f = open(self.path,self.mode) return self def dump(self,obj): pickle.dump(obj,self.f) def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() with MypickleDump('pickle_file') as pickle_obj: pickle_obj.dump({1,2,3})
~~~
import pickle class MypickelLoad: def __init__(self,path,mode='rb'): self.path = path self.mode = mode def __enter__(self): self.f = open(self.path,self.mode) return self def loaditer(self): while True: try: ret = pickle.load(self.f) yield ret except EOFError: break def __exit__(self, exc_type, exc_val, exc_tb): self.f.close()
with MypickelLoad("pickle_file") as p2:
content = p2.loaditer()
for i in content:
print(i)
在一个函数前后添加功能
with语句 就是和 __enter__,__exit__ import time class Timer: def __enter__(self): self.start = time.time() def __exit__(self, exc_type, exc_val, exc_tb): print(time.time() - self.start) def func(): print('wahaha') time.sleep(1) print('qqxing') with Timer(): func()
~~