当前位置: 首页 > news >正文

「Python 基础」函数与高阶函数

文章目录

    • 1. 函数
      • 调用函数
      • 定义函数
      • 函数的参数
      • 递归函数
    • 2. 高阶函数
      • map/reduce
      • filter
      • sorted
    • 3. 函数式编程
      • 返回函数
      • 匿名函数
      • 装饰器
      • 偏函数

1. 函数

函数是一种重复代码的抽象方式,Python 内建支持的一种封装;

调用函数

调用一个函数,需要知道函数的名称和参数;函数名是只想一个函数对象的引用

>>> a = abs
>>> a(-1)
1

可以在交互式命令行通过 help(abs) 查看 abs 函数的帮助信息;

数据类型转换

>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False

开平方

# 方法一
>>> import math
>>> math.sqrt(100)
10.0# 方法二
>>> pow(100, 0.5)
10.0# 方法三
>>> 100 ** 0.5
10.0

定义函数

定义一个函数要使用 def 语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。

如果没有 return 语句,函数执行完毕后也会返回结果,只是结果为 None。return None 可以简写为 return。

空函数

定义一个什么事也不做的空函数,可以用 pass 来作为占位符

参数检查

调用函数时,如果参数个数不对,Python 解释器会自动检查出来,并抛出 TypeError

返回多个值

Python 的函数返回多值其实就是返回一个 tuple;在语法上,返回一个 tuple 可以省略括号,而多个变量可以同时接收一个 tuple,按位置赋给对应的值

函数的参数

参数类型说明
位置参数def power(x, n): 传入的值依次赋给对应位置的参数
默认参数def power(x, n=2): 在调用时可以不用输入该位置的参数,而直接使用默认值;变化大的参数放在前,变化小的放在后作为默认参数,降低调用难度;调用含多个默认参数的函数时,可以写上参数名;如调用 def enroll(name, gender, age=6, city='Beiging'): 可以用enroll('Adam', 'M', city='Tianjin')
可变参数def calc(*numbers): 传入的参数个数时可变的,在参数前面加 1 个 * 号,参数接收到的将是一个 tuple;在 tuple/list 前加 1 个 *,可以将其以可变参数传入函数 calc(*[1,2,3])
关键字参数def person(name, age, **kw): 同理可变参数,在参数前面加 2 个_号,允许传入 0 个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict;在 dict前加 2 个_ 可以将其以关键字参数传入函数 person(name, age, **kw)
命名关键字参数def person(name, age, *, city, job): 如果要限制关键字参数的名字,可以用命名关键字参数;命名参数需要以 * 分隔,其后视为命名关键字参数,如果函数定义了一个可变参数,可以不要 *,命名关键字参数可以给默认值

默认参数必须只想不可变对象
不可变对象减少了由于修改数据导致的错误,多任务环境同时读取不需加锁

# 错误写法
>>> def add_end(L=[]):
...     L.append('End')
...     return L
...
>>> add_end()
['End']
>>> add_end()
['End', 'End']

参数组合

顺序:必选参数 > 默认参数 > 可变参数 > 命名关键字参数 > 关键字参数

递归函数

一个函数在内部调用自己本身,就叫递归函数

函数调用是通过栈实现的,每进入一个函数调用,加一层栈锁,过多时会栈溢出

尾递归

把每一步的结果传递给递归函数,和循环的效果一样,栈不会增加;python 解释器没有对尾递归做优化,会栈溢出

汉诺塔

def move(n, a, b, c):if n == 1:print(a, '->', c)else:move(n-1, a, c, b)move(1, a, b, c)move(n-1, b, a, c)

2. 高阶函数

Higher-order function

变量可以指向函数 and 函数名也是变量 -> 函数可以接收另一个函数作为参数

其参数能够接收别的函数的函数,就是高阶函数

map/reduce

map()

接收两个参数,一个是函数(单个参数),一个是 Iterable 对象,map 将传入的函数依次作用在 Iterable 对象的每一个元素上,并把结果作为一个新的 Iterator 返回,注意 Iterator 是惰性的

>>> list(map(str, [1, 2, 3, 4, 5]))
['1', '2', '3', '4', '5']

reduce()

把一个函数(必须是两个参数)作用在一个序列上,reduce 把结果与下个元素做累计计算

reuce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# str2int
from functools import reduceDIGITS = {'0': 0,'1': 1,'2': 2,'3': 3,'4': 4,'5': 5,'6': 6,'7': 7,'8': 8,'9': 9
}def char2num(c):return DIGITS[c]def str2int(s):return reduce(lambda x1, x2: x1 * 10 + x2, map(char2num, s))
# str2float
from functools import reduceDIGITS = {'0': 0,'1': 1,'2': 2,'3': 3,'4': 4,'5': 5,'6': 6,'7': 7,'8': 8,'9': 9
}def char2num(c):return DIGITS[c]def str2int(s):return reduce(lambda x1, x2: x1 * 10 + x2,map(char2num, [c for c in s if c != '.']))def str2float(s):return str2int(s) / (10**s[::-1].index('.'))
# str2float
def str2float(s):point = 0def to_float(i, c):nonlocal pointif not isinstance(c, int):point = 1return iif point == 0:return i * 10 + celse:point *= 10return i + c / pointreturn reduce(to_float, map(char2num, s))

nonlocal 关键字用来在函数或其他作用域使用外层(非全局)变量

filter

接收一个函数(单个参数)和一个序列,序列的每个元素作用于函数,返回 True/False 决定是否保留该元素

素数 - 埃氏筛选

