类与对象深度问题与解决技巧

流程图

流程图

派生不可变类型

我们想自定义一种新类型的元组,对于传入的可迭代对象,我们只保留其中int类型且值大于0的元素,例如:
IntTuple([2,-2,‘jr’,[‘x’,‘y’],4]) => (2,4)
如何继承内置tuple 实现IntTuple
以IntTuple继承tuple类创建数值型元组为例。
解决这个问题,必须要清楚的一个问题就是:self对象到底是谁创建的?为了清楚这个问题,我们可以在__init__方法中打印一下self,发现,这个元组已经在传入的时候就被创建了,那么就说明我们一定要在__init__方法前改变传入的参数。

class IntTuple(tuple):
    '''实现数值型的元组'''
    def __new__(cls, other):
        f = [i for i in other if isinstance(i,int) and i >= 0]
        return super().__new__(cls, f)

b = IntTuple([2,3,4,-1,'s','r',[2,3,4],(2,3)])
print(b)

如何节省内存创建大量实例

在游戏中,定义了玩家类player,每有一个在线玩家,在服务器内则有一个player的实例,当在线人数很多时,将产生大量实例(百万级)

如何降低这些大量实例的内存开销?

解决方案:
定义类的__slots__属性,声明实例有哪些属性(关闭动态绑定)

动态绑定

__dict__方法实现。
创建一个类
class Demo(object):
def init(self,x):
self.x = x
d1 = Demo(1)
d1.dict[‘y’] = 2

代码

import tracemalloc
import sys

class Player1(object):
    def __init__(self, uid, name, gender, age):
        self.uid = uid
        self.name = name
        self.gender = gender
        self.age = age

class Player2(object):
    __slots__=['uid', 'name', 'gender', 'age']
    # 这里可以用[]、{}、()

    def __init__(self, uid, name, gender, age):
        self.uid = uid
        self.name = name
        self.gender = gender
        self.age = age

player1 = Player1(1,'qinghuan','female',18)
player2 = Player2(2,'qinghuan','female',18)

'''拥有__dict__魔法方法的时候可以实现动态添加属性,当没有这个方法时,
不能够实现动态添加属性,也就是说,__slots__声明了这个类的属性,并且不能添加'''
player1.x = 6
player1.__dict__['y'] = 7
print(player1.__dict__)


print(player2.__dir__())
player2.x = 8
print(player2.__dict__)

如何验证节省了内存?

‘’‘使用__slots__声明变量的作用是出现大量用户时,可以节省内存空间’’’

利用sys模块

print(sys.getsizeof(player1.__dict__))
print(sys.getsizeof(player1.name))
print(sys.getsizeof(player1.uid))

利用tracemalloc

tracemalloc.start()
# p1 = [Player1(1, 2, 3, 4) for _ in range(10000)]      # 1726 KiB
p2 = [Player2(1, 2, 3, 4) for _ in range(10000)]        # 789 KiB
end = tracemalloc.take_snapshot()

top = end.statistics('filename')
for stat in top[:10]:
    print(stat)

上下文管理器

直接操作文件

try:
    f = open('test.txt','w')
    f.write("qinghuan")
except Exception as e:
    print(e)
finally:
    f.close()

使用上下文管理器

# 使用上下文管理器
with open('test.txt','w') as f:
    f.write('qinghuan test')

类和函数也能够使用上下文管理器器吗?

如果我们在使用的过程当中,想要类和函数实现用with语句调用应该怎么做?

使用with打开类

如果类要实现用with进行操作,必须要在类中包括__enter__方法和__exit__方法,最后再用with语句打开。

class Content(object):
    def __init__(self):
        print("我在初始化")

    def __enter__(self):
        print("进入类了")
        return self

    def demo(self):
        print("清欢")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type,'-')
        print(exc_val,'-')
        print(exc_tb,'-')
        print("退出")

with Content() as content:
    content.dems()

使用with打开函数

如果要用with语句打开函数生成器不能够少,如果没有生成器,那么将不能实现此功能。当然,还需要导入一个上下文管理器的模块(contextlib)。

