Python-容易想不起来的东东
阅读目录:
1、import sys
2、__slots__
3、未实现和未实现异常
4、运算符重载中的反向方法
5、生成器交互:
6、引用计数
7、命名元组nametuple
8、待续。。。。。
1、import sys -----sys.exit(100) 退出状态码
2、__slots__
问题引出:都是字典惹的祸。
字典为了提升查找效率,必须用空间换时间。hash算法是散列算法,将数据散列到某个空间的不同位置,所以需要开辟一个足够的空间。
也就是空间换时间,一般来说一个对象,属性对一点,都存储在字典中便于查询,问题不大。但是如果数百万个对象,那么字典占得就有点大了
这个时候,如果需要,可以把属性字典__dict__省了。
Python提供了__solts__属性。
测试1:
总结:
-
-
- __slots__ 告诉解释器,实例的属性都叫什么,一般来说,既然要节约内存,最好还是使用元组比较好。
- 一旦类提供了__slots__,就阻止实例产生__dict__来保存实例的属性。
- 尝试为实例动态增加属性setattr 或者点的方式, 返回的都是AttributeError,说明实例不能动态增加属性了
- 当然只影响实例,类还是可以继续做自己的操作。
-
测试 2:继承, 不会继承
应用场景:使用需要构建在数百万以上对象,且内存容量较为紧张,实例的属性简单,固定且不用动态增加的场景。
经过测试,即便数百万的对象,也就几百兆,用了__slots__也就几十兆,除非必须,否则第一想法是扩容,而不是在这里纠结。
实在不行的情况下,再来考虑这些细节,当然写的时候,注意到也很好。
3、未实现和未实现异常
在库中,NotImplemented =None,但是不是 == is None
注意:继承走的是mro这条路,type,__class__ 与继承不是同一条路,type(type)= type
也就是说类的类型是type
4、运算符重载中的反向方法
测试 1:
测试2:
测试3:
举例测试:对上面的举例
解决 1+a a+1 问题:
参考代码:实现 a+1, 1 + a
1 ######### 方式 1 2 class A: 3 def __init__(self, x): 4 self.x = x 5 def __add__(self, other): 6 print('###### A add #########') 7 if isinstance(other, type(self)): 8 return self.x + other.x 9 else: 10 return self.x + other 11 def __iadd__(self, other): 12 print('###### iadd #########') 13 return type(self)(self.x + other.x) 14 def __radd__(self, other): 15 print('###### radd #########') 16 if isinstance(other, type(self)): 17 return self.x + other.x 18 else: 19 return self.x + other 20 21 a = A(4) 22 print(a + 1) 23 print(1 + a) 24 25 26 ########### 方式 2 减少程序的冗余 27 class A: 28 def __init__(self, x): 29 self.x = x 30 def __add__(self, other): 31 print('###### A add #########') 32 if hasattr(other, 'x'): 33 return self.x + other.x 34 else: 35 try: 36 x = int(other) 37 except: 38 x = 0 39 return self.x + x 40 def __iadd__(self, other): 41 print('###### iadd #########') 42 return type(self)(self.x + other.x) 43 def __radd__(self, other): 44 print('###### radd #########') 45 return self + other 46 47 a = A(4) 48 print(a + 1) 49 print(1 + a)
联想 路径重载:
1 from pathlib import Path 2 3 p = Path('a/b') 4 p = p / 'c' 5 print(p) 6 p = 'q' / p 7 print(p) 8 9 print('a' / 'd' / p) # 报错
sub的举例:
5、生成器交互:
send用法:
事实上不推荐使用这种方式,而是使用类封装的方式:如之前写过的 生成一批数据的功能类:
每次都可以通过传入的值,来改变输出结果。
1 import random 2 3 class RandomNum: 4 @classmethod 5 def nums(cls, patch, start, stop): 6 while True: 7 yield [ random.randint(start, stop) for _ in range(patch)] 8 9 g = RandomNum.nums(30,3,7) 10 for _ in range(4): 11 print(next(g))
7、引用计数
1 import sys 2 3 sys.getrefcount(x)
8、命名元组nametuple :https://www.cnblogs.com/JerryZao/p/9432949.html