如何写出更具有Python风格的代码

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶高效! 阅读详情

我们都喜欢 Python,因为它让编程和理解变的更为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python 的代码风格是非常优雅、明确和简单,在 Python 解释器中执行 import this 你可以看到 Tim Peters 编写的 Python 之禅:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

这里我找了目前最好的中文版本:

美 优于 丑

明确 优于 隐晦

简单 优于 复杂

复杂 也好过 繁复

扁平 优于 嵌套

稀疏 优于 拥挤

可读性很重要

固然代码实用与否 比洁癖更重要,

我们以为的特例也往往没有特殊到必须打破上述规则的程度

除非刻意地静默,否则不要无故忽视异常

如果遇到模棱两可的逻辑,请不要自作聪明地瞎猜。

应该提供一种,且最好只提供一种,一目了然的解决方案

当然这是没法一蹴而就的,除非你是荷兰人[1]

固然,立刻着手 好过 永远不做。

然而,永远不做 也好过 不审慎思考一撸袖子就莽着干

如果你的实现很难解释,它就一定不是个好主意

即使你的实现简单到爆,它也有可能是个好办法

命名空间大法好,不搞不是地球人!

[1]:本文作者 Tim peters 解释说这里的荷兰人指的是 Python 的作者 Guido van Rossum.

以下是用 Python 编写更好的代码的 8 种方法:

一、忘掉类 C 语言风格

如果需要打印列表中的所有元素及其索引,你想到的第一件事是:

for i in range(len(arr)):
    print(i, arr[i])

那么你仍然在编写 C 代码。摆脱这一点,请牢记 Python 关键字 enumerate 。它索引列表/字符串中的所有元素,并且支持设置索引的起始编号

>>> for index, item in enumerate(['a','b','c']): 
...     print(index, item)
... 
0 a
1 b
2 c
>>> for index, item in enumerate(['a','b','c'],1): #这里第二个参数可以设置起始编号
...     print(index,item)
... 
1 a
2 b
3 c

现在看起来更好了,而且更加 Pythonic。将列表转换成字符串呢?如果你这样写:

# The C way
string = ''
for i in arr:
    string += i

就是 C 风格,如果使用 Python 的关键字 join,不仅效率更高,而且更优雅:

# The Python way
string = ''.join(arr)

就像 join 一样  ,Python 有很多神奇的关键字,因此请不要为语言工作,而是使用该语言为你工作。

二、牢记 PEP8

我不是要求你完全遵循 PEP8,而是要求遵循其中的大多数规则,何况现在有很多自动格式化的工具,足以让你的代码更加美观,我们的 Python 之父也说过:阅读代码的频率远远高于写代码的频率,他是如此的正确!因此代码的可读性非常重要。

你是否对自己曾经写过的代码感到好奇?为什么这么写,这句话为什么在这?好吧,PEP8 是大多数这类问题的答案。尽管代码注释是个好方法,但是代码的风格也需要加以调整,比如变量 i , j , count 等即使第一次出现时写了注释,也不能保证后面你仍然记得住,这样来看就浪费了宝贵的时间。

任何普通的程序员都可以编写计算机可以理解的代码。只有好的程序员可以编写人类可以理解的代码。

首选 CamelCase 作为类, UPPER_WITH_UNDERSCORES 作为常量,而 lower_with_underscores 作为变量,方法和模块名称。即使使用,也要避免使用单一名称功能 lambda 。

三、善用推导式

常用的推导式有:列表推导式,集合推导式,字典推导式。先说下列表推导式。

列表推导式就是当我们需要基于一个已有的列表创建新的列表时,所使用的语法格式,列表推导式包含以下四个部分:

1、一个输入序列(Input Sequence) 2、一个变量,代表着输入序列的一个成员(Variable) 3、一个可选的判定表达式,表达这个变量满足的条件(Optional Predicate ) 4、一个输出序列,根据 2 和 3 生成一个输出序列(Output Expression)

