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

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部分即为执行的内容

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值