1.__slots__
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典
class Foo:
__slots__='x'
f1=Foo()
f1.x=1
f1.y=2#报错
print(f1.__slots__) #f1不再有__dict__
class Bar:
__slots__=['x','y']
n=Bar()
n.x,n.y=1,2
n.z=3#报错
2.__next__和__iter__实现迭代器协议
迭代器协议模拟range(start,end)
# 迭代器协议模拟range(start,end)
class Foo:
def __init__(self,start,end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start >= self.end:
raise StopIteration
n = self.start
self.start += 1
return n
f = Foo(0,10)
print(list(f)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
迭代器协议实现斐波那契数列
# 斐波那契数列类
class Fib:
def __init__(self):
self.__a = 0
self.__b = 1
def __iter__(self):
return self
def __next__(self):
if self.__a > 100:
raise StopIteration
self.__a,self.__b = self.__b,self.__a+self.__b
return self.__a
f = Fib()
l = [i for i in f]
print(l) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
3.__module__和__class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
4.__del__析构方法
析构方法,当对象在内存中被释放时,自动触发执行。
此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
# __del__析构函数
import time
class Foo:
def __init__(self, path, mode="r", encode="utf8"):
self.f = open(path, mode=mode, encoding=encode)
def __getattr__(self, item):
return getattr(self.f, item)
def __del__(self):
print("------del------")
self.f.close()
f = Foo("a.txt", "w")
f.write("qqqqqqqqqqqqqqqqqqqqqqq
")
del f # 清除对象时会触发执行,------del------
# f.close()
print("********************")
time.sleep(5)
5.__enter__和__exit__
1.上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法.
2.__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
3.如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
# 上下文管理协议实现打开文件
class Foo:
def __init__(self,path, m="r", e = "utf-8"):
self.f = open(path, mode=m, encoding=e)
def __getattr__(self, item):
return getattr(self.f, item)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(exc_type, exc_val, exc_tb)
return 1
with Foo("a.txt", "w") as f: # 相当于拿到Foo.__enter__()的返回值赋值给f
print("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-")
raise NameError("name cuowu")
print("-"*50)
print("主代码还在继续执行")
# 执行结果
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
# <class 'NameError'> name cuowu <traceback object >
# 主代码还在继续执行
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
6.__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
#\_\_call__
class Foo:
def __call__(self, *args, **kwargs):
print("__call__ is running")
pass
f = Foo()
print(callable(Foo)) # True. 执行 __init__,类()是执行类下的__init__方法
print(callable(f)) # True
7.元类
元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。—— Tim Peters
创建类的另一种方式
# 利用type产生元类
SB = type("SB", (object,), {})
s = SB()
s.name = "zou"
print(type(s)) # <class '__main_ _.SB'>
print(s.__dict__) # {'name': 'zou'}
元类总结
#元类总结
class Mymeta(type):
def __init__(self,name,bases,dic):
print('===>Mymeta.__init__')
def __new__(cls, *args, **kwargs):
print('===>Mymeta.__new__')
return type.__new__(cls,*args,**kwargs)
def __call__(self, *args, **kwargs):
print('aaa')
obj=self.__new__(self)
self.__init__(self,*args,**kwargs)
return obj
class Foo(object,metaclass=Mymeta):
def __init__(self,name):
self.name=name
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
'''
需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__
而爹.__call__一般做两件事:
1.调用name.__new__方法并返回一个对象
2.进而调用name.__init__方法对儿子name进行初始化
'''
'''
class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
Foo=Mymeta('foo',(...),{...})
因此我们可以看到,只定义class就会有如下执行效果
===>Mymeta.__new__
===>Mymeta.__init__
实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
'''
'''
obj=Foo('egon')
的原理同上
'''
'''
总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
1.谁后面跟括号,就从谁的爹中找__call__方法执行
type->Mymeta->Foo->obj
Mymeta()触发type.__call__
Foo()触发Mymeta.__call__
obj()触发Foo.__call__
2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
'''
限制注释信息
# 3 自定义元类限制注释信息
from collections import Iterable,Iterator
class Mymeta(type):
def __init__(self, class_name, base=None, dict=None ):
# print(self)
# print(class_name)
# print(base)
# print(dict)
for key in dict:
if not callable(dict[key]):continue
if not dict[key].__doc__:
raise Exception("你还没写注释信息")
def __call__(self, *args, **kwargs):
print("from mytype",self,args,kwargs) # from mytype <class '__main__.Foo'> ('zou',) {}
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
class Foo(metaclass=Mymeta):
x = 1
def __init__(self,name):
"初始化信息"
self.name = name
def run(self):
"run function"
print("running")
f = Foo("zou") # from mytype <class '__main__.Foo'> ('zou',) {}
# print(Foo.__dict__)