《Python Cookbook》的作者David Beazley的课程PPT开源了,目标用户是希望从编写基础脚本过渡到编写更复杂程序的高级 Python 程序员,课程主题侧重于流行库和框架中使用的编程技术,主要目的是更好地理解 Python 语言本身,以便阅读他人的代码,并将新发现的知识应用到自己的项目中。内容组织的很棒,总共分为九个章节,我在阅读过程中顺便翻译整理下,用来查缺补漏了。翻译内容并非原版无对照翻译,有所增减,本篇是系列第五节。
感兴趣可前往原课件进行阅读 https://github.com/dabeaz-course/python-mastery/blob/main/PythonMastery.pdf
首选关键字来传递可选参数
a = read_data('data.csv', debug=True) # YES!
b = read_data('data.csv', True) # NO!
关键字使代码更加清晰
可以强制使用关键字参数
仅使用不可变值,例如 None、True、False、数字或字符串
def func(a, items=[]):
items.append(a)
return items
>>> func(1)
[1]
>>> func(2)
[1, 2]
>>> func(3)
[1, 2, 3]
函数应该有一个文档字符串
def add(x, y):
'''
Adds x and y together.
'''
return x + y
有助于提供 help() 命令和开发工具
重要提示:类型签名或其他详细信息可以帮助人们阅读代码
可选注释可以指示类型
def add(x:int, y:int) -> int:
'''
Adds x and y together.
'''
return x + y
类型提示不执行任何操作,但可能对代码检查器、文档、IDE 等有用
Future
处理并发,两个函数同时执行
from concurrent.futures import Future
fut = Future()
def sum_map(func, nums):
total = 0
for n in nums:
total += func(n)
return total
nums = [1, 2, 3, 4]
result = sum_map(lambda x: x*x, nums)
def map(func, values):
result = []
for x in values:
result.append(func(x))
return result
def reduce(func, values, initial=0):
result = initial
for n in values:
result = func(n, result)
return result
def sum(x, y):
return x + y
def square(x):
return x * x
nums = [1, 2, 3, 4]
result = reduce(sum, map(square, nums))
将复杂问题分解为可管理的部分,然后将这些部分组合在一起,以创建一个整体的解决方案。这种方式有助于减少复杂性,提高代码的可读性、可维护性和可扩展性,是现代软件开发的一个重要原则。
def add(x, y):
def do_add():
print(f'{x} + {y} -> {x+y}')
return do_add
>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
3 + 4 -> 7
>>>
嵌套作用域:外部函数定义的变量
>>> a = add(3, 4)
>>> a.__closure__
(<cell at 0x54f30: int object at 0x54fe0>,
<cell at 0x54fd0: int object at 0x54f60>)
>>> a.__closure__[0].cell_contents
3
>>> a.__closure__[1].cell_contents
4
try:
statements
...
except RuntimeError as e:
# Handle the runtime error
...
try:
# Some complicated operation
...
except Exception as e:
print("Sorry, it didn't work.")
print("Reason:", e)
...
try:
# Some complicated operation
...
except Exception as e:
print("Sorry, it didn't work.")
print("Reason:", e)
raise
import logging
log = logging.getLogger(__name__)
def read_data(filename):
...
try:
name = row[0]
shares = int(row[1])
price = float(row[2])
except ValueError as e:
log.warning("Bad row: %s", row)
log.debug("Reason : %s", e)
断言不用于检查用户输入: 断言通常不用来验证用户输入数据,而是用来验证程序内部的条件是否满足。用户输入的数据是不可控的,因此使用断言来检查它们可能不太安全,而且断言会在生产环境中被默认禁用。
用于验证程序不变式: 断言应该用于验证程序内部的条件,这些条件被称为“不变式”,即程序执行过程中必须始终保持为真的条件。如果断言失败,意味着程序出现了编程错误,可能是程序员在代码中引入了错误。
失败指示编程错误: 断言失败会指示存在编程错误,而不是一般的错误输入。这种方式可以将错误追溯到错误的调用者或部分,以便进行修复。
可被禁用: 断言可以通过在 Python 解释器中使用 -O
(大写字母 O)参数来禁用。在启用断言时,如果断言条件不满足,程序将会引发 AssertionError
异常。但在禁用断言时,Python 解释器会忽略所有断言语句,这有助于在生产环境中避免性能损失。
def add(x, y):
'''
Adds x and y
'''
assert isinstance(x, int)
assert isinstance(y, int)
return x + y
>>> add(2, 3)
5
>>> add('2', '3')
Traceback (most recent call last):
...
AssertionError
>>>
在大型应用中可能变得相当复杂: 随着应用程序规模的增加,测试代码的编写可能会变得非常复杂。在大型应用中,需要测试的功能和组件变得更多,测试之间的依赖关系也会增加,因此编写、维护和运行测试会变得复杂。
unittest
模块的多样选项: Python 提供了 unittest
模块来进行单元测试,但它有很多选项,涉及测试运行器、结果收集和其他测试相关的方面。在编写测试用例时,你需要处理这些选项,这可能会增加代码的复杂性。
考虑使用 pytest
作为替代: 提到了 pytest
作为替代方案。pytest
是 Python 中流行的一个第三方测试框架,它提供了更简洁的语法和丰富的功能,可以减少测试代码的复杂性。相比 unittest
,pytest
的语法更加简洁直观,并且它具有丰富的插件系统和灵活的配置选项,使得测试更加方便。
class TestAdd(unittest.TestCase):
def test_simple(self):
# Test with simple integer arguments
r = simple.add(2, 2)
self.assertEqual(r, 5)
def test_str(self):
# Test with strings
r = simple.add('hello', 'world')
self.assertEqual(r, 'helloworld')