函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的。编程中的函数在英文中也有很多不同的叫法。
在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
函数能提高应用的模块性,和代码的重复利用率。Python提供了许多内建函数,比如print()。但我们也可以自己创建函数,这些函数叫做用户自定义函数。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
一 函数的作用
1.减少重复代码
2.方便修改,更易扩展
3.保持代码的一致性
二 函数的创建
def 函数名(参数列表):
函数体
• 例子:
def printOK():
print(‘ok‘)
printOK()#ok 函数的调用一定记得加括号---函数名()
函数名的命名规则:
• 函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合。不能使用任何的标点符号;
• 函数名是区分大小写的。
• 函数名不能是保留字。
函数的参数: 形参和实参
形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参
区别:形参是虚拟的,不占用内存空间,形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据传送单向,实参传给形参,不能形参传给实参
def add(x,y): #x,y为形参, ,传入实参时必须一一对应
print(x+y)
add(4,5) #4,5为实参 按顺序对应x=4,y=5
add(7,8) #7,8为实参
def f(index): #index为形参
print(‘function%s‘%index)
f(3) #function3,3为实参
f(5) #function5,7为实参
f(4,5) #TypeError:f()takes1positionalargumentbut2weregiven, 因为函数只有一个形参,所以在调用函数时只能带入一个实参
import time#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 endaction %s\n‘%(time_current,n))
def action1(n):
print(‘startingaction1‘)
logger(n)
def action2(n):
print(‘startingaction2‘)
logger(n)#函数的调用
action1(‘one‘)#startingaction1
action2(‘two‘)#startingaction2
#文件"日志记录"的内容
#2020-03-12 22:27:05 endaction one
#2020-03-12 22:27:05 endaction two
函数的参数分类
• 必备参数
• 关键字参数
• 默认参数
• 不定长参数
参数排列顺序: 必备参数>关键字参数>默认参数>*args>**kwargs e.g. def func(name, age=22,*args,**kwargs)
关于不定长参数的位置:*args放在左边,**kwargs参数放在右边,如果有默认参数, 放到*args左边
#--------------------------------------------------------------------------------
def print_info(name, age): #必需参数 name, age, 必需参数在形参里加
print(‘Name is: %s; Age is :%d‘%(name,age))
print_info(‘xiaohu‘,48) #Name is: xiaohu; Age is :48
#print_info(46,‘xiaohu‘)#TypeError: %d format: a number is required, not str
print_info(age=46,name=‘xiaohu‘)#Name is: xiaohu; Age is :46 #关键字参数在实参里面加
#--------------------------------------------------------------------------------
def print_info(name, age, sex=‘male‘): #sex=‘male‘ 在这儿为默认参数, 默认参数必需跟在其他参数之后
print(‘Name is: %s; Age is :%d: sex is: %s‘%(name,age,sex))
print_info(‘xiaohu‘,40,‘male‘)
#Name is: xiaohu; Age is :40: sex is: male
print_info(‘tata‘,66)#未指明性别时,则默认为male
#Name is: tata; Age is :66: sex is: male
print_info(‘chacha‘,12,‘female‘)#性别指明时,则取指明的性别
#Name is: chacha; Age is :12: sex is: female
def print_info1(sex=‘male‘,name, age): #sex=‘male‘ 在这儿为默认参数, 默认参数必需跟在其他参数之后
print(‘Name is: %s; Age is :%d: sex is: %s‘%(name,age,sex))
#SyntaxError: invalid character in identifier
print_info1(name=‘chacha‘,age=12)
#--------------------------------------------------------------------------------
#low 加法器
def add(x,y,z):
print(x+y+z)
add(1,2,5) #8
#--------------------------------------------------------------------------------
高大上版本加法器
def add(*args):
print(args)
add(1,2,45)#(1, 2, 45)参数在一个元组里
def add(*args):#不一定要写成args #不定长参数 #无命名不定长参数, 存成元组
print(args)
sum=0
for i in args: #args =(1,2,3,4)
sum+=i #sum=sum+i
print(sum)
add(1, 2, 3,4)#10
#--------------------------------------------------------------------------------
def print_info(name, age, sex): #sex=‘male‘ 在这儿为默认参数, 默认参数必需跟在必备参数之后
print(‘Name is: %s; Age is :%d: sex is: %s‘%(name,age,sex))
#print_info(‘alex‘, 18, ‘male‘,job=‘IT‘)#TypeError: print_info() got an unexpected keyword argument ‘job‘
#--------------------------------------------------------------------------------
def print_info(*args, **kwargs):##*args不定长参数, 存成字典 #**kwargs为“命名不定长参数”, 存成字典
print(args)
print(kwargs)
print_info(‘alex‘, 18, ‘male‘,job=‘IT‘, hobby=‘eat‘)
#(‘alex‘, 18, ‘male‘)
#{‘job‘: ‘IT‘, ‘hobby‘: ‘eat‘}
#--------------------------------------------------------------------------------
关于不定长参数的位置一定要先放无命名,再放有名
def print_info(*args, **kwargs):##*args不定长参数存成元组 #**kwargs 有名不定长参数, 存成字典,
print(args)
print(kwargs)
for i in kwargs:
#print(i)#字典的键
print(‘%s:%s‘%(i,kwargs[i]))
print_info(job=‘IT‘, hobby=‘eat‘)
#{job:‘IT;hobby:eat}
#job:‘IT‘
#hobby:eat
#--------------------------------------------------------------------------------
def f(*args,**kwargs):
pass
f(1,2,‘34‘,[123,4], name=‘Liao‘,age=23)#1,2,‘34‘,[123,4] 由*args接受,name=‘Liao‘,age=23 由**kwargs接收
#--------------------------------------------------------------------------------
def print_info(*args, **kwargs):
for i in kwargs:
print(‘%s:%s‘%(i,kwargs[i]))
print_info(‘alex‘,18,hobby=‘girl‘,nationality=‘Chinese‘,ability=‘Python‘) #正常 hobby:girl, nationality:Chinese,ability:Pythin
# #print_info(hobby=‘girl‘,‘alex‘,18,nationality=‘Chinese‘,ability=‘Python‘) #报错 #SyntaxError: positional argument follows keyword argument关于不定长参数的位置一定要先放无命名,再放有名
# #print_info(‘alex‘,hobby=‘girl‘,18,nationality=‘Chinese‘,ability=‘Python‘) #报错 #SyntaxError: positional argument follows keyword argument关于不定长参数的位置一定要先放无命名,再放有名
#--------------------------------------------------------------------------------
def print_info(sex=‘female‘,*args, **kwargs):
print(sex)
print(args)
print(kwargs)
print_info()#female,#(),#{}
print_info(‘male‘,1,2,34)
# male
# (1, 2, 34)
# {}
print_info(1,2,34,‘male‘)
# 1 #1传给了sex
# (2, 34, ‘male‘)
# {}
print_info(1,2,34,‘male‘, name=‘hello‘)
# 1
# (2, 34, ‘male‘)
# {‘name‘: ‘hello‘}
四 函数的返回值
# 要想获取函数的执行结果,就可以用return语句把结果返回
# 注意:
# 1. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
# 2. 如果未在函数中指定return,那这个函数的返回值为None
# 3. return多个对象时,解释器会把这多个对象组装成一个元组作为一个整体结果输出。
def f():
print(‘ok‘)
return 10 #如果没有加return, 默认返回None, return作用:1.结束函数,2返回某个对象
print(‘alex‘)#不会报错, 但也不会执行,因为return语句已经结束函数
#返回什么内容,又给谁呢
a=f()
print(a)#跟print(f())一样
# ok
# 10
#高大上版本加法器
def add(*args):#不一定要写成args #不定长参数 #无命名不定长参数, 存成元组
print(args)
Sum=0
for i in args:#args =(1,2,3,4)
Sum+=i#Sum=Sum+i
print(Sum)
return(Sum)
a=add(1, 2, 3,4)
print(a)
# (1, 2, 3, 4)#print(args)
# 10#print(Sum)
# 10#return(Sum)
def foo():
return 1,‘123‘,8
print(foo())#(1, ‘123‘, 8)
# 注意点:
# 1, 函数里如果没有return,会默认返回一个None
# 2, 如果return多个对象,那么python会帮我们把多个对象封装成一个元祖返回
五 函数的作用域
python中的作用域分4种情况:
• L:local,局部作用域,即函数中定义的变量;
• E: enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
• G:global,全局变量,就是模块级别定义的变量;
• B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB
# if True:
# x=3
# print(x)#3 if 没有作用域
#
# def f():
# a=10
# f()
# print(a)#NameError: name ‘a‘ is not defined #函数有自己的作用域
#
#
# # python中的作用域分4种情况:
# # • L:local,局部作用域,即函数中定义的变量;
# # • E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
# # • G:global,全局变量,就是模块级别定义的变量;
# # • B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:
# # 作用域 局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
# x = int(2.9) #B-int built-in系统内部定义的方法
# g_count = 0 #global
# def outer():
# o_count = 1 # enclosing
# i_count =8
# def inner():
# i_count = 2 # local
# print(i_count)
# inner()
# outer()
# print(o_count) #找不到 NameError: name ‘o_count‘ is not defined
# count=10#全局变量Global
# def outer():
# print(count)
# count=5#报错, UnboundLocalError: local variable ‘count‘ referenced before assignment
# # 但是如果去掉上面一行print(count),或者把print(count)放到后面就不会报错,要先定义再调用,再在内部函数中对该变量做改动,python则认为这是在内部函数新建了一个变量。
# # 该变量的改动不会影响到全局变量, 全局变量remains unchanged
# outer()
# print(count)
# x=6
# def f2():
# print(x)
# x=5
# f2()
#
# # 错误的原因在于print(x)时,解释器会在局部作用域找,会找到x=5(函数已经加载到内存),但x使用在声明前了,所以报错:
# # local variable ‘x‘ referenced before assignment.如何证明找到了x=5呢?简单:注释掉x=5,x=6
# # 报错为:name ‘x‘ is not defined
# #同理
# x=6
# def f2():
# x+=1 #local variable ‘x‘ referenced before assignment.
# f2()
# count=10#全局变量Global
# def outer():
# global count #声明在该函数中此变量为全局变量
# print(count) #10
# count=5
# print(count)#5
# outer()
# count=0
# def outer():
# count = 10#enclosing 嵌套变量
# def inner():
# nonlocal count #声明在该函数中此变量为嵌套变量
# count = 20
# print(count)#20
# inner()
# print(count)#20
# outer()
# 变量作用域小结:
# 1.变量查找顺序, LEGB, local>enclosing>global>built-in
# 2.在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的
# 3.对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量
# 4.内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。
# nonlocal是python3新增的关键字,有了这个关键字,就能完美实现闭包
---------------------------
#如何将列表作为未命名参数传入
def f(*args):
print(args)
f(*[1,2,3])#(1, 2, 3)
f(*[1,2,3],*[4,5,6])#(1, 2, 3, 4, 5, 6)
#如何将字典作为有命名参数传入
def f2(**kwargs):
print(kwargs)
f2(name=‘alex‘,age=‘19‘)#{‘name‘: ‘alex‘, ‘age‘: ‘19‘}
f2(**{‘name‘:‘alex‘})#{‘name‘: ‘alex‘}
f2(**{‘name‘:‘alex‘,‘age‘:‘19‘})#{‘name‘: ‘alex‘, ‘age‘: ‘19‘}
六 高级函数
#高阶函数
def f(n):
return n*n
print(f(2))#4
def foo(a,b,func):
return func(a)+func(b)
print(foo(1,3,f))#10
def f():
print(‘ok‘)
#函数名可以进行复制,因为它也是一个变量
#函数名是变量,所以函数名也可以作为函数的参数,还可以作为函数的返回值
foo=f
print(foo)#<function f at 0x0000022524101B70>
foo()#ok
def bar(a,b,func):
func()
return 1
bar(1,2,f)
def foo2():
x=5
return x
print(foo2())#5
def foo3():
def inner(): #函数在定义时写入内存
return 8
return inner()
print(foo3())#8
def foo4():
def inner():
return 8
return inner
print(foo4())#<function foo4.<locals>.inner at 0x000001A19FCA1F28>
print((foo4())())#8
七 递归函数
递归函数的优点: 是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返 回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
阶乘 !5=5*4*3*2*1 = 120
##我的 用循环:
def f(final):
final_end = final
#print(final)#2
while final>1:
final=final-1
final_end *= final
return final_end
#print(f(2))
print(f(7))
老师的 用循环:
def fat(n):
ret=1
for i in range(1,n+1):#range() 包前不包后
ret=ret*i #fat(5)=5*4*3*2*1
return ret
print(fat(5))
递归函数
递归函数的特性
1. 函数内部自己调用自身函数
2. 有一个结束条件
递归函数的特点:
但凡是递归可以的, 循环都可以解决
递归的效率在很多时候都比较低
递归例子1, 阶乘
def fact(n):
if n==1: #结束条件
return 1
return n*fact(n-1) #调用自己 n*(n-1)*(n-2)*...*1
print(fact(5))
递归例子2, 斐波那契数列
0,1,1,2,3,5,8,13,21,34,55,89
n=(n-1)+(n-2)
def fibo(n):
if n<=2:
return n #fibo(1)+fibo(0)被省略
return fibo(n-1)+fibo(n-2)
print(fibo(8))
def fibo(n):
if n==0 or n==1:
return n #fibo(1)+fibo(0)被省略 return 结束函数
return fibo(n-1)+fibo(n-2)
print(fibo(8))
八 内置函数(Py3.5)
py内置函数:https://docs.python.org/3.5/library/functions.html#repr
Built-in Functions
abs()
dict()创建字典
help()
min()
setattr()
all() 检测参数是否都非空
dir()
hex()
next()
slice()
any()
divmod()求余
id()
object()
sorted()
ascii()
enumerate()添加序号
input()
oct()
staticmethod()
bin()
eval()从字符串转到字典, 计算器功能
int()
open()
str()
bool()
exec()
isinstance()
ord()
sum()
bytearray()
filter()
issubclass()
pow()
super()
bytes()
float()
iter()
print()
tuple()
callable()
format()
len()长度
property()
type()
chr()
frozenset()不可变集合
list()生成列表
range()
vars()
classmethod()
getattr()
locals()
repr()
zip()
compile()
globals()
map()
reversed()
__import__()
complex()
hasattr()
max()
round()
delattr()
hash()
memoryview()
set()可变集合
print(all((1,2,3,4,‘‘,5)))#False 判断参数是否都为非空, 都为非空返回True, 有空值返回 False
print(eval(‘1+2+3*4‘))#15
filter(function, sequence) #第一个参数为函数名,第二个参数为一个序列
str = [‘a‘, ‘b‘,‘c‘, ‘d‘]
def fun1(s):
if s != ‘a‘:
return s
ret = filter(fun1, str)
print(type(ret))#<class ‘filter‘>
print(list(ret))# ret是一个迭代器对象 #[‘b‘, ‘c‘, ‘d‘]
#对sequence中的item依次执行function(item),将执行结果为True的item做成一个filter object的迭代器返回。可以看作是过滤函数。
#map(function, sequence)
str = [‘a‘, ‘b‘]
def fun2(s):
return s + "alvin"
ret = map(fun2, str)#注意filter()与map()的区别, 如果filter()的函数中没有过滤条件, 则sequence remains unchanged
print(ret)# map object的迭代器 <map object at 0x000002107EFE7438>
print(list(ret))# [‘aalvin‘, ‘balvin‘]
#对sequence中的item依次执行function(item),将执行结果组成一个map object迭代器返回.
#map也支持多个sequence,这就要求function也支持相应数量的参数输入:
#
# def add(x,y):
# return x+y
# print (list(map(add, range(10), range(10))))##[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# # reduce(function, sequence, starting_value)
from functools import reduce
def add1(x,y):
return x + y
print (reduce(add1, range(1, 10)))## 45 (注:1+2+...+9)reduce()的结果就是一个值
# reduce()实现过程:
# reduce(add1, range(1, 10))
# reduce(add1, [1,2,3,4,5,6,7,8,9])
# reduce(add1, [3,3,4,5,6,7,8,9])
# reduce(add1, [6,4,5,6,7,8,9])
# .........
# reduce(add1, 36,9)
print (reduce(add1, range(1, 101)))#5050
print (reduce(add1, range(1, 101), 20))## 5070 (注:1+2+...+99+20
#对sequence中的item顺序迭代调用function,如果有starting_value,还可以作为初始值调用.
#lambda 匿名函数
匿名函数的命名规则,用lamdba 关键字标识,冒号(:)左侧表示函数接收的参数(a,b) ,冒号(:)右侧表示函数的返回值(a+b)。
因为lamdba在创建时不需要命名,所以,叫匿名函数
普通函数与匿名函数的对比:
#普通函数
def add(a,b):
return a + b
print(add(2,3)
#匿名函数
add = lambda a,b : a + b
print(add(2,3))
拿着铲子的土豆-Python 函数
原文:https://www.cnblogs.com/cathecathcat/p/12535352.html