百科问答小站 logo
百科问答小站 font logo



你见过哪些令你瞠目结舌的 Python 代码技巧? 第1页

  

user avatar   sharetechlee 网友的相关建议: 
      

几行行代码节省90%内存占用,还有比这更“奇”的吗?

Python效率低!

Python占内存!

Python太差劲!

...

程序员必备宝藏库github.com/Jackpopc/CS-
欢迎添加vx:code_7steps和我进行技术交流!

​作为近年来最为火热的编程语言之一,Python受到的争议和推崇同样很多。

无论是否从事Python方向的开发,都已经习惯把问题当做客观因素推卸给Python。

“你这个项目为什么耗时那么长?”

“Python的原因。”

我想说,Python为很多开发者背太多锅了。

的确,对比于C/C++、Java这些基于编译的语言而言,Python在内存利用和执行效率方面的确没有可比性。但是,它也没有大多数描述的那么不堪。

或许,有很多同学会想,至于为了一点一点内存费这么大劲吗?

至于!

举个例子,外出消费的过程中,觉得每次花费5块、10块不起眼,无关痛痒,但是每次月底还花呗的时候才发现居然消费了几千。

开发也一样,也许1个实例之间只节省了50byte,但是,100000000个呢?那就会节省高达5G的内存!

本文就来逐步介绍Python在内存方面的优惠,让你通过一篇文章迅速从青铜变成王者!

文末有干货

字典

字典对于Python就如同一把双刃剑。

字典在Python中要远比在Java、C++中占据更高的地位。在Python中,字典以其易于创建、删除、修改、读取,使得它备受欢迎。

我看过很多周围同事和GitHub开源代码,字典在Python中的使用频率非常之高。

但是,很多人却忽略了,字典具有很明显的弊端--耗内存

甚至很多从事多年Python开发的程序员也没有意识到这个问题,或者寻求替代方案。

下面来看一个例子,

       >>> exm = {"x": 1, "y": 2, "z": 3} >>> print(sys.getsizeof(exm)) 240     

直接使用字典,占用内存240byte

很多开发者已经习惯了使用Python字典,或者对前面提到的240byte没有什么概念。

那么,下面用类的方式来存储数据。这种方式在很多开源的Java、C++代码中非常常见。

下面来用用类实现以下等同字典的结构,

       class Shape:     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z  exm = Shape(1, 2, 3)     

这样的话exm.x的功能等同于字典中的exm["x"],可以用于访问对应的数据。

下面来看一下它占的内存,

       >>> print(sys.getsizeof(exm) + sys.getsizeof(exm.__dict__)) 168     

通过实现类,1个实例可以比字典节省72byte的内存!

通过字典的方式是类方式内存占用的1.4倍。

由于在Python类中,会用__dict__存储类的属性值,因此,内存占据比重较大。这里168byte内存,其中56byte来自exm实例,112byte来自__dict__

namedtuple

Python中常用的数据结构除了字典,还有元组tuple。

元组虽然可以用于存储数据,而且,可以通过索引进行取值,来替代通过key进行取值,但是它不具有键值信息。我想很多使用字典的场景,都是因为喜欢Python字典中key-value键值对,使得取值更加方便。

其实Python内置的collections提供了namedtuple可以替代字典的功能。

       from collections import namedtuple  Shape = namedtuple('Shape', ['x', 'y', 'z'])  exm = Shape(1, 2, 3)     

这样,我们可以通过exm.x进行取值,下面来看一下它的内存占用情况。

       >>> print(sys.getsizeof(exm)) 72     

相比于类实现的方法,namedtuple节省了96byte,相对于字典,它更是节省了高达168byte

通过字典的方式是namedtuple内存占用的3.3倍。

__slots__

__slots__是在Python内存优化中用的相对较多的方式,它相对于前面介绍的类实现方式__slots__能够确定性的指明哪些类属性可以访问,同时不需要__dict__去存储类属性的值,所以,对比于单纯的类实现形式能够进一步优化内存。

       class Shape:   __slots__ = 'x', 'y', 'z'   def __init__(self, x, y, z):   self.x = x   self.y = y   self.z = z  exm = Shape(1, 2, 3)     

下面来看一下它的内存占用,

       >>> print(sys.getsizeof(exm)) 64     

相对于字典,它更是节省了高达176byte

通过字典的方式是namedtuple内存占用的3.8倍。

recordclass

前面介绍的方法都是通过Python内置的方法或模块实现的,现在再来介绍一种通过第三方包实现内存优化的方式。

