语言基础之:函数
函数
- 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
- 具有减少重复代码,使程序变的可扩展,易维护等特点
1 函数的定义规则
def new_function(x, y): # 此处x,y为形参
"The function definitions"
x + y
return x, y
def:定义函数的关键字
test:函数名
():"()"内定义形参
"":文档描述(建议为你的函数添加描述信息)
x + y:泛指代码块或程序处理逻辑
return:定义返回值
# 调用参数
new_function(1, 2) # 此处1,2为实参
- 默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
2 返回值return
- 作用:后续程序可能需要根据返回值结果进行下一步操作
def func1():
"""定义过程函数,0个返回值"""
print("定义过程函数,0个返回值")
def func2():
"""定义函数,1个返回值"""
print("定义函数,1个返回值")
return 0
def func3():
"""定义函数,多返回值"""
print("定义函数,多返回值")
return 1, 1.1, 'abc', ['a', 'b'], {'age': 1}, ('a', 'b'), func2, func2()
# 可以返回func2函数名称,返回的是函数内存地址,
# 可以返回func2()函数,返回的是func2()函数的返回值
x = func1()
y = func2()
z = func3()
print("定义过程函数,0个返回值:", x)
print("定义函数,1个返回值:", y)
print("定义函数,多返回值:", z)
总结:
- 返回值数=0:返回none
- 返回值数=1:返回object
- 返回值数>1:返回tuple(一个元组,return的多个值撞到一个元组中)
3 函数之间调用
- 函数之间调用,需要被调用的函数在调用函数之前。
import time
def logger():
"""logger被调用函数"""
time_format = "%Y-%m-%d %X"
time_current = time.strftime(time_format)
with open("testfile", "a") as f:
f.write("\n%s add" % time_current)
def test1():
"""第一次调用"""
print("this is test1")
logger()
def test2():
"""第二次调用"""
print("this is test2")
logger()
test1()
test2()
4 形参与实参
形参:
- 变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参: - 可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
4.1 含参数的函数
def func1(x, y, z):
print("x = ", x)
print("y = ", y)
print("z = ", z)
# 位置参数调用,与形参顺序一一对应
func1(1, 2, 3)
# 关键字调用,与形参顺序无关
func1(x=2, y=3, z=1)
# 关键字调用用位置参数调用同时存在,关键参数是不能写在位置参数前面的
func1(1, 2, z=3)
# func1(x=2, y=1, 3)
# SyntaxError: positional argument follows keyword argument
# func1(3, x=2, y=1)
# TypeError: func1() got multiple values for argument 'x'
4.2 *args
- 接受N个位置参数,转换成元组形式
def func1(*args):
print(args)
func1(1)
# 输出:(1,)
func1(1, 2, 3, 4)
# 输出:(1, 2, 3, 4)
# "*"表示args的参数不固定,可用其他变量名称替换,不建议
def func2(*x):
print(x)
func2(*['a', 2, 'c'])
# 输出:('a', 2, 'c')
def func3(x, *args):
print(x)
print(*args)
func3(1, 2, 3, 4, 5)
# 输出:1
# 输出:2 3 4 5
4.3 **kwargs
- 接受N个关键字参数,转换成字典的方式
def func1(**kwargs):
print(kwargs)
print(kwargs['语文'])
print(kwargs['数学'])
func1(语文=100, 数学=90, 英语=80)
func1(**{'语文': 100, '数学': 90, '英语': 80})
def func2(name, **kwargs):
print(name)
print(kwargs)
func2('carey', age=200, sex='m')
# 参数组一定要放在最后
def func3(name, age=18, **kwargs):
print(name)
print(age)
print(kwargs)
func3('carey', hobby='skateboard', age=200, sex='m')
4.4 多种实参,多种参数组
def func4(name, age=18, *args, **kwargs):
print(name)
print(age)
print(args)
print(kwargs)
func4('carey', 13, 'a', 'b', 'c', hobby='skateboard', sex='m')
5 局部变量与全局变量
name1 = 'carey' # name1便是该函数的全局变量
def change_name(name):
"""change name"""
print("before change:", name)
name = "fan" # 这个函数就是"name"的变量的作用域
print("after change:", name)
global name2 # 在函数内写全局变量,不要用!了解就好
name2 = 'fan_carey2'
print("global name2", name2)
name3 = 'f_carey3'
change_name(name1)
# 输出:before change: carey
# after change: fan
# global name2 fan_carey2
print("函数之外的name1:", name1)
# 输出:函数之外的name1: carey
print("global name2:", name2)
# 输出:global name2: fan_carey2
print("函数之内的name3:", name3)
# 输出:NameError: name 'name3' is not defined
- 列表在函数中修改变量后,全局也发生改变
# 列表在函数中修改变量后,全局也发生改变
# 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
# 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
list1 = ["a", "b", "c"]
def change_list():
list1[0] = "abc"
print("inside list1:", list1)
change_list()
print("outside list1: ", list1)
6 递归
- 函数在内部调用自身本身,这个函数就是递归函数。
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
python 中最大递归次数为999
def calc1(n):
print(n)
return calc1(n+1)
calc1(0)
** 实例**
def calc2(n):
print(n)
if int(n/2) > 0:
return calc2(int(n/2))
print("-->", n)
calc2(10)
7 函数、函数式编程、高阶函数
- 面向对象:特点:类(class)
- 面向过程:过程(def)
- 函数式编程:函数(def)
7.1 函数和过程
# 定义函数
def func1():
"""定义函数"""
print("this is function1. ")
return 0
# 定义过程
def func2():
"""定义面向过程函数"""
print("this is function2")
# 调用定义函数
x = func1()
# 调用定义过程
y = func2()
print("func1.return:%s\nfunc2.return:%s" % (x, y))
# 输出
# this is function1.
# this is function2
# func1.return:0
# func2.return:None
过程和函数都可以调用,过程就是没有返回值的函数。
7.2 函数式编程
- 只要输入确定,输出也确定
一、定义
简单说,“函数式编程"是一种"编程范式”(programming paradigm),也就是如何编写程序的方法论。
主要思想是把运算过程尽量写成一系列嵌套的函数调用。
实例:
(1 + 2) * 3 - 4
传统的过程式编程,可能这样写:
var a = 1 + 2;
var b = a * 3;
var c = b - 4;
函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:
var result = subtract(multiply(add(1,2), 3), 4);
以上就是函数式编程,这段代码再演进以下,可以变成这样
add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:
merge([1,2],[3,4]).sort().search("2")
因此,函数式编程的代码更容易理解。
7.3 高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
(1)把函数作为实参
(2)把函数作为返回值
def add(a, b, f):
return f(a)+f(b)
res = add(-1, -2, abs)
print(res)