Python是一种编程语言,具有高水平的灵活性。同行是,开发人员可以轻松地使用不同的技巧,这些技巧将导致源代码中的异质性,从而降低其可读性和可维护性。与任何编程语言一样,团队中的define best practices很重要,以使源代码保持一致,避免错误并节省code reviews期间的时间。
在Promyze上,我们最近与合作伙伴Arolla(重播是in French)在上进行了网络研讨会,如何在Python中编写干净的代码? /p>
nb:请注意,我们声称以下做法始终有效,而且没有示例总是不好的。相信自己;) 当您想计算列表,元组或另一个可触觉的元素出现时,在运行时使用 关键字 in 是一种优雅,可读和可维护的方法,可以在序列中检查特定元素的存在: 主张将更容易按以下顺序阅读: 有时,当我们创建一个类时,我们将拥有一个字段,其价值源于一个或多个其他字段。例如,在class person 中,我们可以拥有一个 在这种情况下,重要的是通过用注释 @property 定义属性来保护复合字段的内容。回到我们的班级 person 的示例,这将阻止用户通过编写 这使代码更可读取和可维护,因此,当修改代码时,更容易弄清代码中的每个对象来自何处。 性能方面,它基本上与导入完整模块(ex。 也就是说,如果我们编写 避免在不相关时创建新列表。 a 列表理解 是一种通过从现有迭代中转换元素(例如列表,元组或字典)来创建新列表的一种方式,我们希望要过滤一些元素并对每个元素执行操作。 多次,尤其是在函数或方法的参数之间没有逻辑顺序时,建议通过指定参数名称来调用函数或方法(例如, 可以在调用函数/方法时强制命名参数。我们可以通过在参数开始时使用*来做到这一点。 这避免了许多可能的问题和混乱。 但是,这不是一直要做的事情,而是在有意义的时候。 而不是: 我们更喜欢: ,如果您与不是Python专家但对Java或C#更熟悉的开发人员合作,则这种做法可能很重要。他们对课堂和方法的抽象概念更加满意。 而不是: 我们更喜欢: 避免全局变量,通常是源代码外部函数。 而不是: 我们更喜欢: 这可能导致出乎意料且非常奇怪的行为。 而不是: 我们更喜欢:: f-string允许以比字符串串联提供的更自然(公认的烦人)方式写句子。 做: 不要: 这种做法有助于代码可读性及其性能,同时仍保持索引。性能增益是因为 enumerate()创建了该集合的迭代器,该迭代器比通过每个项目循环 不要: 做: 所有这些最佳实践都可以从我们的IDE和代码评论插件中定义。我们与Vscode,Jetbrains Suite和Eclipse兼容。因此,如果您使用VSCODE或PYCHARM编码Python,则可以选择它!然后,您创建的每种练习都将在专门的研讨会期间作为团队进行验证,最终结果看起来像: 您可以提供句法模式,以在编码或审查代码时提供建议,并在Promyze的入职研讨会期间使用此练习。 整个目录也可在我们的公共Hub of best practices上获得,用户可以在各种域上共享实践并在Promyze中使用它们。 您现在可以开始创建实践for free。
#1使用计数器计算出现
collection
库的计数器更有效:
from collections import Counter
array = [1, 1, 2, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3]
counts = Counter(array)
print(counts)
# Will print => Counter({2: 5, 3: 4, 1: 3, 4: 2, 5: 1})
#2使用“在”中简化语句
detectives = ["Sherlock Holmes", "Hercule Poirot", "Batman"]
person = "Batman"
# Don't
if person == "Batman" or person == "Hercule Poirot" or person == "Sherlock Holmes":
print("That person is a detective")
# Do
if person in detectives:
print("That person is a detective")
#3在断言中预期的是实际的
def test_big_stuff():
actual_result = ...
expected_result = ...
assert actual_result == expected_result
#4 相关时使用属性
full_name
字段,该字段将first_name
和last_name
的值串联。person.full_name = ...
从郊外设置full_name
的值。
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
#5使用完全合格的绝对进口
import foo
)的基本相同,因为Python始终加载完整的模块,无论我们是否只是导入该模块的对象。from foo.bar import Bar
时,python会加载整个模块foo.bar
,然后继续选择Bar
from foo.bar import Bar
from spam.eggs import Eggs
def main():
bar = Bar()
eggs = Eggs()
#6使用迭代器而不是明确列表
def get_max():
iterable = ["a", "bbb", "c"]
# Don't
max_len = max([len(x) for x in iterable])
# Do
max_len = max(len(x) for x in iterable)
assert max_len == 3
get_max()
#7使用列表综合
# Don't
def get_even_nums_squared():
nums = [1, 2, 3, 4, 5, 6]
res = []
for num in nums:
if num % 2 == 0:
res.append(num * num)
return res
# Do
def get_even_nums_squared():
nums = [1, 2, 3, 4, 5, 6]
return [x * x for x in nums if x % 2 == 0]
#8更喜欢使用仅关键词的参数
make_coffee(with_sugar=True, with_milk=True)
)。
def make_coffee(with_sugar=False, with_milk=False):
pass
make_coffee(True, True)
def make_coffee(*, with_sugar=False, with_milk=False):
pass
make_coffee(with_milk=True, with_sugar=True)
#9使用abcmeta进行抽象课程
ABCMeta
是一种在Python中的元类(创建类的类)。它代表“抽象基类元”。
class Fooer:
def foo(self):
raise NotImplementedError()
class Spam(Fooer):
def foo(self):
print("spamming")
from abc import ABCMeta, abstractmethod
class Fooer(metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass
class Spam(Fooer):
def foo(self):
print("spamming foos")
#10使用main()函数
from server import Server
HOST = "127.0.0.1"
PORT = 8080
SERVER = Server()
if __name__ == "__main__":
SERVER.start(HOST, PORT)
from server import Server
def main():
host = "127.0.0.1"
port = 8080
Server = Server()
Server.start(host, port)
if __name__ == "__main__":
main()
#11 请勿将空列表作为默认参数
def add_player_to_team(player, team=[]):
team.append(player)
print(team)
def add_player_to_team(player, team=None):
if team is None:
team = []
team.append(player)
print(team)
#12 更喜欢f弦而不是字符串串联
first_name = "Jake"
last_name = "Sully"
age = 28
message = f"{first_name} {last_name} is {age} years old now"
print(message)
first_name = "Jake"
last_name = "Sully"
age = 28
message = first_name + " " + last_name + " is " + str(age) + " years old now"
print(message)
#13 更喜欢枚举()而不是范围(len())当您要保留峰值项目的索引
ages = [1, 2, 18, 24, 8]
for i in range(len(ages)):
if ages[i] >= 18:
print(f"I'm client n°{i+1} and I'm {age} years old, I'm an adult now.")
ages = [1, 2, 18, 24, 8]
for i, age in enumerate(ages):
if age >= 18:
print(f"I'm client n°{i+1} and I'm {age} years old, I'm an adult now.")