首页 > 代码库 > python\面向对象高级
python\面向对象高级
一.__slots__
1.__slots__的概念:是一个变量,变量值可以是列表,元组,或者可迭代对象,也可以是一个字符串。
2.使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例是独立的)
3.为什么要用:节省内存,不会产生新的名称空间。
定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是每个实例定义一个字典;在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能用__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性,比如多继承。
5.应用场景:一个类产生N多个对象,产生对象的属性都是相同的,用__slots__来统一管理属性
class People: __slots__=["x","y","z"] p=People() print(People.__dict__) >> {‘__module__‘: ‘__main__‘, ‘__slots__‘: [‘x‘, ‘y‘, ‘z‘], ‘x‘: <member ‘x‘ of ‘People‘ objects>, ‘y‘: <member ‘y‘ of ‘People‘ objects>, ‘z‘: <member ‘z‘ of ‘People‘ objects>, ‘__doc__‘: None} p.x=1 p.y=5 p.z=4 print(p.x,p.y,p.z) >> 1 5 4 p.d=9 #报错 File "C:/python_fullstack_s4/day32/__slots__方法.py", line 14, in <module> p.d=9 AttributeError: ‘People‘ object has no attribute ‘d‘ class Foo: __slots__=[‘name‘,‘age‘] f1=Foo() f1.name=‘alex‘ f1.age=18 print(f1.__slots__) f2=Foo() f2.name=‘egon‘ f2.age=19 print(f2.__slots__) >> [‘name‘, ‘age‘] [‘name‘, ‘age‘] #f1与f2都没有属性字典了,统一归__slots__管,节省内存 print(f1.__dict__)#报错 >> Traceback (most recent call last): File "C:/python_fullstack_s4/day32/__slots__方法.py", line 23, in <module> print(f1.__dict__) AttributeError: ‘Foo‘ object has no attribute ‘__dict__‘
二.__iter__ __next__
可迭代对象是有方法__iter__()
迭代器是有方法__next__()
因而可以自己构建一个类, 使得它的对象, 既是一个可迭代对象, 也是一个迭代器
from collections import Iterable,Iterator#导入模块 检查是否hi可迭代对象或迭代器 class Foo: def __init__(self,start): self.start=start def __iter__(self): return self def __next__(self): if self.start>10:#设置数据限制,当self.start>10时,停止运行 raise StopIteration n=self.start self.start+=1 return n f=Foo(0) # print(isinstance(f,Iterable)) for i in f: print(i) >> 0 1 2 3 4 5 6 7 8 9 10
三.__doc__
__doc__是类的描述信息
该属性无法继承给子类
四.
__module__表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
class Bar(): pass b=Bar() print(b.__class__) print(b.__module__) >> <class ‘__main__.Bar‘> __main__
五.__del__
析构方法,当对象在内存中被释放时,自动触发执行
class Open: def __init__(self,filepath,mode="r",encode="utf8"): self.f=open(filepath,mode=mode,encoding=encode) def write(self): pass def __del__(self):#产生的对象被垃圾处理时 # 会触发__del__ print("--->del") self.f.close() f=Open("a.txt","w") del f#如果手动删除,直接触发,再执行别的程序
六.__enter__ __exit__
上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
用途:
- 使用with语句的目的是把代码块放在with中执行,with结束后,自动完成清理工作,无须手动干预
- 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制
class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) # return self def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) with Open(‘a.txt‘) as f: print(‘=====>执行代码块‘) >> 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 =====>执行代码块 with中代码块执行完毕时执行我啊
-
抛出异常
with语句中代码块出现异常,则with后的代码都无法执行
class Foo: def __enter__(self): print("enter") return 11111 def __exit__(self, exc_type, exc_val, exc_tb): print("exit") print("exc_type",exc_type)#异常类型 print("exc_val",exc_val)#异常值 print("exc_tb",exc_tb)#追溯信息 with Foo():#1.with加对象()就回触发enter的运行 print("1111")#2.打印 raise NameError()#只要抛出异常,子代码块就运行完毕 #触发exit的运行 print("******************")#不会运行 print("999999999999999999999999")#子代码运行结束后(无异常) #正常运行 >> Enter 1111 exit exc_type <class ‘NameError‘> exc_val exc_tb <traceback object at 0x02EE1DA0> Traceback (most recent call last): File "C:/python_fullstack_s4/day32/上下文管理协议.py", line 17, in <module> raise NameError()#只要抛出异常,子代码块就运行完毕 NameError
异常解决 如果__exit()返回值为True,那么异常就会被清空,就好像什么都没发生,with后的语句正常执行 class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) print(exc_type) print(exc_val) print(exc_tb) return True with Open(‘a.txt‘) as f: print(‘=====>执行代码块‘) raise AttributeError(‘***着火啦,救火啊***‘)#传给exc_val print(‘0‘*100) #------------------------------->会执行 >> 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 =====>执行代码块 with中代码块执行完毕时执行我啊 <class ‘AttributeError‘> ***着火啦,救火啊*** <traceback object at 0x02C51E68> 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
七.__call__
对象后面加括号,触发执行
构造方法的执行是由创建对象触发的,即对象=类名();
对于__call__方法的执行是由对象后加括号触发的,即对象()或者类()()
class People: def __init__(self,name): self.name=name def __call__(self, *args, **kwargs): print("call") p=People("karina") p()#实例也变成一个可调用对象 >> call
八.元类
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样
元类的实例为类,正如类的实例是对象(Foo是type的类,f1对象是Foo的一个实例)
Type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
产生类的方法
1. class Foo: def func(self): print("from func") f1=Foo() f1.func() >> from func
2. 格式 类名=type(class_name,class_bases(父类),class_dict({})) def func(self): print("from func") x=1 Foo=type("Foo",(object,),dict({})) print(Foo) print(type(Foo)) print(Foo.__dict__) >> <class ‘__main__.Foo‘> <class ‘type‘> {‘__module__‘: ‘__main__‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>, ‘__doc__‘: None}
新建对象的过程
首先, 类要生成对象, 类本身需要可调用
针对于基类, 类是基类的对象, 也就是说在基类中, 需要有一个__call__()函数, 而这个函数, 是在类的__init__之前执行的
在基类的__call__()方法中, 需要使用self.__new__(self)来创建一个空对象, 这个对象就是类
有了类之后就可以调用原有的方法__init__(), 这时在其中就是熟悉的生成对象了
最后再返回这个类就行了
class MyMetaclass(type): def __call__(self, *args, **kwargs): obj = self.__new__(self) self.__init__(obj, *args, **kwargs) # obj.name=‘egon‘ return obj class People(metaclass=MyMetaclass): def __init__(self, name): self.name = name whc = People(‘whc‘) print(whc.name)
python\面向对象高级