比如有个列表既有数字,又有字符,现在需要计算数字的平方,并将结果放在新的列表中,如果不用列表推导式,写出的代码就是这样的:

# bad code
a_list = [1, ‘4’, 9, ‘a’, 0, 4]

squared_ints = []
for item in a_list:
    if type(item) == types.IntType:
        squared_ints.append(item**2)

如果使用列表推导式,只需要两行代码,非常的优雅:

a_list = [1, ‘4’, 9, ‘a’, 0, 4]
squared_ints = [ e**2 for e in a_list if type(e) == types.IntType ]

当然,如果你喜欢 map 和 filter,你还可以这样做,当时这是不推荐的,因为可读性不好:

map(lambda e: e**2, filter(lambda e: type(e) == types.IntType, a_list))

比如集合推导式的使用:

给定输入

names = [ 'Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'J', 'Bob' ]

希望得到:

{ 'Bob', 'John', 'Alice' }

那么集合推导式就是:

{ name[0].upper() + name[1:].lower() for name in names if len(name) > 1 }

再比如字典推导式:

mcase = {'a':10, 'b': 34, 'A': 7, 'Z':3}

mcase_frequency = { k.lower() : mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys() }

# mcase_frequency == {'a': 17, 'z': 3, 'b': 34}

从上面可以看出。推导式风格的代码是优雅的,人类易读的。

四、你还在显式的关闭文件吗?

如果你在写代码时仍然在显式的关闭文件,就像上图中的 programmer,你在为编程语言工作,如果你学会了使用 with 上下文管理器,那么你就是一个 Python programmer,让编程语言为你工作:

with open('filename.txt', 'w') as filename:
    filename.write('Hello')

当程序退出 with 块时,文件会自动关闭。with 语句的语法格式:

with VAR as EXPR:
    BLOCK

相当于:

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

有很多网络连接、数据库连接库都会提供 with 功能。甚至熟悉了 with 的实现机制后,可以自行实现 with 功能:

class File(object):
    def __init__(self, file_name, method):
        self.file_obj = open(file_name, method)
    def __enter__(self):
        return self.file_obj
    def __exit__(self, type, value, traceback):
        self.file_obj.close()

只要定义了 __enter__,__exit__方法,就可以使用 with 语句:

with File('demo.txt', 'w') as opened_file:
    opened_file.write('Hola!')

五、使用迭代器和生成器

迭代器:iterator 生成器:generator

迭代器和生成器都是 Python 中功能强大的工具,值得精通。迭代器是一个更笼统的概念:任何一个对象只要它所属的类具有__next__方法(Python 2是next)和具有返回 self 的__iter__方法都是迭代器。

每个生成器都是一个迭代器,但反之不然。生成器是通过调用具有一个或多个 yield 表达式的函数而构建的,并且该函数是满足上一段对iterator 的定义的对象。

使用区别:

网络上很多技术博主都说生成器是懒人版的迭代器,比迭代器更节省内存,其实是错误的,他们都很节省内存(我会举例子)。

他们真正的区别是:当你需要一个具有某些复杂的状态维护行为的类,或者想要公开除__next__(和__iter____init__)之外的其他方法时,你就需要自定义迭代器,而不是生成器。

通常,一个生成器(有时,对于足够简单的需求,一个生成器表达式)就足够了,并且它更容易编写代码。

比如说计算正整数 a 到 b (b 远远大于 a)直接的平方,生成器的话就是:

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)

或者:

generator = (i*i for i in range(a, b))

如果是迭代器,则是这样:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop
    def __iter__(self): return self
    def __next__(self): # next in Python 2
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)

可以看出,迭代器写起来稍麻烦,当也更为灵活,比如你想提供一个 current 方法时,可以直接添加到 Squares 类中:

    def current(self):
       return self.start

从上述可以看出,迭代器并没有保存 a 到 b 之间的所有值,所有并不消耗过多的内存,这一点也可以自行测试,代码如下:

