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

1.如何派生内置不可变类型并修改其实例化行为

#我们想自定义一种新类型的元组,对于传入的可迭代对象,我们只保留其中int类型且值大于0的元素,例如:
IntTuple([2,-2,'jr',['x','y'],4]) => (2,4)
class TntTuple(tuple):
    def __new__(cls,iterable):
        # for i in iterable:
        #     if isinstance(i,int) and i>0:
        #         super().__init__(i)
        f=[i for i in iterable if isinstance(i,int) and i>0]
        print(f)
        return super().__new__(cls,f)

int_t=TntTuple([2,-2,'lz',['x','y'],4])
print(int_t)    #2,4

在这里插入图片描述
如何继承内置tuple 实现IntTuple

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

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

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

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

import sys     #导入库
import tracemalloc

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():
    __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','xiaoming')
p2=Player2('0002','xiaoming')

print(dir(p1))  #查看类属性
print(dir(p2))
print(len(dir(p1)),len(dir(p2)))
#__wealref__  弱引用
#__dict__  动态绑定属性
print(set(dir(p1))-set(dir(p2)))    #相减的集合
print(set(dir(p2))-set(dir(p1)))

# p1.x=6
# # p1.__dict__['y']=7
# # print(p1.__dict__)

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

tracemalloc.start()
#p1=[Player1(1,2,3) for _ in range(100000)]
p2=[Player2(1,2,3) for _ in range(100000)]
end = tracemalloc.take_snapshot()
top = end.statistics('filename')
# top = end.statistics('xiaoming')

for stat in top[:10]:
    print(stat)

在这里插入图片描述

3.Python中的with语句

上下文管理器协议

contextlib简化上下文管理器

import contextlib

@contextlib.contextmanager
def file_open(filename):
    print("file open")
    yield {}
    print("file end")

with file_open('lib1.py') as f:
    print("file operation")

4.如何创建可管理的对象属性

在面向对象编程中,我们把方法看做对象的接口。直接访问对象的属性可能是不安全的,或设计上不够灵活,但是使用调用方法在形式上不如访问属性简洁。

# A.get_key()  #访问器
# A.set_key()  #设置器


class A():
    def __init__(self,age):
        self.age=age
    def get_age(self):
        return self.age

    def set_age(self,age):
        if not isinstance(age,int):
            raise  TypeError('Type Error')
        self.age=age
    R=property(get_age,set_age)
    @property
    def S(self):
        return self.age
    @S.setter
    def S(self,age):
        if not isinstance(age,int):
            raise TypeError('Type Error')
        self.age=age
a=A(20)
a.S=25
print(a.S)    #打印出 25

5.如何让类支持比较操作

有时我们希望自定义类的实例间可以使用,<,<=,>,>=,==,!=符号进行比较,我们自定义比较的行业,例如,有一个矩形的类,比较两个矩形的实例时,比较的是他们的面积

from functools import total_ordering
import math
import abc

@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 Rect(Shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

    # def __lt__(self, other):
    #     return self.area() < other.area()
    #
    # def __eq__(self, other):
    #     return self.area() == other.area()

# rect1 = Rect(1, 2)
# rect2 = Rect(1, 2)
# print(Rect(1, 2) > Rect(1, 2))    # rect2 < rect1

class Cirle(Shape):
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2*math.pi

    # def __lt__(self, other):
    #     return self.area() < other.area()
    #
    # def __eq__(self, other):
    #     return self.area() == other.area()


c = Cirle(8)
rect = Rect(1, 2)

False

6.如何在环状数据结构中管理内存

双向循环链表

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

    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(1000)
head = None

import time
for _ in range(1000):
    time.sleep(1)
    print('run...')
input('wait...')

通过实例方法名字的字符串调用方法
我们有三个图形类

Circle,Triangle,Rectangle

他们都有一个获取图形面积的方法,但是方法名字不同,我们可以实现一个统一的获取面积的函数,使用每种方法名进行尝试,调用相应类的接口

class Triangle:
    def __init__(self,a,b,c):
        self.a,self.b,self.c = a,b,c
    
    def get_area(self):
        a,b,c = self.a,self.b,self.c
        p = (a+b+c)/2
        return (p * (p-a)*(p-b)*(p-c)) ** 0.5

class Rectangle:
    def __init__(self,a,b):
        self.a,self.b = a,b
    
    def getArea(self):
        return self.a * self.b
        
class Circle:
    def __init__(self,r):
        self.r = r
    
    def area(self):
        return self.r ** 2 * 3.14159
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值