1.上下文管理器
2.模式方法
1.上下文管理器
1).python的上下文管理协议:包含__enter__() 、__exit__()
2)上下文管理器:支持"上下文管理的协议"的对象(同时支持__enter__()、__exit__())
3)with 语句操作上下文管理器对象
with object as o:
pass
♥ with后的object是上下文管理器的对象;o是__enter__()的返回值
举例:在执行with里的语句之前,先执行__enter__(),再执行with中的语句,最后执行__exit__()-------即上下文管理器
""" python上下文管理的协议:包含__enter__() 、__exit__() 上下文管理协议:支持"上下文管理的协议"的对象(同时支持__enter__()、__exit__()) with 后面跟的是上下文管理器的对象 """ # 自定义上下文管理器---包含__enter__()、__exit__() class MyClass(object): def __enter__(self): print("enter is running...") def __exit__(self, exc_type, exc_val, exc_tb): print("exit is running...") def main(): # 实例对象 obj = MyClass() with obj as o: print("with is running...") if __name__ == '__main__': main() """ enter is running... with is running... exit is running... """
4)常见的上下文管理器
open(file)
with open("上下文管理器.txt","w",encoding="utf8") as f: f.write("python")
为什么open能够被with操作?看看open()的返回值包含哪些属性:
f = open("上下文管理器.txt") # f就是一个上下文管理器 print(dir(f)) """ ... ,'__enter__', '__eq__', '__exit__', ... """
open()的返回值f是一个上下文管理器,所以可以被with操作。
当然,不是上下文管理器,是不能被with操作的!如下:
with 1 as o: pass """ with 1 as o: AttributeError: __enter__ """
5)如果一个对象不是上下文管理器,怎么变成上下文管理器
在继承的新的类中,添加__enter__() 、__exit__() 2个方法即可。
# 一个对象不是上下文管理器,怎么变成上下文管理器: 继承,在新的类中添加2个方法 class Base(object): pass class MyBase(Base): def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb): pass
2.魔术方法:
在python中方法名如果是__xxxx__()
的,那么就有特殊的功能,因此叫做“魔法”方法
1)__str__:
- 当使用print输出对象的时候,只要自己定义了
__str__(self)
方法,那么就会打印这个方法中return的数据 __str__
方法需要返回一个字符串,当做这个对象的描写
举例,不写__str__()方法(默认继承object的str方法,返回的是存储地址)
class MyClass(object): def __init__(self,name): self.name = name def main(): a = MyClass("zhangsan") print(a) if __name__ == '__main__': main() # <__main__.MyClass object at 0x000001B57D0BEC88>
重写__str__()
class MyClass(object): def __init__(self,name): self.name = name def __str__(self): print("这是对对象的描述...") return self.name def main(): a = MyClass("zhangsan") print(a) if __name__ == '__main__': main() """ 这是对对象的描述... zhangsan """
2).让自定义的类生成的对象(实例)能够使用运算符进行操作
首先来看下list的相加:
def main(): a = [1, 2, 3] b = [4, 5, 6] return a + b if __name__ == '__main__': print(main()) # [1, 2, 3, 4, 5, 6]
为什么list能够相加?因为list含有__add__属性
def main(): a = [1, 2, 3] b = [4, 5, 6] print(hasattr(a,"__add__")) # True return a + b if __name__ == '__main__': print(main())
1)对象没有__add__属性,进行相加:报错
class MyClass(object): pass def main(): a = MyClass() b = MyClass() return a + b if __name__ == '__main__': print(main()) # TypeError: unsupported operand type(s) for +: 'MyClass' and 'MyClass'
对象添加__add__属性
两个对象能不能相加,取决于该对象有没有__add__属性
class MyClass(object): def __init__(self, value): self.value = value def __add__(self, other): return self.value + other.value # self 是a对象,other是b对象 def main(): a = MyClass(11) b = MyClass(23) return a + b if __name__ == '__main__': print(main()) # 34
3)__del__:Python解释器释放实例对象,调用该方法------析构方法
当删除一个对象时,Python解释器也会默认调用一个方法,这个方法为__del__()方法。在Python中,对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)。Python的内存管理机制能够很好的胜任这份工作。也就是说,不管是手动调用del还是由Python自动回收都会触发__del__方法执行。
①创建多个对象的时候触发__del__方法,python解释器自动删除对象,释放内存
# python解释器删除不再用的对象 ,释放内存 class MyClass(object): def __init__(self): print("init is running...") def __new__(cls, *args, **kwargs): print("new is running...") instance = super().__new__(cls) return instance def __del__(self): print("del is running...") def main(): a = MyClass() b = MyClass() if __name__ == '__main__': main() print("main() is running...") """ new is running... init is running... new is running... init is running... del is running... del is running... main() is running... """
②del关键字手动删除
当使用del 把内存的所有应用删除,立刻调用__del__方法
class MyClass(object): def __init__(self): print("init is running...") def __new__(cls, *args, **kwargs):
#创建对象 分配内存 print("new is running...") instance = super().__new__(cls) return instance def __del__(self):
#销毁对象 print("del is running...") def main(): a = MyClass() b = MyClass() del a del b
__del__用其他应用场景:在对象被销毁前,进行一些其他操作。
4)多态 (面向对象的三大特征:封装、继承、多态)
类型动态
同样的方法,根据不同的对象,会有不同的行为结果。
# 多态 class MyClass(object): def music(self): print("myclsss music is running...") class AClass(MyClass): def music(self): print("Aclass music is running...") class BClass(MyClass): def music(self): print("Bclass music is running...") def func(obj): obj.music() # 只要这个对象有music方法,就会正常调用 if __name__ == '__main__': m = MyClass() a = AClass() b = BClass()
#上面三个对象都有music方法,都可以正常调用该方法 func(a) func(b) func(m) """ Aclass music is running... Bclass music is running... myclsss music is running... """
5)鸭子类型-----依赖的是方法()
①什么是鸭子类型?
②鸭子类型有什么用?
③ 理解:动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
④举例
un()
来访问不同 Animal
子类中的相同方法。但其实对于上面的 canrun()
函数来说,传入的参数并不一定需要是 Animal
类型的,只需要保证传入的对象有一个 run()
方法即可,如下面代码所示。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子----有run()方法class Animal(object): def run(self): print("animal is running...") class Cat(Animal): def run(self): print("cat is running...") class Dog(Animal): def run(self): print("dog is running...") class Person(object): def run(self): print("person is running...") def canrun(obj): # 只要obj含有run()方法,就是个鸭子类型 obj.run() if __name__ == '__main__': canrun(Animal()) canrun(Cat()) canrun(Person()) """ animal is running... cat is running... person is running... """
⑤怎么实现鸭子类型?
可以封装一个函数,函数中特殊的参数,对参数作特殊的说明:参数必须是含有什么方法的对象,就是一个鸭子类型。----只要这个参数含有想要的特殊方法,就是鸭子类型。
5)类方法的使用
类方法时为了创建对象!!!
# 类方法创建对象 class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name @classmethod def teacher(cls,full_name): # 类方法,扩展一个创建对象的方式 first_name, last_name = map(str, full_name.split(" ")) obj = cls(first_name, last_name) return obj if __name__ == '__main__': # 普通方式创建对象 zhangsan = Person("san", "zhang") print(zhangsan.first_name) # 类方法创建对象 teacher = Person.teacher("si li") print(teacher.first_name) print(teacher.last_name)
6) __getitem__: ----有__getitem__方法的对象才能用[]操作
①作用:凡是在类中定义了这个__getitem__ 方法,那么它的实例对象obj,可以像这样
obj[key] 取值,当实例对象做obj[key] 运算时,会调用类中的方法__getitem__
②使用:一般如果想使用索引访问元素时,就可以在类中定义这个方法(__getitem__(self, key) )
③举例
class MyClass(object): def __init__(self): self.items = [1, 2, 3] def __getitem__(self, item): return self.items[item] if __name__ == '__main__': myclass = MyClass() print(myclass[0]) # 1 print(myclass[1]) # 2 print(hasattr(myclass, "__getitem__")) # True
print(hasattr(list, "__getitem__")) # True print(hasattr(tuple, "__getitem__")) # True
7)__getattr__: 执行调用对象的属性,而对象无此属性时,会调用__getattr__方法。
# __getattr__方法 class Myclass(object): def __init__(self,name): self.name = name def __getattr__(self, item): return 1 if __name__ == '__main__': A = Myclass("zhangsan") print(A.value) # 1 对象A并没有value属性,但是输出的是__getattr__的返回值
不重写__getattr__方法,对象没有X属性而调用X属性时,会报系统内置的属性错误信息。
class Myclass(object): def __init__(self,name): self.name = name # def __getattr__(self, item): # return 1 if __name__ == '__main__': A = Myclass("zhangsan") print(A.value) # AttributeError: 'Myclass' object has no attribute 'value'
也可以自定义报错信息,重写__getattr__方法。如下:
__getattr__内置方法,没有属性时的异常抛出的大概设计思路。
#自定义获取对象属性的报错信息 class MyAttributionError(Exception): def __init__(self,msg = "属性不存在"): super().__init__(self) self.msg = msg def __str__(self): return self.msg class Myclass(object): def __init__(self,name): self.name = name def __getattr__(self, item): raise MyAttributionError if __name__ == '__main__': A = Myclass("zhangsan") print(A.value) """ raise MyAttributionError __main__.MyAttributionError: 属性不存在 """