recordclass包引入了recordclass.mutabletuple类型,该类型与元组tuple几乎相同,但它支持赋值。在此基础上,创建的子类几乎与namedtuples完全相同,但支持将新值分配给字段(无需创建新实例)。

       from recordclass import recordclass  Shape = recordclass('Shape', ('x', 'y', 'z'))  exm = Shape(1, 2, 3) print(exm.x)     

下面来看一下它的内存占用情况,

       >>> print(sys.getsizeof(exm)) 48     

相对于字典,它更是节省了高达192byte

通过字典的方式是namedtuple内存占用的5倍。

Dataclass

recordclass还提供了另外一种更加节省内存的解决方案。

在内存中使用与具有__slots__的类实例中相同的存储结构,但不参与循环垃圾回收机制。

       from recordclass import make_dataclass  Shape = make_dataclass('Shape', ('x', 'y', 'z'))  exm = Shape(1, 2, 3) print(exm.x)     

下面来看一下内存占用情况,

       >>> print(sys.getsizeof(exm)) 40     

相对于字典,它更是节省了高达200byte

通过字典的方式是namedtuple内存占用的6倍。

Cython

最后一种方式,采用Cython

Cython 是具有 C 数据类型的 Python,因此,参数和变量都可以声明为C 数据类型,在内存上能够进一步优化。

不过,采用Cython方式要比前面几种方式更为复杂一些。首先需要把核心逻辑写在.pyx文件中,然后需要进行编译成.so或者.pyd文件。最后,在另一个Python文件中通过import导入模块。

下面来看一下示例,

       # Example.pyx  cdef class Shape:  cdef public int x, y, z   def __init__(self, x, y, z):   self.x = x   self.y = y   self.z = z     

然后,写一下编译文件,

       # setup.py  from distutils.core import setup from Cython.Build import cythonize setup(     ext_modules = cythonize("cc.pyx") )     

在命令行下执行setup.py,编译文件,

       $ python setup.py build_ext --inplace     

在Windows下会生成一个Shape.pyd文件,在Linux和macOS下会生成Shape.so文件。这里只是介绍一下,对于使用无关紧要。

然后就是调用编译后的文件。

       import Shape exm = Shape(1, 2, 3) print(exm.x)     

下面来看一下它的内存占用情况,

       >>> print(sys.getsizeof(exm)) 32     

相对于字典,它更是节省了高达208byte

通过字典的方式是namedtuple内存占用的7.5倍。

不积跬步,无以至千里。

在编程开发中也是这样,我们总是会觉得208byte微乎其微,对于现在计算机的内存来说无关紧要。或许,在一些财大气粗的公司、部门,动辄就可以提供一个集群让开发者使用。但是,内存是由上限的,不可能无节制的使用。但是,积少成多,在一个大工程中,数据量较大的项目中,如果进行这样的优化,内存优化是非常可观的。

以本文为例,很多Python开发者都已经习惯使用字典这种数据结构,并且对于内存占用不以为然。然而,你会发现,通过使用Cython,一个实例的内存可以从240byte优化到32byte,内存占用减少比例高达86.7%




干货

最近,为了方便大家,我花费了半个月的时间把这几年来收集的各种技术干货整理到一起,其中内容包括但不限于Python、机器学习、深度学习、计算机视觉、推荐系统、Linux、工程化、Java,内容多达5T+,我把各个资源下载链接整理到一个文档内,目录如下:

所有干货送给大家,希望能够点赞支持一下!

pan.baidu.com/s/1eks7CU (提取码:0000)




  

相关话题

  突然意识自己曾经引以为豪的编程其实是一种工具,这是一种悲哀吗? 
  你在 GitHub 上看到过的最有意思的项目是什么? 
  最难调试修复的 bug 是怎样的? 
  如何系统学习机器学习? 
  为什么要学习别人的设计模式? 
  如何看待又一位深圳 24 岁程序员倒在工位上?是否程序员下班晚、加班多成了常态? 
  如何巧妙地向没有学过编程语言的同志们解释“空格也是字符”? 
  程序员IntelliJ IDEA都是正版吗? 
  C 语言float和double哪个算得快? 
  有了 IP 地址,为什么还要用 MAC 地址? 

前一个讨论
最厉害的计算机病毒厉害到什么程度?
下一个讨论
为什么中国小学数学教育要揪“除”和“除以”的区别?





© 2024-12-22 - tinynew.org. All Rights Reserved.
© 2024-12-22 - tinynew.org. 保留所有权利