1.如何派生内置不可变类型并修改其实例化行为
比如我们想定义一个IntTuple类,表示接受参数后,只取其中int类型,且大于0的,然后存为tuple类型
首先我们想到继承父类Tuple,然后修改一下:
class IntTuple(tuple):
def __init__(self,iterable):
for i in iterable:
if isinstance(i,int) and i>0:
super().__init__(i)
t = IntTuple([1,-2,[1,2],'abc'])
而当我们这样运行时,却会发现报错了,报错显示为TypeError: object.__init__() takes exactly one argument (the instance to initialize),
class IntTuple(tuple):
def __init__(self,iterable):
print(self)
t = IntTuple([1,-2,[1,2],'abc'])
此时我们将上述循环删除,直接打印,会发现此时,直接输出的self就是(1,-2,[1,2],‘abc’)
此时其实我们应该使用__new__方法,我们可以这样理解他:__init__()负责将类实例化,__new__()负责制造这样的一个实例对象。
然后我们将代码改为:
class IntTuple(tuple):
def __new__(cls,*args, **kwargs):
f = (i for i in iterable if isinstance(i, int) and i > 0)
return super().__new__(cls, f)
t = IntTuple([1,-2,[1,2],'abc'])
print(t)
此时我们再运行,即可得到我们需要的。
2.如何为创建大量实例节省内存
在实例情况多的情况下我们如何降低这些大量实例的内存开销?
我们先定义两个类
class Player1(object):
def __init__(self, uid, name, status=0, level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
class Player2(object):
__slots__ = ('uid', 'name', 'status', 'level')
def __init__(self, uid, name, status=0, level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
p1 = Player1('0001', 'dog')
p2 = Player2('0002', 'cat')
__slots__来修饰属性的话可以减少其内存开销,那么他具体是怎么实现的呢。
我们分别用dir()查看p1,p2的内部属性,发现相差的有__dict__
__dict__指的是动态绑定属性,即
p1.x = 3
p2.y = 4
执行上述两条操作的话,第一条是可以执行的,因为类Player1无__slots__,可以进行这些动态绑定属性的操作,而第二条不行,类Player2只能修改uid,name,status,level这四个属性。
而想要查询内存使用情况的话,我们可以导入sys库,使用其中的getsizeof函数,
import sys
print(sys.getsizeof(p1.__dict__))
即可
3.Python中的with语句
我们在用python执行文件时应该都写过with open(‘xxx.txt’, ‘r’) as f:这种语句,这种带with的open语句自带关闭就不需要我们再自行 f.close()去关闭,那么with 语句能不能对类这些进行操作呢?
class Sample(object):
def text(self):
print('111')
with Sample() as s:
s.text()
当我们这样执行时,会报错,提示我们缺少__enter__,而我们加上__enter__后又提示了我们缺少__exit__,当我们再把__exit__后,诶,就发现ok了。
class Sample(object):
# 获取资源
def __enter__(self):
print('start')
return self
def text(self):
print('111')
# 释放资源
def __exit__(self, exc_type, exc_val, exc_tb):
# 异常类
print(exc_type)
# 异常值
print(exc_val)
# 追踪信息
print(exc_tb)
print('end')
with Sample() as s:
s.text()
讲到这就得在提到python中的上下文管理器
contextlib简化上下文管理器
import contextlib
@contextlib.contextmanager
def file_open(filename):
# xxx __enter__ 函数
print('file open')
yield {}
# __exit__ 函数
print('file close')
with file_open('demo.txt') as f:
print('file operation')
在导入contextlib库后使用装饰器@contextlib.contextmanager
在yield{}上面的部分就相当于上个例子中的__enter__函数
而在yield{}下面的部分就相当于上个例子中的__exit__函数
在with部分即为执行的内容