def _odd_iter():n = 1while True:n += 2yield ndef _not_divisible(n):return lambda x: x % n > 0def primes():yield 2oi = _odd_iter()while True:n = next(oi)yield noi = filter(_not_divisible(n), oi)

sorted

接收一个 Iterable 对象,一个函数(形参:key,一个参数的函数),以及 reverse;key 作用与序列的每个元素,再对结果排序,reverse 表示是否反向排序,默认为 False

3. 函数式编程

面向过程程序设计

通过一层一层的函数调用,把复杂的任务分解成简单任务,这种分解称之为面向过程的程序设计,函数是面向过程编程的基本单元

Functional Programming

一种抽象程度很高的编程范式,纯粹的函数式编程语言(Lisp)编写的函数没有变量,只要输入确定,输出就是确定的(没有副作用)。允许使用变量的函数内部变量状态不确定,同样输入可能输出不同

Python 对函数式编程提供部分支持,其允许使用变量,不是纯函数式编程语言

返回函数

函数作为返回值
往往不需要立即执行的时候,可以使用返回函数的方式达到惰性计算的效果(lazy

闭包(Closure)
当返回函数时,相关参数和变量都保存在返回的函数中,这种程序结构成为闭包

def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fsf1, f2, f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

返回的函数引用了变量 i,但它并没有立刻执行,等到 3 个函数都返回时,它们引用的变量 i 已经变成了 3,因此最终结果都是 9

返回闭包时,返回函数不要引用任何循环变量,或者后续会发生变化的变量

def count():def f(j):def g():return j*jreturn gfs = []for i in range(1, 4):# f(i) 立即执行,因此 i 的当前值被传入 f()fs.append(f(i))return fs
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

添加多层函数,用执行外层函数将循环变量的值绑定到函数的参数中,可以绑定循环变量变化过程中的值

计数器(闭包)

def createCounter():def counter():n = 0while True:n += 1yield nc = counter()return lambda : next(c)
def createCounter():n = 0def counter():nonlocal nn += 1return nreturn counter

匿名函数

关键字 lambda 表示匿名函数,冒号前面的是参数表,冒号后面的是返回结果,不用写 return,只能有一个表达式

匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

>>> f = lambda x: x*x
>>> f(5)
25

也可以把匿名函数当作一个函数的返回值返回

def build(x, y):return lambda x, y: x*x + y*y

装饰器

Decorator

在函数调用前后自动增加处理,不修改函数的定义,这种在代码运行期间动态增加功能的方式,即为 Decorator

import functoolsdef log(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f'call {func.__name__}():')return func(*args, **kwargs)return wrapper
def log(info):def decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f'{info} {func.__name__}')return func(*args, **kwargs)return wrapperreturn decorator

调用 Decorator

@log
def now():print('2020-11-12')
now = log(now)
@log('execute')
def now():print('2020-11-12')
now = log('execute')(now)

functools.wraps(func) 的作用是将 wrapper 函数的 __name__ 改为被装饰函数对象的 __name__, 相当于:

wrapper.__name__ = func.__name__

Decorator 即在 面向对象(OOP)设计模式 中的 装饰模式,OOP 的装饰模式通过类的继承和组合实现,而 Python 可以直接从语法层面支持 decorator,也可以通过类实现

偏函数

Partial function

把一个函数的某些参数固定住(给这些参数设置默认值),返回一个新函数,以方便调用

偏函数仅仅是给参数设定了默认值,在调用新函数时是可以传入其他值给这些参数的

import functools
# 相当于
# kw = {'base': 2}
# int('1000000', **kw)
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1000000', base=10)
1000000
# 相当于
# args = [10]
# args.extend([5, 6, 7])
# max(*args)
>>> max2 = functools.partial(max, 10)
>>> max2(5, 6, 7)
10

创建偏函数时,实际接收的参数是:函数对象,*args / **kwargs


上一篇:「Python 基础」基础语法与高级特性
专栏:《Python 基础》

PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!

http://www.lryc.cn/news/31176.html

相关文章:

  • DIV内容滚动,文字符滚动标签marquee兼容稳定不卡
  • SpringBoot_第五章(Web和原理分析)
  • 4-2 Linux进程和内存概念
  • 【微信小程序】计算器案例
  • 408 计算机基础复试笔记 —— 更新中
  • 找出最大数-课后程序(Python程序开发案例教程-黑马程序员编著-第二章-课后作业)
  • Java——N叉树的层序遍历
  • 【Kubernetes】第十八篇 - k8s 服务发现简介
  • Codeforces Round 856 (Div. 2) 最好ak的div2
  • 最新JVM技术: GraalVM,让你一文了解它的方方面面
  • MySQL索引失效的场景
  • Java - 对象的比较
  • [算法]选择排序
  • dp模型——状态机模型C++详解
  • 1.4 条件概率与乘法公式
  • VITA/PYTHON/LUPA families
  • ChatGPT概述:从模型训练到基本应用的介绍
  • C语言实现扫雷【详细讲解+全部源码】
  • Vue2.0开发之——购物车案例-Goods组件封装-商品名称和图片(46)
  • 0201基础-组件-React
  • 论文笔记 | Conducting research in marketing with quasi-experiments
  • 有关Android导览(Android Navigation component)
  • 01 C语言计算
  • java单元测试简介(基于SpringBoot)
  • Linux常用命令操作
  • SpringCloud GateWay配置—TLS 和 SSL、Http超时配置
  • python Django中的cookies和session会话保持技术
  • vue3的v-model指令
  • Matlab小波去噪——基于wden函数的去噪分析
  • 分布式对象存储——Apache Hadoop Ozone