>>> from collections.abc import Iterator
>>> from sys import getsizeof
>>> a = [i for i in range(1001)]
>>> print(type(a))
<class 'list'>
>>> print(getsizeof(a))
9016
>>>
>>> b = iter(a)
>>> print(type(b))
<class 'list_iterator'>
>>> print(isinstance(b,Iterator))
True
>>> print(getsizeof(b))
48
>>> c = (i for i in range(1001))
>>> print(getsizeof(b))
48
>>> type(c)
<class 'generator'>
>>> type(b)
<class 'list_iterator'>

可以看出 b 是 iterator,c 是 generator,它们占用的内存大小是一样的。

六、善用 itertools

itertools 模块标准化了一个快速、高效利用内存的核心工具集,这些工具本身或组合都很有用。它们一起形成了“迭代器代数”,这使得在纯 Python 中有可以创建简洁又高效的专用工具。比如,如果你想要字符串中所有字符的组合或列表中数字的所有组合,则只需编写

from itertools import combinations
names = 'ABC'
for combination in combinations(names, 2):
    print(combination)
''' Output -
    ('A', 'B')
    ('A', 'C')
    ('B', 'C')
'''

这是一个值得经常使用的标准库,更多详细功能请参考官方文档:https://docs.python.org/zh-cn/3/library/itertools.html[1]

七、善用 collections

这又是一个值得使用的标准库 collections,它提供替代内置的数据类型的多个容器,如 defaultdict、OrderedDict、namedtuple、Counter、deque 等,非常使用,而且比自己实现要安全稳定的多。比如:

# frequency of all characters in a string in sorted order
from collections import (OrderedDict, Counter)
string = 'abcbcaaba'
freq = Counter(string)
freq_sorted = OrderedDict(freq.most_common())
for key, val in freq_sorted.items():
    print(key, val)
''' Output -
    ('a', 4)
    ('b', 3)
    ('c', 2)
'''

不多说了,看官方文档:https://docs.python.org/3/library/collections.html[2]

八、不要过度使用类

不要过度使用类。坚持用 Java 和 C ++ 的程序员会经常使用类,但是在使用 Python 时,可以在函数和模块的帮助下复用代码。除非绝对需要,否则不必创建类。

本文讲述类 8 个让你写出更好 Python 代码的方法,希望对你有所帮助。

推荐阅读:

10个技巧让你的代码更优雅

6 个值得玩味的 Python 代码

参考资料

[1]

https://docs.python.org/zh-cn/3/library/itertools.html: https://docs.python.org/zh-cn/3/library/itertools.html

[2]

https://docs.python.org/3/library/collections.html: https://docs.python.org/3/library/collections.html

Python入门教程:几种常见的Python算法实现过程 打个比方来说明二分查找的原理:比如我随便想了个范围在1~100以内的整数,由你来猜,以最少的次数来猜出这个数字,你每次猜完给出个数字,我会回复大了或小了,第一种方法是你从1开始依次往后猜,那如果我想的数字是100,那么你就要猜100次;第二类问题是从节点A出发,前往B节点的哪条路径最短。快速排序的运行速度快于选择排序,它的工作原理是这样:设要排序的数组是N,首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。 阅读详情

相关推荐

python-个人笔记

入门python运行

u011767319的博客 2479

python __setstate___Python模块

模块是包含Python定义和语句的文件。一个模块可以定义函数,类和变量。模块也可以包含可运行的代码。将相关代码分组到一个模块中可使代码易于理解和使用。示例:# A simple module, calc.py def add(x, y): return (x+y) def subtract(x, y): return (x-y) import语句通过在其他一些Python...

weixin_39796855的博客 507

深入理解 Python 类中的各种方法

实例方法:绑定到实例,通过 self 访问实例属性和方法。类方法:绑定到类,通过 cls 访问和修改类属性。静态方法:不绑定到实例或类,通常用于逻辑上属于类但不依赖实例或类属性的方法。特殊方法:以双下划线包围,由 Python 在特定情况下自动调用。属性方法:将方法转换为属性,提供定制的 getter、setter 和 deleter。__new__ 方法:用于创建实例,在 __init__ 之前调用。__call__ 方法:使实例可以像函数一样被调用。__del__ 方法。

