50个编写出色的Python程序的实用技巧 (编写cxmyd)
If you're new to Python or looking to enhance your skills, this comprehensive guide offers 50 valuable tips to improve your coding practices and write efficient, maintainable Python programs. From understanding core concepts to using advanced libraries, these recommendations will help you become a proficient Python programmer.
1. Programming Fundamentals
1.1 Understand Pythonic Concepts
Familiarize yourself with the principles outlined in the "Zen of Python" for a grasp of Python's core philosophy.
1.2 Write Pythonic Code
- Avoid non-Pythonic practices: don't useall caps or confusing variable names.
- Study Python's features and libraries; learn from well-established Pythonic codebases.
1.3 Understand Differences between Python and C
Recognize the key distinctions in syntax and semantics, such as indentation, braces, quotes, ternary operator, and exception handling.
1.4 Add Meaningful Comments
Document your code for clarity and understanding, explaining the purpose and functionality of specific sections.
1.5 Use Whitespace Wisely
Break up code with blank lines to enhance readability and organization.
1.6 Design Effective Functions
- Keep functions concise and avoid excessive nesting.
- Ensure proper and consistent function naming.
- Consider backwards compatibility when designing function parameters.
- Limit each function to a single purpose and maintain granularity.
1.7 Centralize Constants
Place constants in a separate file with uppercase names for easy identification.
2. Programming Idioms
2.1 Utilize Assert Statements
Use assert statements to detect errors, keeping in mind that they can impact performance.
2.2 Exchange Values Efficiently
Swap variable values directly (e.g., a, b = b, a) instead of using temporary variables.
2.3 Leverage Lazy Evaluation
Avoid unnecessary calculations by understanding the concept of lazy evaluation.
2.4 Understand Enum Alternatives
Use alternative ways to implement enumerations, as Python's enum feature is only available in newer versions.
2.5 Be Wary of eval() Security Issues
Exercise caution when using the eval() function to avoid potential security vulnerabilities.
2.6 Utilize enumerate() for Iterables
Simultaneously obtain the index and value of items in an iterable using enumerate().
2.7 Distinguish Between == and is
Understand the nuances of comparison operators == (equality) and is (identity), especially when comparing immutable types.
2.8 Favor Unicode
Use Unicode for handling text to avoid encoding issues, especially in Python 3.
2.9 Structure Packages Effectively
Organize modules into hierarchical packages for better code management.
3. Advanced Usage
3.1 Import Modules Responsibly
Use from...import sparingly to avoid polluting the namespace; prefer absolute imports.
3.2 Simplify Loops with Else Clauses
Emphasize loops clearly by using else clauses, particularly in exception handling.
3.3 Understand Exception Handling
- Minimize code inside try blocks.
- Use specific exception types instead of broad catch-all statements.
- Handle exceptions at the appropriate levels.
- Provide informative and standardized exception messages.
3.4 Avoid Traps in Finally Blocks
Be aware of potential issues that can arise within finally blocks.
3.5 Master None
Correctly determine whether an object is null, understanding the significance of None.
3.6 Use Consistent Container Initialization
Use the same syntax for initializing lists, sets, and dictionaries, such as [list], {set}, and (tuple).
3.7 Understand Parameter Passing
Functions pass references to objects, not values or copies.
3.8 Be Wary of Default Arguments
Handle default arguments carefully, especially when they are mutable objects.
3.9 Use Args and Kwargs Sparingly
- Avoid excessive use due to decreased readability and function signature clarity.
- Refactor functions with many arguments to improve maintainability.
3.10 Distinguish Between Static Methods and Class Methods
Understand the appropriate scenarios for using static methods and class methods.
4. Library Usage
4.1 Master String Manipulation Basics
Become proficient in using Python's string manipulation capabilities.
4.2 Choose sort() or sorted() Wisely
- Sort lists in-place with sort().
- Use sorted() to sort iterables without modifying the original.
4.3 Leverage ConfigParse
Effectively parse configuration files.
4.4 Utilize argparse for Command-Line Arguments
Handle command-line arguments with ease.
4.5 Learn Regular Expression Basics
Understand regular expressions for powerful pattern matching and text processing.
Conclusion
By following these 50 practical tips, you can significantly enhance your Python programming skills, write more efficient and robust code, and become a proficient Python developer. Remember to practice consistently, seek feedback, and keep exploring the vast Python ecosystem to grow your capabilities.
如何编写高质量的python程序
代码规范首先阅读下面的两份规范,并深入理解。 Python社区官方建议采用的Python编码风格:PEP8 中文版Google SoC 建议的 Python 编码风格:Google Python Style Guide 中文版写出规范的代码是写出高质量代码的第一步,并且有助于培养仔细的习惯。 为了培养规范写代码的习惯,可以安装flake8这个工具,它不仅可以检查代码风格是否符合官方建议(PEP8),而且还能找出潜在的隐患(用Pyflakes做语法分析),更逆天的是还能检测到你有些函数写的太复杂(代码圈复杂度)了,更更逆天的是可以设置git commit之前必须通过这些检查。 当然具体操作需要根据自己的项目进行一些定制,比如可以忽略E501,W293。 空白项目模版好的开始是成功的一半,写python代码就从pyempty开始吧。 在github上看一下那些经典的项目,,flask, pep8,他们的项目目录都很规范,综合借鉴了一些项目的特点,我写了这个pyempty项目。 这里写你项目的简介,quick start等信息,虽然distutils要求这个文件没有后缀名,但github上如果后缀是的话可以直接转换成html显示。 该文件存放程序各版本的变更信息,也有一定的格式,参考的 这里存放你项目使用的协议,不要编写自己的协议。 如果你的项目需要依赖其它的python第三方库,在这里写出来,可能pip install的时候能自动帮你安装 安装脚本,后面详细介绍 里面存放你的项目文档,如概要设计,详细设计,维护文档,pydoc自动生成的文档等,强烈推荐大家使用MarkDown格式编写文档 这个目录里存放项目模块的主要代码,尽量不要把模块目录直接放到根目录,模块代码目录可以在里指定的 这个目录存放所有单元测试,性能测试脚本,单元测试的文件确保以test_做前缀,这样distutils会自动打包这些文件,并且用python -m unittest discover -s ./ -p test_* -v 可以直接执行这些测试单元测试Martin Fowler:在你不知道如何测试代码之前,就不该编写程序。 而一旦你完成了程序,测试代码也应该完成。 除非测试成功,你不能认为你编写出了可以工作的程序。 我们有很多理由不写单元测试,归根结底是懒,虽然代码大全上说:大部分研究都发现,检测比测试的成本更小。 NASA软件工程实验室的一项研究发现,阅读代码每小时能够检测出来的缺陷要比测试高出80%左右(Basili and Selby 1987)。 后来,IBM的一项研究又发现,检查发现的一个错误只需要3.5个工作时,而测试则需要花费15-25个工作时(Kaplan 1995)。 但是单元测试还是让别人相信你的代码有很高质量的最有力证据。 好了,请详细阅读:深入python3.0: 单元测试-2.x也适用Unit testing framework 不完整中文版文档敏捷开发不是提倡什么文档也不写,没有文档就没有传承和积累,轮岗或新人接手任务就会遇到很大的麻烦,所以我决定每个项目最少要写以下文档 概要设计文档,不同于文件,该文档应该写于项目开发之前,把项目有哪些功能,大概分几个模块等项目整体概述信息写一下。 详细设计文档,不用太详细,至少把项目依赖哪些东西,谁依赖这个项目,重要算法流程描述,代码整体结构等写出来。 维护文档,这个我觉得最重要,你的服务都记录哪些日志,需要监控哪些业务指标,如何重启,有哪些配置项等,没这些东西,你的项目很难运维。 上面这些文档都是项目全局性的文档,不适合写在docstring或注视里,所以要有单独的文档。 打包python有专门的模块打包系统distutils,你可以用这套机制把你的代码打包并分发到Pypi上,这样任何人都可以用pip或easy_install安装你的模块。 如果你开发的是内部项目,还可以用mypypi架设私有的pypi,然后把项目的大的版本更新发布到内部的pypi上,配置管理人员和运维人员可以很方便的从pypi上拉取代码安装到测试环境或生产环境。 发布大版本的时候要给版本命名及编写ChangeList,可以参考Git Pro的相关章节,主要记住以下几个命令。 git tag -a v0.1 -m my test tag#给大版本命名,打Taggit describe master #给小版本命名,Git将会返回一个字符串,由三部分组成:最近一次标定的版本号,加上自那次标定之后的提交次数,再加上一段SHA-1值git shortlog --no-merges master --not v0.1 #生成版本简报,ChangeListpython有自己的打包机制,所以一般不要用git archive命令。 当然大版本管理用pypi管理比较合适,小的bug fix,紧急上线等好多公司都是用git直接从生产环境拉代码更新,因为git,svn等可以很方便的撤销某次更新,回滚到某个位置。 关于打包,请阅读如下链接:Python 打包指南深入Python3.0:打包 Python 类库python打包:分发指定文件
「干货」让Python性能起飞的15个技巧,你知道几个呢?
前言
Python 一直以来被大家所诟病的一点就是执行速度慢,但不可否认的是 Python 依然是我们学习和工作中的一大利器。本文总结了15个tips有助于提升 Python 执行速度、优化性能。
关于 Python 如何精确地测量程序的执行时间,这个问题看起来简单其实很复杂,因为程序的执行时间受到很多因素的影响,例如操作系统、Python 版本以及相关硬件(CPU 性能、内存读写速度)等。在同一台电脑上运行相同版本的语言时,上述因素就是确定的了,但是程序的睡眠时间依然是变化的,且电脑上正在运行的其他程序也会对实验有干扰,因此严格来说这就是实验不可重复。
我了解到的关于计时比较有代表性的两个库就是time和timeit。
其中,time库中有time()、perf_counter()以及process_time()三个函数可用来计时(以秒为单位),加后缀_ns表示以纳秒计时(自 Python3.7 始)。在此之前还有clock()函数,但是在 Python3.3 之后被移除了。上述三者的区别如下:
与time库相比,timeit 有两个优点:
(stmt=pass, setup=pass, timer= , number=, globals=None)参数说明:
本文所有的计时均采用timeit方法,且采用默认的执行次数一百万次。
为什么要执行一百万次呢?因为我们的测试程序很短,如果不执行这么多次的话,根本看不出差距。
Exp1:将字符串数组中的小写字母转为大写字母。
测试数组为 oldlist = [life, is, short, i, choose, python]。
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 21.29%
Exp2:求两个list的交集。
测试数组:a = [1,2,3,4,5],b = [2,4,6,8,10]。
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 35.33%
关于set()的语法:|、&、-分别表示求并集、交集、差集。
我们可以通过多种方式对序列进行排序,但其实自己编写排序算法的方法有些得不偿失。因为内置的 sort()或 sorted() 方法已经足够优秀了,且利用参数key可以实现不同的功能,非常灵活。二者的区别是sort()方法仅被定义在list中,而sorted()是全局方法对所有的可迭代序列都有效。
Exp3:分别使用快排和sort()方法对同一列表排序。
测试数组:lists = [2,1,4,3,0]。
方法一
方法二
方法一耗时 2.s ,方法二耗时 0.s ,性能提升 97.76%
顺带一提,sorted()方法耗时 0.s 。
可以看出,sort()作为list专属的排序方法还是很强的,sorted()虽然比前者慢一点,但是胜在它“不挑食”,它对所有的可迭代序列都有效。
扩展 :如何定义sort()或sorted()方法的key
1.通过lambda定义
2.通过operator定义
![50个编写出色的Python程序的实用技巧](https://tyye.cn/zb_users/theme/tpure/style/images/lazyload.png)
operator的itemgetter()适用于普通数组排序,attrgetter()适用于对象数组排序
3.通过cmp_to_key()定义,最为灵活
Exp4:统计字符串中每个字符出现的次数。
测试数组:sentence=life is short, i choose python。
方法一
方法二
方法一耗时 2.s ,方法二耗时 1.s ,性能提升 41.94%
列表推导(list comprehension)短小精悍。在小代码片段中,可能没有太大的区别。但是在大型开发中,它可以节省一些时间。
Exp5:对列表中的奇数求平方,偶数不变。
测试数组:oldlist = range(10)。
方法一
方法二
方法一耗时 1.s ,方法二耗时 1.s ,性能提升 7.57%
大多数人都习惯使用+来连接字符串。但其实,这种方法非常低效。因为,+操作在每一步中都会创建一个新字符串并复制旧字符串。更好的方法是用 join() 来连接字符串。关于字符串的其他操作,也尽量使用内置函数,如isalpha()、isdigit()、startswith()、endswith()等。
Exp6:将字符串列表中的元素连接起来。
测试数组:oldlist = [life, is, short, i, choose, python]。
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 70.29%
join还有一个非常舒服的点,就是它可以指定连接的分隔符,举个例子
life//is//short//i//choose//python
Exp6:交换x,y的值。
测试数据:x, y = 100, 200。
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 13.88%
在不知道确切的循环次数时,常规方法是使用while True进行无限循环,在代码块中判断是否满足循环终止条件。虽然这样做没有任何问题,但while 1的执行速度比while True更快。因为它是一种数值转换,可以更快地生成输出。
Exp8:分别用while 1和while True循环 100 次。
方法一
方法二
方法一耗时 3.0004s ,方法二耗时 3.9991s ,性能提升 1.94%
将文件存储在高速缓存中有助于快速恢复功能。Python 支持装饰器缓存,该缓存在内存中维护特定类型的缓存,以实现最佳软件驱动速度。我们使用lru_cache装饰器来为斐波那契函数提供缓存功能,在使用fibonacci递归函数时,存在大量的重复计算,例如fibonacci(1)、fibonacci(2)就运行了很多次。而在使用了lru_cache后,所有的重复计算只会执行一次,从而大大提高程序的执行效率。
Exp9:求斐波那契数列。
测试数据:fibonacci(7)。
方法一
方法二
方法一耗时 3.0009s ,方法二耗时 0.s ,性能提升 98.72%
注意事项:
我被执行了(执行了两次demo(1, 2),却只输出一次)
_cache(maxsize=128, typed=False)的两个可选参数:
点运算符(.)用来访问对象的属性或方法,这会引起程序使用__getattribute__()和__getattr__()进行字典查找,从而带来不必要的开销。尤其注意,在循环当中,更要减少点运算符的使用,应该将它移到循环外处理。
这启发我们应该尽量使用from ... import ...这种方式来导包,而不是在需要使用某方法时通过点运算符来获取。其实不光是点运算符,其他很多不必要的运算我们都尽量移到循环外处理。
Exp10:将字符串数组中的小写字母转为大写字母。
测试数组为 oldlist = [life, is, short, i, choose, python]。
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 24.33%
当我们知道具体要循环多少次时,使用for循环比使用while循环更好。
Exp12:使用for和while分别循环 100 次。
方法一
方法二
方法一耗时 3.9997s ,方法二耗时 1.s ,性能提升 73.82%
Numba 可以将 Python 函数编译码为机器码执行,大大提高代码执行速度,甚至可以接近 C 或 FORTRAN 的速度。它能和 Numpy 配合使用,在 for 循环中或存在大量计算时能显著地提高执行效率。
Exp12:求从 1 加到 100 的和。
方法一
方法二
方法一耗时 3.s ,方法二耗时 0.s ,性能提升 93.61%
矢量化是 NumPy 中的一种强大功能,可以将操作表达为在整个数组上而不是在各个元素上发生。这种用数组表达式替换显式循环的做法通常称为矢量化。
在 Python 中循环数组或任何数据结构时,会涉及很多开销。NumPy 中的向量化操作将内部循环委托给高度优化的 C 和 Fortran 函数,从而使 Python 代码更加快速。
Exp13:两个长度相同的序列逐元素相乘。
测试数组:a = [1,2,3,4,5], b = [2,4,6,8,10]
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 54.22%
若要检查列表中是否包含某成员,通常使用in关键字更快。
Exp14:检查列表中是否包含某成员。
测试数组:lists = [life, is, short, i, choose, python]
方法一
方法二
方法一耗时 0.s ,方法二耗时 0.s ,性能提升 74.19%
itertools是用来操作迭代器的一个模块,其函数主要可以分为三类:无限迭代器、有限迭代器、组合迭代器。
Exp15:返回列表的全排列。
测试数组:[Alice, Bob, Carol]
方法一
方法二
方法一耗时 3.9484s ,方法二耗时 0.s ,性能提升 89.98%
根据上面的测试数据,我绘制了下面这张实验结果图,可以更加直观的看出不同方法带来的性能差异。
从图中可以看出,大部分的技巧所带来的性能增幅还是比较可观的,但也有少部分技巧的增幅较小(例如编号5、7、8,其中,第 8 条的两种方法几乎没有差异)。
总结下来,我觉得其实就是下面这两条原则:
内置库函数由专业的开发人员编写并经过了多次测试,很多库函数的底层是用C语言开发的。因此,这些函数总体来说是非常高效的(比如sort()、join()等),自己编写的方法很难超越它们,还不如省省功夫,不要重复造轮子了,何况你造的轮子可能更差。所以,如果函数库中已经存在该函数,就直接拿来用。
有很多优秀的第三方库,它们的底层可能是用 C 和 Fortran 来实现的,像这样的库用起来绝对不会吃亏,比如前文提到的 Numpy 和 Numba,它们带来的提升都是非常惊人的。类似这样的库还有很多,比如Cython、PyPy等,这里我只是抛砖引玉。
原文链接:
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。