Python 指南程序员Python语言与信息数据获取和机器学习

说一说那些我也不太懂的 Python 对象优化

2017-08-25  本文已影响96人  谢烟客

我们通常做性能优化的思路是:先优化业务逻辑,再优化架构,最后再优化语言的数据结构等。所以如果想将性能优化到极致,往往就涉及到了 Python 语言的原子数据结构的分析(通常是不建议大家在没必要做性能优化的时候过分的进行优化)。

谈一谈 Python 的对象空间优化

假如定义一个类这个类会被创建很多实例对象,那么我们为了节省内存,就需要控制单个对象所占用内存大小

例如:订单这个类,我们如何对其进行优化呢?
class Order(object):
    def __init__(self, id, price):
        self.id = id
        self.price = price

我们都知道 Python 对象,功能丰富,对开发者非常的友好,那么 Python 对象就肯定包含了很多的内容,为了节省内存空间,我们就要把一些占用空间大,且不是我们必用的功能替换掉或去除,这里我们首先选中的就是:__dict__

优化的具体实现:
class Order2(object):
    __slots__ = ['id', 'price']
    def __init__(self, id, price):
        self.id = id
        self.price = price
我们对比一下优化前后的对象区别
#! /usr/bin/env python
# -*- coding: utf-8 -*-

class Order(object):
    def __init__(self, id, price):
        self.id = id
        self.price = price

class Order2(object):
    __slots__ = ['id', 'price']
    def __init__(self, id, price):
        self.id = id
        self.price = price

o1 = Order(1, 1.2)
o2 = Order2(1, 1.2)

print(set(dir(o1)) - set(dir(o2)))
# 打印结果:set(['__dict__', '__weakref__'])

从打印结果可以看出,优化后的对象确实比优化前的对象少了 __dict__

那么 __dict__ 有什么作用,我们为什么优化对象内存空间就要去除它呢?

我们先看一下 __dict__ 的值是什么?

#! /usr/bin/env python
# -*- coding: utf-8 -*-

class Order(object):
    def __init__(self, id, price):
        self.id = id
        self.price = price

o1 = Order(1, 1.2)

print(o1.__dict__)
# 打印结果:{'price': 1.2, 'id': 1}

从打印结果可以看出:__dict__ 中存储的为当前对象所有属性的 KV,其实它的实际作用为促使对象属性具备动态的扩展能力,也就是说在对象创建之后可以为不存在的属性赋值,所以 __dict__ 就是我们要去除掉的功能:即占用空间大,又不常调用。

看示例:
#! /usr/bin/env python
# -*- coding: utf-8 -*-

class Order(object):
    def __init__(self, id, price):
        self.id = id
        self.price = price

o1 = Order(1, 1.2)
o1.title = 'orange'
print(o1.__dict__)
# 打印结果:{'price': 1.2, 'id': 1, 'title': 'orange'}

# 优化后
class Order2(object):
    __slots__ = ['id', 'price']
    def __init__(self, id, price):
        self.id = id
        self.price = price

o2 = Order2(1,1.2)
o2.title = 'apple'  # 此处报错
print(o2.__slots__)

通过上面示例可以看出,在优化前 Order 的实例是可以进行属性的动态扩展的,而优化后就不可以了,确保已经达到了去除 __dict__ 的目的。

结尾处我们讨论一下:去除 __dict__ 确实优化了存储空间,但是真的达到了优化性能的目的了吗?

答案是不一定的,我们使用 __slots__ 替代了 __dict__ 进行了对象属性的初始化定义,虽然从存储角度内存空间占用下降了很多,但是观察 2 者的数据结构就会发现 __slots__ 是一个 list,在内存空间优化后我们在使用对象属性的时候,检索的时间复杂度变成了 O(n),也就是说当一个对象有很多属性的时候,性能会下降很大,而优化前 __dict__ 的数据结构是一个字典,对象属性检索的时间复杂度为 O(1),并不受属性个数大小的影响。可见这还是一个典型的空间换时间的经典案例。

最后总结一下:如果你的类包含的属性并不是很多,且有必要做内存空间优化的时候,可以考虑本篇使用 __slots__ 预定义属性的方式进行类的定义。


qq群.jpg
上一篇 下一篇

猜你喜欢

热点阅读