import contextlib

@contextlib.contextmanager
# def Sample():
#     print("进入文件")
#     yield
#     print("文件操作")
#     print("结束")
def sample():
    print("进入文件")
    yield
    print("文件操作")
    print("结束")

with sample() as f:
    pass

创建可管理的对象属性

A.get_key() # 访问器
A.set_key() # 设置器
这样去调用比较麻烦,我们要怎么样才可以实现以下方式去自动调用访问器和设置器呢?
A.key
A.key = ‘jr’
形式上 属性访问
实际上 调用方法

class Demo(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def get_info(self):
        self.info = "我叫{},今年{}".format(self.name,self.age)
        return self.info

    def set_info(self,name):
        self.name = name

    f = property(get_info,set_info)

player = Demo("qinghuan",18)
print(player.get_info())
player.f = 'qinghuan2'
print(player.f)

class Demo(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    @property
    def get_info(self):
        self.info = "我叫{},今年{}".format(self.name,self.age)
        return self.info
    @get_info.setter
    def get_info(self,name):
        self.name = name

a = Demo('qinghuan',18)
print(a.get_info)
a.get_info = "qinghuan2"
print(a.get_info)

类的比较操作

假设这里有一个计算面积的类Rect,并且有两个实例化的对象r1,r2,要怎么样才能实现判断r1>r2输出布尔值呢?

类的比较

from functools import total_ordering
import math

@total_ordering
class Rect1(object):
    def __init__(self,length,width):
        self.length = length
        self.width = width

    def area(self):
        return self.length*self.width

    def __le__(self, other):    #实现了>=,<=
        return self.area()<other.area()

    def __eq__(self, other): # 实现了==
        return self.area() == other.area()
    #没有实现 >,<(lt,gt),是否需要每一个写一遍?不需要
r1 = Rect1(1,2)
r2 = Rect1(3,4)

class Cycle(object):
    def __init__(self,r):
        self.r = r

    def area(self):
        return math.pi*self.r**2
r3 = Cycle(1.5)
#如何实现 print(r1>r2)
print(r1<r2)
print(r2>r3)

利用抽象基类简化代码

from functools import total_ordering
import math
import abc

@total_ordering
class Square(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def area(self):
        pass

    def __le__(self, other):    #实现了>=,<=
        return self.area()<other.area()

    def __eq__(self, other): # 实现了==
        return self.area() == other.area()
    #没有实现 >,<(lt,gt),是否需要每一个写一遍?不需要

class Rect1(Square):
    def __init__(self,length,width):
        self.length = length
        self.width = width

    def area(self):
        return self.length*self.width

r1 = Rect1(1,2)
r2 = Rect1(3,4)

class Cycle(Square):
    def __init__(self,r):
        self.r = r

    def area(self):
        return math.pi*self.r**2
r3 = Cycle(1.5)
#如何实现 print(r1>r2)
print(r1<r2)
print(r2>r3)

在环状结构中管理内存

弱引用

弱引用没有占用引用计数。

import weakref
class Demo(object):
    def __init__(self):
        print("初始化")

    def operation(self):
        print("test")

    def __del__(self):
        print("释放方法")

a = Demo()
b = weakref.ref(a)
c = b
print(c is a)
print(b is a)
del c
del a
print("hahah")

代码

代码来源:如何在环状数据结构中管理内存

import weakref
class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

    def add_right(self, node):
        self.right = node
        # node.left = self
        node.left = weakref.ref(self)

    def __str__(self):
        return 'Node:<%s>' % self.data

    def __del__(self):
        print('in __del__: delete %s' % self)


def create_linklist(n):
    head = current = Node(1)
    for i in range(2, n + 1):
        node = Node(i)
        current.add_right(node)
        current = node
    return head


head = create_linklist(100)
head = None

import time
for _ in range(100):
    time.sleep(1)
    print('run...')
input('wait...')
发布了8 篇原创文章 · 获赞 9 · 访问量 77

猜你喜欢

转载自blog.csdn.net/weixin_45814193/article/details/103746373