互联网架构小马的博客 1405

python类及其方法

                 python类及其方法 一、介绍 在 Python 中,面向对象编程主要有两个主题,就是类和类实例类与实例:类与实例相互关联着:类是对象的定义,而实例是"真正的实物",它存放了类中所定义的对象的具体信息。 类有这样一些的优点: 1、类对象是多态的:也就是多种形态,这意味着我们可以对不同的类对象使用同样的操作方法,而不需要额外写代码。 2、类的封装:封...

weixin_34149796的博客 575

如何写出具有Python风格代码 | 如何写出优雅的Python代码

很多人喜欢 Python,因为它让编程和理解变的为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python代码风格是非常优雅、明确和简单,在 Python 解释器中执行import this你可以看到 Tim Peters 编写的 Python 之禅: >>>importthis TheZenofPython,byTimPeters Beautifulisbe...

自闭小菜 380

如何写出具有Python风格代码,五分钟教会你!

我们都喜欢 Python,因为它让编程和理解变的为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python代码风格是非常优雅、明确和简单,在 Python 解释器中执行import this你可以看到 Tim Peters 编写的 Python 之禅: >>>importthis TheZenofPython,byTimPeters Beautifulisbe...

爬遍所有网站 230

python怎么写方法_如何写出具有Python风格代码,五分钟教会你!

原标题:如何写出具有Python风格代码,五分钟教会你!我们都喜欢 Python,因为它让编程和理解变的为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python代码风格是非常优雅、明确和简单,在 Python 解释器中执行 import this 你可以看到 Tim Peters 编写的 Py...

weixin_39640265的博客 341

python exit()什么意思_如何写出具有Python风格代码

我们都喜欢 Python,因为它让编程和理解变得为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python代码风格是非常优雅、明确和简单,在 Python 解释器中执行 import this 你可以看到 Tim Peters 编写的 Python 之禅:>>> import th...

weixin_39733232的博客 138

python代码怎么写出色_如何写出具有Python风格代码,五分钟教会你!

我们都喜欢 Python,因为它让编程和理解变的为简单。但是一不小心,我们就会忽略规则,以非 Pythonic 方式编写一堆垃圾代码,从而浪费 Python 这个出色的语言赋予我们的优雅。Python代码风格是非常优雅、明确和简单,在 Python 解释器中执行import this你可以看到 Tim Peters 编写的 Python 之禅:>>>importth...

weixin_39925350的博客 165

python程序的书写风格_如何编写高质量的Pythonic风格代码

来自微信公共号:菜鸟学python阅读本文大概需要3分钟每一种语言都有它的编程风格,打个比方就像各种菜系,粤菜,川菜,淮扬菜每一种都有自己的独特风格.Python的开发者用Pythonic这个词来形容那种符合python风格代码.这种pythonic风格代码,既不是非常严格的规范,也不是编辑器强加给开发者的规则,它是大家在python语言的过程中指定的一种指南,一种协同工作过逐渐形成的习惯.宗...

weixin_39898011的博客 196

电脑课装b专用代码_对比几段代码,看看你是 Python 菜鸟还是老鸟

Python 里有个小彩蛋:在 Python Shell 里输入 import this 这段话被称作“Python 之禅”(The Zen of Python),它列举了一些 Python 所推崇的理念,比如:优美胜于丑陋明确胜于隐晦简单胜于复杂…可读性很重要不要忽略错误面对不确定时,拒绝猜测现在做好过不做,但盲目动手不如不做如果你的实现很难说清楚,那是个坏想法;反之亦然…当你学完基础,可以写点...

weixin_39867708的博客 5588

python测网络连通性_Python基础5之编程风格

