__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 方法,打印出的只是一串地址
lst = [1,2,3]
print(lst)
lst是对象,打印的时候直接显示的是元素
因为python自动给了 list.__str__() 的str方法
__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__ 的备胎
如果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格式化字符串 都会打印出内存地址
class Course(object): 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 class Python(Course): pass # def __repr__(self): # 备胎 # return '%s--%s--%s'%(self.name,self.price,self.period) # def __str__(self): # return '全栈开发 :'+self.name py20 = Python('python',25000,'6 months') print(py20)
打印对象 先走自己的str,如果没有,走父类的,如果除了object之外的所有父类都没有str
再回来,找自己的repr,如果自己没有,再找父类的
repr是str的备胎
和所有的字符串格式化以及直接打印这个对象相关
str(obj),repr(obj)
流畅的python - repr
print(str('123')) --> 123
print(repr('123')) ---> '123'
有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了
增强了用户的体验 在程序开发的过程中
如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,实际上是一种麻烦
如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示
__new__
构造方法,生产对象的时候用的 -- 单例模式
class Foo: def __new__(cls, *args, **kwargs): print('in new') # 先执行 obj = object.__new__(cls) print(obj) return obj def __init__(self): print('init',self) # 后执行 Foo()
实例化一个Foo的对象
先开辟一块儿空间,使用的是Foo这个类内部的__new__
如果我们的Foo类中是没有__new__方法的
就调用object类的__new__方法
class Foo(object): def __new__(cls, *args, **kwargs): # cls永远不能使self参数,因为self在之后才被创建 obj = object.__new__(cls) # self是在这里被创造出来的 print('new : ',obj) return obj def __init__(self): print('init',self) Foo()
在使用self之前,都还有一个生产self的过程
就是在内存中开辟一块属于这个对象的空间,并且在这个空间中存放一个类指针
以上就是__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('alex',84) print(a1) a2 = A('alex',83) print(a2) a3 = A('alex') print(a3) print(a1.age) -- 82 被a3传的值覆盖了 保证一个类无论 被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址
__del__
析构方法 在删除一个对象之前用的 -- 归还系统操作资源
因为python是解释型语言,先编译,后解释
所以一些文件中用不到的变量会自动被删除,释放内存空间
但自动删除要等解释器分析完全文件,效率不高,所以可以使用 del 方法 手动删除不需要的变量
import time class A: def __init__(self,name,age): self.name = name self.age = age def __del__(self): # 只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容 print('执行我啦') a = A('alex',84) print(a.name) print(a.age) # del a # 这个变量已经没了 time.sleep(1) 在所有的代码都执行完毕之后,所有的值都会被python解释器回收
python解释器清理内存的方式
1.我们主动删除 del obj
2.python解释器周期性删除
3.在程序结束之前 所有的内容都需要清空
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()
with 和 __enter__ , __exit__
class File: def __enter__(self): print('start') def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with File(): print('wahaha')
先运行 __enter__ , 再运行 with ,后运行 __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()
总是在程序的结尾调用 __exit__ 方法
文件操作相关
with open 文件操作原理
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: as后的f是__enter__方法的返回值 f.write('hello,world')
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 mypic: for obj in mypic.loaditer(): print(obj)
在一个函数的前后添加功能,利用使用装饰器函数中的内容
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)