抽象基类
- 什么是抽象类?
- 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化.
- 抽象类的作用
- 从一堆类中抽取相同的内容,内容包括数据属性和函数属性。我的个人理解就是抽象基类就是一个框架模型。
- 抽象基类的继承
- 继承了抽象基类必须重写指定的方法。
import abc
class F_file(metaclass=abc.ABCMeta):
all_type = 'file'
@abc.abstractmethod #定义抽象方法
def read(self):
pass
@abc.abstractmethod
def write(self):
pass
class TXT(F_file):
def read(self):
print('读txt文件')
def write(self):
print('写入到txt文件中')
a=TXT()
print(issubclass(TXT,F_file)) #True
print(isinstance(a,F_file)) #True
- 使用register方法注册。
import abc
class A(metaclass=abc.ABCMeta):
all_title='file'
@abc.abstractmethod
def read(self):
pass
@abc.abstractmethod
def write(self):
pass
class B(object):
pass
A.register(B)
print(issubclass(B,A)) #True
自定义一个类的案例
我们想自定义一种新类型的元组,对于传入的可迭代对象,我们只保留其中int类型且值大于0的元素。
例:
data = [12,-5,['tu',1],5,'8',1.1]
print(tuple(data))
#(12, -5, ['tu', 1], 5, '8', 1.1)
#新类型元组:
#new_tuple(data) =>(12,5)
思路:继承元组并重写方法
class new_tuple(tuple):
def __new__(cls, iterable):
f = (i for i in iterable if isinstance(i,int) and i > 0 )
return super().__new__(cls,f)
print(new_tuple(data))
上下文管理
-
同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器。
-
__enter__(self):进入上下文管理器自动调用的方法。
-
__exit__(self, exc_type, exc_value, exc_traceback):退出上下文管理器自动调用的方法
class Get_info():
def __init__(self,name):
self.name = name
def __enter__(self):
print('获取资源')
return self.name #将返回值作为as的对象
def __exit__(self,exc_type,exc_val,exc_tb):
print('错误类型:',exc_type)
print('错误值:',exc_val)
print('回溯错误:',exc_tb)
return True #返回值为True时抛出错误但不会中断程序
with Get_info('lh') as f:
print(f)
执行结果:
获取资源
lh
释放资源
错误类型: None
错误值: None
回溯错误: None
使用内置模块contextlib,@contextmanager让我们通过编写generator来简化上下文管理。
import contextlib
@contextlib.contextmanager
def show_info(name):
#__enter__方法
file_name = open(name,'r',encoding='utf-8')
#yield
try:
yield file_name
except Exception as err:
print(err)
#__exit__()方法
finally:
file_name.close()
with show_info('test.txt') as f:
print(f.readline())
抽象基类的应用
import abc
import math
# from functools import total_ordering
# @total_ordering
class Shape(metaclass=abc.ABCMeta):
@abc.abstractmethod
def area(self):
pass
def __lt__(self, other):
return self.area() < other.area()
def __eq__(self, other):
return self.area() == other.area()
class Cricle(Shape):
def __init__(self,x):
self.x = x
def area(self):
return self.x ** 2 * math.pi
class Square(Shape):
def __init__(self,l):
self.l = l
def area(self):
return self.l ** 2
class Rectange(Shape):
def __init__(self,x,y):
self.x = x
self.y = y
def area(self):
return self.x * self.y
cricle=Cricle(5)
square=Square(6)
rectange=Rectange(4,9)
print(cricle < rectange)
print(square == rectange)
多态的应用
实现一个统一的获取面积的函数
import math
class Cricle(object):
def __init__(self,x):
self.x = x
def get_area(self):
return self.x ** 2 * math.pi
class Rectange(object):
def __init__(self,x,y):
self.x = x
self.y = y
def get_area(self):
return self.x * self.y
class Square(object):
def __init__(self,x):
self.x = x
def get_area(self):
return self.x ** 2
cricle=Cricle(5)
rectange=Rectange(7,6)
square=Square(7)
shape_list=[cricle,rectange,square]
for i in shape_list:
print(i.get_area())
使用getattr方法实现
import math
class Cricle(object):
def __init__(self,x):
self.x = x
def get_area(self):
return self.x ** 2 * math.pi
class Rectange(object):
def __init__(self,x,y):
self.x = x
self.y = y
def get_Area(self):
return self.x * self.y
class Square(object):
def __init__(self,x):
self.x = x
def area(self):
return self.x ** 2
def get_all_area(object):
method_name = ['get_area','get_Area','area']
for name in method_name:
goal = getattr(object,name,None)
if goal:
return goal()
cricle=Cricle(5)
rectange=Rectange(7,6)
square=Square(7)
shape_list=[cricle,rectange,square]
area_list = list(map(get_all_area,shape_list))
print(area_list)
节约内存的实例
在游戏开发中,有一个玩家类Player,每有一个在线玩家,在服务器内则有一个player的实例,当在线的人数很多时,将产生大量实例(百万级)。
如何降低这些大量实例的内存开销?
-
由于Python中默认用一个字典来保存一个对象的实例属性,使得我们在运行时可以任意设置新属性。如果创建成千上万个这样的小类,Python就会浪费掉很多内存,所以python中引入了 __slot__属性。这个属性的两个作用:1、给类指定一个固定大小的空间存放属性;2、无法给该类创建的实例添加新的属性。
#首先创建两个对象使用__dict__来查看对象内的内容
class Player1(object):
pass
class Player2(object):
__slot__ = ()
pass
print(Player1.__dict__)
print(Player2.__dict__)
执行结果:
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Player1' objects>, '__weakref__': <attribute '__weakref__' of 'Player1' objects>, '__doc__': None}
{'__module__': '__main__', '__slots__': (), '__doc__': None}
显而易见,使用__slot__()后,对象中的属性都由__slot__ : ()取代了。这时你可能是会说,虽然属性看着确实少了,但是没有说服力,那确实,下面我们拿数据来证明。
这里我需要调用tracemalloc模块来对内存使用进行跟踪
import tracemalloic
class Player1(object):
def __init__(self,name,uid,attribute=1,skill=2):
self.name = name
self.uid = uid
self.attribute = attribute
self.skill = skill
class Player2(object):
__slots__ = ('name','uid','attribute','skill')
def __init__(self,name,uid,attribute=1,skill=2):
self.name = name
self.uid = uid
self.attribute = attribute
self.skill = skill
#内存跟踪
tracemalloc.start() #开始跟踪内存分配
player1 = [Player1('haha',1,) for i in range(100000)] #size=15.3 MiB
# player2=[Player2('haha',1) for i in range(100000)] #size=7055 KiB
snapshot = tracemalloc.take_snapshot() #快照,当前内存分配
top = snapshot.statistics('filename') #快照对象的统计 监控文件
for start in top:
print(start)