首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python|Google Python样式指南(2)

Python|Google Python样式指南(2)

作者头像
算法与编程之美
发布2020-08-02 17:39:55
6810
发布2020-08-02 17:39:55
举报

2.11 条件表达式

适用于单行函数

2.11.1 定义

条件表达式(有时称为“三元运算符”)是为if语句提供较短语法的机制。例如:x = 1 if cond else 2。

2.11.2 优点

比if语句更短,更方便。

2.11.3缺点

可能比if语句难读。如果表达式很长,则可能很难找到条件。

2.11.4 结论

适用于单行函数. 在其他情况下,推荐使用完整的if语句.

2.12 参数值

2.12.1 定义

可以在函数的参数列表的末尾指定变量的值,例如def foo(a, b=0):。如果foo仅使用一个参数 b调用if,则将其设置为0。如果使用两个参数调用if,则b具有第二个参数的值。

2.12.2 优点

通常,您有一个使用许多默认值的函数,但是在极少数情况下,您想覆盖默认值。默认参数值提供了一种简便的方法,而不必为罕见的异常定义很多函数。由于Python不支持重载的方法/函数,因此默认参数是“伪造”重载行为的简便方法。

2.12.3缺点

默认参数在模块加载时评估一次。如果参数是可变对象(例如列表或字典),则可能会导致问题。如果函数修改了对象(例如,通过将项目附加到列表),则默认值将被修改。

2.12.4 结论

注意:不要在函数或方法定义中使用可变对象作为默认值。

Yes: def foo(a, b=None): if b is None: b = []Yes: def foo(a, b: Optional[Sequence] = None): if b is None: b = []Yes: def foo(a, b: Sequence = ()): ... No: def foo(a, b=[]): ...No: def foo(a, b=time.time()): ...No: def foo(a, b=FLAGS.my_thing): ...No: def foo(a, b: Mapping = {}): ...

2.13 属性

在通常使用简单,轻量级的访问器或设置器方法的地方,使用属性访问或设置数据。

2.13.1 定义

一种用于包装方法调用的方式,要求在轻量级计算时获取并设置属性作为标准属性访问。

2.13.2 优点

通过消除对简单属性访问的显式get和set方法调用,提高了可读性。允许计算是懒惰的。考虑使用Python方式维护类的接口。在性能方面,当直接变量访问是合理的时,允许属性绕过需要琐碎的访问器方法的情况。这也允许将来在不破坏接口的情况下添加访问器方法。

2.13.3 缺点

必须object在Python 2中继承。可以隐藏副作用,就像运算符重载一样。对于子类可能会造成混淆。

2.13.4 结论

使用新代码中的属性来访问或设置数据,而通常情况下,这些属性本可以使用简单,轻量级的访问器或设置器方法。属性应使用@property装饰器创建。

如果不覆盖属性本身,则对属性的继承可能不是显而易见的。因此,必须确保间接调用访问器方法,以确保属性会调用子类中重写的方法(使用 模板方法设计模式)。

2.14 True/False的求值

尽可能使用隐式false

2.14.1 定义

Python在布尔上下文中会将某些值求值为False。简单地说,所有的“空”值都被认为是False,因此 0, None, [], {}, ''在布尔上下文中所有值都为是False。

2.14.2 优点

使用Python布尔值的条件更易于阅读且不易出错。在大多数情况下,它们也更快。

2.14.3 缺点

对于C / C ++开发人员来说可能看起来很奇怪。

2.14.4 结论

如果可能,请使用“隐式”假,例如,if foo:而不是if foo != []:。不过,请注意以下几点:

始终使用if foo is None:(或is not None)检查None值。例如,在测试是否将默认None 设置为的变量或参数设置为其他值时。另一个值可能是在布尔上下文中为False的值!

切勿将布尔变量与False使用进行比较==。使用if not x: 代替。如果您需要与区分False,None则将表达式链接起来,例如if not x and x is not None:。

对于序列(字符串,列表,元组),使用的事实,空序列为假,所以if seq:和if not seq:是优选的,以if len(seq): 及if not len(seq):分别。

当处理整数时,隐式false可能带来的收益大于收益(即,意外地处理None为0)。您可以将一个已知为整数(而不是的结果len())的值与整数0进行比较。

2.15 过时的语言特性

尽可能使用字符串方法而不是字符串模块。使用函数调用语法而不是apply。如果函数参数是内联lambda,则使用列表理解和for循环,而不是filter和map。使用for循环而不是reduce。

2.15.1 定义

当前版本的Python提供了人们通常更喜欢的替代构造。

2.15.2 结论

我们不使用任何不支持这些功能的Python版本,因此没有理由不使用新样式。

Yes: words = foo.split(':') [x[1] for x in my_list if x[2] == 5] map(math.sqrt, data) # 没有内联lambda表达式。 fn(*args, **kwargs) No: words = string.split(foo, ':') map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list)) apply(fn, args, kwargs)

2.16 词法作用域(Lexical Scoping)

可以使用。

2.16.1 定义

嵌套的Python函数可以引用在封闭函数中定义的变量,但不能分配给它们。变量绑定使用词法作用域来解决,即基于静态程序文本。在块中对名称的任何赋值都会使Python将对该名称的所有引用都视为一个局部变量,即使使用是在赋值之前。如果发生全局声明,则将该名称视为全局变量。

