常见的内置方法、双下方法、魔法方法
内置方法是python的对象内部自带的
并且都比不需要我们自己去调用它
有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了
增强了用户的体验 在程序开发的过程中 如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,实际上是一种麻烦
如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示
__str__
打印这个对象的时候自动触发__str__
class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
def __str__(self):
'''打印这个对象的时候 自动触发__str__'''
'''使用%s进行字符串的拼接的时候 自动触发__str__'''
return '%s,%s,%s'%(self.name,self.price,self.period)
python = Course('python',25000,'6 months')
print(python)
print('course %s'%python)
print(f'course {python}')
如果没有实现__str__方法,那么对象打印出来的就只是一串内存地址
__repr__
class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period def __repr__(self): # 备用 return '%s,%s,%s'%(self.name,self.price,self.period) def __str__(self): return self.name python = Course('python',25000,'6 months') print(python) print('course %s'%python) print(f'course {python}') print(repr(python)) print('course %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格式化字符串 都会打印出内存地址
打印对象 先走自己的str,如果没有,走父类的,如果除了object之外的所有父类都没有str
再回来,找自己的repr,如果自己没有,再找父类的
repr是str的备胎 和所有的字符串格式化以及直接打印这个对象相关 str(obj),repr(obj)
__new__
构造方法 生产对象的时候用的 - 单例模式
class A: __flag=None def __new__(cls, *args, **kwargs): if cls.__flag is None: cls.__flag=object.__new__(cls) return cls.__flag def __init__(self,name=None,age=None): self.name=name if age: self.age=age a1=A('li',55) a2=A('s',33) print(a1) print(a2) print(a1.age)
如果不用__new__ 每次实例化的时候也会默认使用__new__ 但是每次实例化开辟的空间不一样
使用 单例模式后 每次实例化 都把信息放在这一个开辟的空间中 内存地址都一样
__del__ 析构方法 在删除一个对象之前用的 - 归还操作系统资源
import time class A: def __init__(self,path): self.f = open(path,'w') def __del__(self): '''归还一些操作系统的资源的时候使用''' '''包括文件\网络\数据库连接''' self.f.close() a = A('userinfo') time.sleep(1)
在删除这个之前执行一次里面的内容
大多使用在文件句柄的时候
感觉 好像没有太多其他的用途
__call__ 源码里用比较多 Flask web框架 对象()自动触发__call__中的内容
class A: def call(self): print('in call') def __call__(self, *args, **kwargs): print('in __call__') A()() obj = A() obj() obj.call()
构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
with语句 就是和 __enter__,__exit__
在一个函数的前后添加功能
利用使用 装饰器函数中的内容
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 obj: obj.dump({1,2,3,4}) with MypickelLoad('pickle_file') as obj: for i in obj.loaditer(): print(i)
class A: def __enter__(self): print('before') def __exit__(self, exc_type, exc_val, exc_tb): print('after') with A() as a: print('123')
class Myfile: def __init__(self,path,mode='r',encoding = 'utf-8'): self.path = path self.mode = mode self.encoding = encoding def __enter__(self): self.f = open(self.path, mode=self.mode, encoding=self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() with Myfile('file',mode='w') as f: f.write('wahaha')
__enter__中的内容是在执行with之前执行的
__exit__中的内容是在执行with之后执行的