我的完整施工计划目前已完成以下四期Python专题:1我的施工计划2数字专题3字符串专题4列表专题5流程控制专题今天讨论 Python 编程风格,如何写出Pythonic的代码是本篇讨论的话题。基本目录结构:1 基本编程习惯1.1 多余的空格1.2 是否为 None 判断1.3 lamda 表达式1.4 最小化受保护代码1.5 保持逻辑完整性1.6 使用语义加明确的方法2 EAFP...

weixin_33484711的博客 188

python try catch 能知道是哪一行代码_3000 字教你学会最地道的 Python 编程风格

点击上方“Python编程时光”,选择“加为星标”第一时间关注Python技术干货!今天讨论 Python 编程风格,如何写出Pythonic的代码是本篇讨论的话题。基本目录结构:1 基本编程习惯1.1 多余的空格1.2 是否为 None 判断1.3 lamda 表达式1.4 最小化受保护代码1.5 保持逻辑完整性1.6 使用语义加明确的方法2 EAFP 防御编程风格3 LBYL ...

weixin_39874379的博客 150

python编程中要注意什么_关于编写Python代码中的一些注意事项

本篇文章参考 [美] Brett Slatkin 所著的《Effective Python: 59 Specific Ways to Write Better Python》一书。1 用 Pythonic 方式来思考在 Python 这个圈子中,开发者会用 pythonic 这个形容词来描述那些符合特定风格代码。这种 pythonic 风格,既不是非常严密的规范,也不是由编译器强加给开发者的规则...

weixin_39881802的博客 340

Python编码规范:写出优雅的Python代码

要编写优美的Python代码,需要不断地学习和实践,同时遵循Python社区的编码规范和最佳实践,写出代码清晰、简洁、易读、可维护和易于扩展。注释:好的注释能够让代码加易读和易于理解,注释应该清晰地解释代码的功能,而不是简单地描述代码的实现过程。缩进:在Python中,缩进是非常重要的,一般采用4个空格进行缩进,而不是使用tab键,这样能够使代码加清晰、易读。这些属性和方法应该只在类的内部使用。函数返回值:函数的返回值应该清晰地说明返回值的类型和用途,如果函数没有返回值,则应该使用None进行返回。

吃不胖. 270

Python 编码风格指南

原文:http://python.jobbole.com/84618/ 本文超出 PEP8 的范畴以涵盖我认为优秀的 Python 风格。本文虽然坚持己见,却不偏执。不仅仅涉及语法、模块布局等问题,同时深入范式、组织及架构的领域。希望本文能成为精简版 Python 代码风格的要素》。 目次 Python 风格要素 基本遵从 PEP 准则 灵活的单行长度 一致的命名 不要在这...

weixin_33709590的博客 258

python优雅代码大全_10个Python技巧帮你写出优雅的代码

阅读本文需要 2 分钟,公众号 somenzz ,欢迎学习 Python 的朋友订阅。现在写代码的门槛非常低了,少儿都开始编程了,但从代码风格一眼看出编码水平。是的,写代码是容易的,写出易读的代码也是容易的,但写出易读、优雅、高效的代码则需要经验的积累。今天分享 10 个技巧帮你写出优雅、符号 Pythonic 风格代码。1、三元表达式通常情况下,条件表达式是这样写的:condition ...

weixin_39975868的博客 333

pythonic风格代码有什么好处?附12个代码实例

就好比中文的笔画,有先后顺序,这是前人总结出的最符合文字书写的习惯。最后说下PEP8规范,PEP8是Python的编码规范,其目的在于提高代码的可读性。因为是习惯,不是江湖规则,所以你大可不必遵守pythonic,但如果你想成为python高手,最好是习惯这个习惯。zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。with语句提供一个有效的机制,让代码简练,同时在异常产生时,清理工作简单。美胜于丑,简胜于繁,这就是Python哲学。

分享Python、数据分析、人工智能前沿知识 704
上一篇: Python Web开发的完整指南
下一篇: 15个Python游戏小项目
somenzz
博客等级 码龄17年 762粉丝 292原创
评论 22
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值