Python 函数
1.1 函数定义及作用
- 函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用;
- 函数的作用:
- 减少代码重复;
- 方便修改,更易扩展;
- 保持代码一致性;
# 函数定义:
# 函数名称命名规则:
# 可以由字母,下划线和数字组成
# 不能以数字开头
def 函数名():
函数封装的代码
# 函数注释:
# 在定义函数的下方,使用连续的三对引号
# 在函数调用的位置,使用"View -> Quick Documentation"可以查看函数的说明信息
# 由于函数体相对比较独立,函数定义的上方, 应该和其他代码(包括注释)保留两个空行
# 示例一: 日志记录
import time
def logger(n):
time_format = '%Y-%m-%d %X'
time_current = time.strftime(time_format)
with open('日志记录','a') as f:
f.write('%s end action %s\n' % (time_current, n))
def action1(n):
print('starting action1...')
logger(n)
def action2(n):
print('starting action2...')
logger(n)
def action3(n):
print('starting action3...')
logger(n)
action1(11)
action2(22)
action3(33)
1.2 函数的参数
- 必需参数
- 须以正确的顺序传入函数,调用时的数量必须和声明时的一样;
- 关键字参数
- 默认参数(缺省参数)
- 不定长参数
# 示例一: 必需参数
def f(name, age):
print('Name: %s' % name)
print('Age: %d' %age)
f('小虎',25)
f('小米', 32)
# 示例二: 关键字参数
def f(name, age):
print('Name: %s' % name)
print('Age: %d' % age)
f(age=28, name='小虎') # 注意,此处传入参数的顺序与函数定义时,不一致
# 示例三: 默认参数:
def f(name, age, gender='male'):
print('Name: %s' % name)
print('Age: %d' % age)
print('Gender: %s' % gender)
f('小虎', 26) # 其中,gender参数具有默认值,在调用函数时,可以不用赋值;
# 示例四: 不定长参数(*args)
# 计算传入参数的和
def add(*args):
print(args)
result = 0
for i in args:
result += i
print(result)
add(1, 2, 3, 4) # 输出: (1, 2, 3, 4), Python 将不定长参数封装成元组
# 示例五: 不定长参数(**kwargs)
def stu_info(name, age):
print('Name: %s' % name)
print('Age: %d' % age)
# 如果需要为 stu_info 增加参数,例如:
# stu_info(name, age, job)
# stu_info(name, age, job, hobby)
def stu_info(name, age, **kwargs):
print('Name: %s' % name)
print('Age: %d' % age)
print(kwargs)
# 此处,可以循环遍历字典
for i in kwargs:
print('%s : %s' %(i, kwargs[i]))
stu_info('小虎', 22, job='IT', hobby='football')
# 输出:
# Name: 小虎
# Age: 22
# {'job': 'IT', 'hobby': 'football'}
# Python 将 **kwargs 不定长参数封装成字典
# kwargs = keyword arguments
# 示例六: 不定长参数
def f(*args, **kwargs):
pass
# 备注:
# 关于不定长参数的位置: *args 放在左边, **kwargs 放在右边
# 如果参数中存在默认值的情况:
def stu_info(gender='male', *args, **kwargs):
print(args)
stu_info(2, 3, 4, 'female')
# 输出:
# (3, 4, 'female')
# 其中, 2 被赋值给了 gender
1.3 函数的返回值
- 如果未在函数中指定return, 那这个函数的返回值为None;
- 如果 return 多个对象,那么,Python 会帮我们把多个对象封装成一个元组返回;
# 示例一: 利用元组返回多个值
# 需求: 测量温度和湿度
def measure():
"""测量温度和湿度"""
print("测量开始...")
temp = 39
wetness = 35
print("测量结束...")
# 如果函数返回的类型是元组, 小括号可以省略
# return (temp,wetness)
return temp, wetness
result = measure()
print(result)
# 如果需要单独的处理温度或者湿度,可以使用多个变量, 一次接收函数的返回结果;
# 注意: 使用多个变量接收结果时, 变量的个数应该和元组中元素的个数保持一致;
gl_temp, gl_wetness = measure()
print(gl_temp)
print(gl_wetness)
# 示例二: 交换两个数字
# 要求: 1. 有两个整数变量 a = 6, b = 100
# 2. 不使用其他变量, 交换两个变量的值
# 方法一:
a = a + b
b = a - b
a = a - b
# 方法二: Python 专有, 利用元组
# a, b = (b, a)
a, b = b, a
1.4 作用域
- Python中的作用域分四种情况:
L
: local, 局部作用域, 即函数中定义的变量;E
: enclosing, 嵌套在父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;G
: global, 全局变量,就是模块级别定义的变量;B
: built-in, 系统固定模块里面的变量,比如 int, bytearray等。- 搜索变量的优先即顺序依次是: 局部作用域 > 外层作用域 > 当前模块中的全局作用域 > Python 内置作用域
即 LEGB
- 在Python中,只有模块(module), 类(class)以及函数(def, lambda)才会引入新的作用域,其他的代码块(例如
if, try, for等)是不会引入新的作用域的;
# 示例一:
x = int(2.9) # int built-in
g_count = 11 # global
def outer():
name = '小虎' # enclosing
def inner():
i = 4 # local
print(name)
# print(i) # 找不到
inner()
outer()
# 示例二:
count = 10
def outer():
count = 5
outer()
# 示例三:
count = 10
def outer():
print(count) # 注意,此处会报错,在赋值之前,使用局部变量
# count += 1 # 此处,也会报错
count = 5 # 此处,count 属于重新创建
outer()
# 示例四:
count = 10
def outer():
global count # 此处,标识 count 为全局变量
print(count)
count = 5
outer()
# 示例五:
def outer():
count = 10
def inner():
nonlocal count # 此处, count 为嵌套函数内变量, 使用 nonlocal 声明
count = 3
print(count)
inner()
print(count)
outer()
1.5 高阶函数
- 函数名可以作为参数输入;
- 函数名可以作为返回值;
# 示例:
def f(n):
return n * n
def foo(a, b, func):
ret = func(a) + func(b)
return ret
print(foo(1, 2, f)) # 注意,此处函数当作参数,传入另一函数内部的形式
# 备注:
# 1. 函数名可以进行赋值,函数名存储着函数对象在内存中的地址;
# 2. 函数名可以作为函数参数,还可以作为函数的返回值;
1.6 变量说明
- 在
Python
中,变量和数据是分开存储的; - 数据保存在内存中的一个位置;
- 变量中保存着数据在内存中的地址;
- 变量中记录数据的地址,叫做引用;
- 使用
id()
函数可以查看变量中保存数据所在的内存地址;
def test(num):
print("在函数内部 %d 对应的内存地址是 %d" % (num, id(num)))
a = 10
print("a 变量保存数据的内存地址是 %d" % id(a))
# 调用函数,本质上传递的是实参保存数据的引用, 而不是实参保存的数据
# 函数的返回值,本质上返回的是数据的引用,而不是数据本身
test(a)
1.7 递归函数
- 递归特性:
- 必须有一个明确的结束条件;
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少;
- 递归效率不高,递归层次过多会导致栈溢出;
# 示例一: 求 N 的阶乘
def fact(n):
if n==1:
return 1
return n*fact(n-1)
# 示例二: 斐波那契数列
def fibo_new(n):
if n <= 1:
return n
return fibo_new(n-1) + fibo_new(n-2)
print(fibo_new(10))
1.8 内置函数
filter()
: 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表;map()
: 会根据提供的函数对指定序列做映射;reduce()
: 会对参数序列中元素进行运算:- 用传给reduce中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
# 示例一: filter()
# 语法: filter(function, iterable)
# 其中,function 为判断函数, iterable 为可迭代对象
# 需求: 过滤出列表中的所有奇数
def is_odd(n):
return n % 2 == 1
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(newlist)
# 示例二: map()
# 语法: map(function, iterable, ...)
# python 2.x 返回列表, python 3.x 返回迭代器
# 需求: 计算平方数
def square(x):
return x ** 2
map(square, [1, 2, 3, 4, 5])
map(lambda x: x**2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
# 提供了两个列表, 对相同位置的列表数据进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
# 示例三: reduce()
# 语法: reduce(function, iterable[, initializer])
from functools import reduce # python3.x 使用之前,需要先导入模块
def add(x, y):
return x + y
reduce(add, [1, 2, 3, 4, 5]) # 计算列表的和: 1+2+3+4+5
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
1.9 匿名函数
- 匿名函数的命名规则:用lambda关键字标识,冒号(
:
)左侧表示函数接收的参数,右侧表示函数的返回值;
# 示例:
# 普通函数
def add(x, y):
return x + y
print add(2, 3)
# 匿名函数
add = lambda a, b : a + b
print add(2, 3)
参考资料: