100 道 Python 经典面试题超强汇总(四):函数专题

本文介绍了高级Python程序员DavidBeazley的课程,关注流行库中的编程技术,包括函数设计原则、默认参数、关键字参数、文档字符串、类型提示、并发处理、函数式编程(如高阶函数、Lambda和Map)、闭包、错误处理和日志记录,以及在大型项目中的单元测试和pytest替代unittest的建议。
摘要由CSDN通过智能技术生成

《Python Cookbook》的作者David Beazley的课程PPT开源了,目标用户是希望从编写基础脚本过渡到编写更复杂程序的高级 Python 程序员,课程主题侧重于流行库和框架中使用的编程技术,主要目的是更好地理解 Python 语言本身,以便阅读他人的代码,并将新发现的知识应用到自己的项目中。内容组织的很棒,总共分为九个章节,我在阅读过程中顺便翻译整理下,用来查缺补漏了。翻译内容并非原版无对照翻译,有所增减,本篇是系列第五节。

感兴趣可前往原课件进行阅读👉 https://github.com/dabeaz-course/python-mastery/blob/main/PythonMastery.pdf

LLM应用全栈开发

函数设计

  • 仅对传递的参数进行操作
  • 对于相同的参数产生相同的结果
  • 避免隐藏的副作用
  • 目标:简单性和可预测性
函数调用
  • 名称和参数是“接口”

    image-20230812174241381

  • 调用函数应该直观且简单

  • 编写 API 的核心组件

命名约定
  • 有一种首选的 Python 风格

  • 下划线方式,而不是驼峰式

    image-20230812174446614

  • 对内部/私有函数使用前导 _

默认参数
  • 默认参数必须出现在定义的最后
  • 如果指定了参数值,则该参数在函数调用中是可选的
关键字参数
  • 首选关键字来传递可选参数

    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() 命令和开发工具

  • 重要提示:类型签名或其他详细信息可以帮助人们阅读代码

类型提示 (PEP 484)
  • 可选注释可以指示类型

    def add(x:int, y:int) -> int:
        '''
        Adds x and y together.
        '''
        return x + y
    
  • 类型提示不执行任何操作,但可能对代码检查器、文档、IDE 等有用

并发
  • 函数可能同时执行(线程)

  • 共享状态,在单个解释器中执行

    image-20230812175856552

Future

处理并发,两个函数同时执行

from concurrent.futures import Future
fut = Future()

image-20230812180128176

函数式编程

高阶函数

  • 函数可以接受函数作为输入

    image-20230812180334310

  • 函数可以返回函数作为结果

Lambda函数
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)
Map函数(Map-Reduce)
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))

将复杂问题分解为可管理的部分,然后将这些部分组合在一起,以创建一个整体的解决方案。这种方式有助于减少复杂性,提高代码的可读性、可维护性和可扩展性,是现代软件开发的一个重要原则。

image-20230816143403597

内部函数
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
>>>

嵌套作用域:外部函数定义的变量

image-20230816143732419

闭包

  • 内部函数称为“闭包”
  • 闭包是一种机制,允许函数保留它需要的所有变量的值,以确保在稍后的运行中能够正常工作
>>> 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
  • Alternate evaluation (e.g., "delayed evaluation): 这是闭包的一种常见用法。通过闭包,可以实现“延迟评估”,即推迟某些操作的执行,直到需要的时候再进行计算。这对于性能优化和避免不必要的计算很有帮助。
  • Callback functions: 回调函数是闭包的另一个典型用例。在编程中,回调函数是一种通过将函数作为参数传递给其他函数来实现的机制。闭包可以让回调函数捕获它们被定义时的上下文,以便在稍后的某个时间点执行。
  • Code creation (“macros”): 闭包还可以用于动态地创建代码,这就是所谓的“代码生成”或“宏”。通过闭包,可以在运行时生成函数或代码块,并在需要的地方调用。这对于在运行时根据不同条件生成代码非常有用。

错误处理

捕获运行过程异常
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
自定义异常

image-20230816145139346

日志记录

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 中流行的一个第三方测试框架,它提供了更简洁的语法和丰富的功能,可以减少测试代码的复杂性。相比 unittestpytest 的语法更加简洁直观,并且它具有丰富的插件系统和灵活的配置选项,使得测试更加方便。

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')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值