使用此功能的一个示例是:

def get_adder(summand1): """返回一个将数字加到给定数字上的函数。""" def adder(summand2): return summand1 + summand2 return adder

2.16.2 优点

通常会产生更清晰,更优雅的代码。特别让经验丰富的Lisp和Scheme(以及Haskell和ML等)的程序员感到欣慰。

2.16.3 缺点

可能导致令人困惑的错误。

2.16.4 结论

可以使用。

2.17 函数与方法装饰器

如果有明显的优势,请明智地使用装饰器。避免 @staticmethod并限制使用@classmethod。

2.17.1 定义

函数和方法的装饰器 (也称为“ @符号”)。一种常见的修饰符是@property,用于将普通方法转换为动态计算的属性。但是,装饰器语法也允许用户定义装饰器。具体来说,对于某些功能my_decorator,这是:

class C: @my_decorator def method(self): # method body ...

等效于:

class C: def method(self): # method body ... method = my_decorator(method)

2.17.2 优点

优雅地指定了方法上的一些转换;转换可能会消除一些重复的代码,强制执行不变式等。

2.17.3 缺点

装饰器可以对函数的参数或返回值执行任意操作,从而导致令人惊讶的隐式行为。此外,装饰器在导入时执行。装饰器代码中的错误几乎不可能恢复。

2.17.4 结论

如果有明显的优势,请明智地使用装饰器。装饰器应遵循与功能相同的导入和命名准则。装饰器的python文档应该清晰的说明该函数是一个装饰器。为装饰器编写单元测试.避免装饰器自身对外界的依赖(例如,不要依赖文件,套接字,数据库连接等),因为在装饰器运行时(在导入时,可能来自pydoc或其他工具)它们可能不可用。在所有情况下,应(尽可能)确保使用有效参数调用的装饰器成功。

2.18 线程

不要依赖内置类型的原子性。

尽管Python的内置数据类型(例如字典)似乎具有原子操作,但在某些极端情况下,它们不是原子操作(例如,如果将 __hash__ 或 __eq__ 实现为Python方法),则不应依赖其原子性。您也不应该依赖于原子变量赋值(因为这又取决于字典)。

使用队列模块的Queue数据类型作为线程之间通信数据的首选方式。否则,请使用线程模块及其锁定原语。了解条件变量的合适使用方式,使用 threading.Condition 来取代低级别的锁了。

2.19 威力过大的特性

避免使用这些特性。

2.19.1 定义

Python是一种非常灵活的语言,可为您提供许多精美功能,例如自定义元类,访问字节码,即时编译,动态继承,对象重载,导入hack,反射(例如的某些用法 getattr()),对系统内部的修改,等等。

2.19.2 优点

这些是强大的语言功能。它们可以使您的代码更紧凑。

2.19.3 缺点

在并非绝对必要时使用这些“炫酷”功能非常诱人。难以阅读,理解和调试使用底层异常功能的代码。起初(原始作者)似乎没有这种方式,但是在重新访问代码时,它往往比更长但简单的代码更加困难。

2.19.4 结论

在代码中避免使用这些功能。

2.20 现代Python:Python 3和__future__导入

尽管不是每个项目都可以使用它,但所有代码都应编写为3兼容(并在3下进行测试)。

2.20.1 定义

python3是Python语言的一个重大变化。虽然现有的代码通常是在2.7的基础上编写的,但是有一些简单的事情可以让代码更加明确地表达其意图,从而更好地准备在python3下使用而不需要修改。

2.20.2 优点

一旦项目的所有依赖项都准备好了,用Python3编写的代码会更加明确,更容易在Python3下运行。

2.20.3 缺点

有些人觉得额外的样板很难看。将导入添加到实际上不需要导入所添加的功能的模块中是不寻常的。

2.20.4 结论

从__future__导入

鼓励使用from __future__ import语句。所有新代码应包含以下内容,现有代码应尽可能更新以兼容:

from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_function

2.21 类型注释代码(Type Annotated Code)

2.21.1 定义

类型注释(或“类型提示”)用于函数或方法的参数并返回值:

def func(a: int) -> List[int]:

您还可以使用类似的PEP-526语法声明变量的类型 :

a: SomeType = some_func()

或者在必须支持旧版Python版本的代码中使用类型注释。

a = some_func() # type: SomeType

2.21.2 优点

类型注释提高了代码的可读性和可维护性。类型检查器会将许多运行时错误转换为构建时错误,并降低使用Power Features的能力。

2.21.3 缺点

必须保持类型声明是最新的。您可能会看到您认为是有效代码的类型错误。使用类型检查器 可能会降低您使用Power Features的能力。

2.21.4 结论

强烈建议您在更新代码时启用Python类型分析。添加或修改公共API时,请包括类型注释,并在构建系统中启用通过pytype进行检查。由于静态分析对Python来说还比较陌生,因此我们认识到不良的副作用(例如错误推断的类型)可能会阻止某些项目采用。在这种情况下,鼓励作者添加带有TODO的注释或指向描述当前阻止在BUILD文件或代码本身中采用类型注释的问题的bug的链接。

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法与编程之美 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档