Python函数总结
一、函数的基本用法
1、概念:
函数是对程序逻辑进行结构化或是过程化的一种编程方法,其是组织好的,可重复使用的,用来实现单一,或者相同功能的代码段。
函数提高了应用点的模块性和代码的重复利用率
本质:函数是对功能的封装
形式参数:简称形参,本质是一个没有值的变量 实际参数:简称实参,本质是常量,变量或者表达式 传参:实参给形参赋值的过程
而实参的类型取决于形参的需要
2、函数定义:
def 函数名(参数1,参数2,参数3.。。。):
函数体
return 返回值
注:a、函数命名遵循标识符规则,做到见名知意,小驼峰命名法、
b、参数1,参数2,参数3.....形式参数,不同的参数之间使用逗号隔开,参数的数量没有限制,依据具体的需求决定参数的数量
c、函数体:被封装的功能
d、return:结束函数,将返回值返回给调用者,也可单独使用
e、返回值可为常量、变量、表达式
3、返回值
返回值:表示一个函数执行完毕之后得到的结果
注:对于return语句不带参数,则返回一个None
4、调用
函数的调用:实质就是函数入栈出栈的过程
即:函数的入栈:函数被调用;函数的出栈:函数被调用完毕
注:在函数调用的过程要注意避免出现死循环
5、变量的作用域
变量的作用域:指变量可以被访问的范围
作用域的划分:
L:(local)局部作用域
E:(Enclosing)函数作用域(闭包)
G:(Global)全局作用域
B:(Built-in)内置作用域
变量的查找规则(变量重名):
python中变量的作用域由大到小,依次为内建(built_in B) >全局(glbal G)> 函数的闭包外(enclosing E)> 局部(local L)
注:在变量重名情况下在函数内部访问变量时使用就近原则。
如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉,此时我们就需要使用global或者nonlocal来声明变量了。
#1.变量不重名
num1 = 10 #全局作用域
def outer():
num2 = 20 #函数作用域
def inner():
num3 = 30 #局部作用域
print(num1,num2,num3)
return inner
f = outer()
f()
# global:全局的
# 全局变量
num1 = 4
def func1():
# 声明num1是全局变量的num1
global num1
print(num1) #4
num1 = 20
func1()
a = 10
def test():
global a
a = a + 1
print(a) #UnboundLocalError: local variable 'a' referenced before assignment
test()
# nonlocal:不是局部的
# nonlocal;前提条件:必须使用在闭包中
x = 0 # 全局作用域
def outer():
x = 1 # 函数作用域
def inner():
# 将一个局部作用域的变量声明为不是局部的,局部----》函数
nonlocal x
x = 2 #局部作用域
print("inner:",x)
#在外部函数中调用内部函数
nner()
print("outer:",x)
outer()
print("global:",x)
6、参数
1、参数的传递:
参数的传递有值传递和引用传递
值传递:传递不可变类型的数据,例:num、string、tuple等;在值传递时,形参的改变并不会影响实参
引用传递:传递可变类型的数据,例:list、dict、set等;形参的改变会影响实参的使用
在函数中参数传递的是对象的引用
#引用传递:传递列表或者字典时,如果改变引用的值,就修改了原始的对象
def check(l):
print(l)
print(id(l))
l.append([1, 23, 2, 3, 4])
return l
l = [1, 2, 3, 4]
print(check(l))
print(id(l))
'''
[1, 2, 3, 4]
2902500909320
[1, 2, 3, 4, [1, 23, 2, 3, 4]]
2902500909320
'''
#值传递:当传递不可变对象时,如果改变引用变量的值,只是创建了不同的对象,原始对象并没有改变。
def check(s):
print(s)
print(id(s))
s = "i am test"
print(id(s))
return s
s = "This is a test"
print(check(s))
print(s)
'''
This is a test
2418424029424
2418424029488
i am test
This is a test
2、参数的类型:
a、必须参数:必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
def printme( str ):
"打印任何传入的字符串"
print str
return
#调用printme函数
printme()
b、关键字参数:允许实参的顺序和形参的顺序不一致,因为Python解释器会根据关键字参数的名称自动的匹配
def show2(name,age):
print("name:%s age:%d" % (name,age))
show2(name="jack",age=47)
# 注:关键字参数使用在实参列表中,不要求顺序保持一致
show2(age=36,name="fadj")
# 注:在实参列表中,可以不全部设置为关键字参数
show2("zhangsan",age=15)
# 注:关键字参数只能出现在实参列表的后面
def show3(a,b,c):
print(a,b,c)
show3(1,4,4)
show3(a=3,c=5,b=5)
show3(45,b=9,c=18)
#show3(a=45,9,18) #SyntaxError: positional argument follows keyword argument
c、默认参数:调用函数的时候,如果没有传递参数,则使用默认值【default】
#注意1:默认参数体现在形参列表中
def func3(name="abc",age=18):
print("name:%s age:%d" % (name, age))
#注意2:使用了默认参数,则可以选择不传参,使用的默认值,如果传参,则相当于给形参重新赋值
func3()
func3("jack",19)
#注意3:关键字参数和默认参数可以结合使用
func3(name="jack",age=19)
func3("jack",age=19)
#注意4:形参列表可以不全部设置为默认参数,只要吃部分设置,则默认参数出现在形参列表的后面
#报错:SyntaxError: non-default argument follows default argument
# def show4(name="abc",age):
# print("name:%s age:%d" % (name, age))
# show4("bob",18)
print("hello")
d、不定长参数:可以处理比声明时更多的参数
#a.*,一般写法为*args
def text1(*num):
print(num)
for n in num:
print(n)
# *不定长参数被当做元组处理,num形参名其实就是元组名
text1(10)
text1(10,4,54,65,65,7)
# 可以传一个元组,但是,元组被当做一个整体全部传参
text1((54,4,64))
# 一般情况下,将不定长参数设置在形参列表的最后
def text2(*num3,num1,num2):
print(num1,num2,num3)
# 如果不定长参数出现在形参列表的前面或者中间,则可以借助于关键字参数传参
#text2(12,43,43)
text2(12,34,num1=35,num2=59)
# 在形参列表,不定长参数最好只出现一个
#错误演示
# def text3(*num3,num2,*num1):
# print(num1,num2,num3)
# text3(43,53,num2=10,5,5,4)
#b.**,一般写法为**kwargs
def text4(**num3):
print(num3)
#注意1:**,被当做字典处理,传参的时候,需要以key=value的方式进行传参
text4(x=26,y=17)
#注意2:在形参列表中使用**,保证出现在后面
"""
使用场景:单例设计模式
def text(*args,**kwargs):
总结:
a.必需参数使用最多,其次是不定长参数
b.关键字参数和默认参数最多使用在系统函数中
"""
7、匿名函数
lambda表达式:python中的匿名函数主要用来处理一些简单逻辑表达式的封装,使用lambda关键字
优点:不占用内存,提高代码的运行速度
一般格式为:
var = lambda args:表达式
例如:
f = lambda x,y:x+y
#该函数的调用结果为 冒号后的表达式所表达的结果
print(f(1,2))
二、函数进阶
1、概念【特殊用法】:
1、变量可以指向函数
x = abs(-35)
print(x) # 35
# 一个普通的变量可以指向一个函数,该变量就可以被当做函数调用
f = abs
print(f)
print(f(-100))
def check():
print("check")
check()
f1 = check
f1()
2、函数也可以作为变量名
# 本质:函数名就是一个指向函数的变量
print(abs(-28))
# abs = "hello"
# print(abs(-7))
3、函数作为参数使用
# 调用形参中的函数,必须和原函数保持一致【注意是否需要传递参数】
def test(a,b,fun):
return fun(a) + fun(b) #abs(43) + abs(-27)
print(test(43,-27,abs)) #fun = abs
def test1(s1,s2,func):
return func(s1) + func(s2)
print(test1("hello","gajghj",len))
2、闭包:
在函数内部定义了另一个函数,即存在外部函数和内部函数
闭包【closure】:在外部函数中定义一个内部函数,并且外部函数的返回值是内部函数的引用。
# 普通函数
def show():
print("1111")
return num1
# 闭包
def outter():
def inner():
print("inner")
return inner
f = outter() #f = inner
f()
# 在闭包设置参数,a和b两个变量被称为自由变量【临时变量】
# 闭包的优点:在外部函数中定义的变量,在内部函数可以直接访问
def outer1(a):
b = 10
def inner1():
print(a + b)
return inner1
f1 = outer1(23) #f1 = inner1
f1()
# 内部函数设置参数
def outer2(a):
b = 10
def inner2(c):
print(a + b + c)
return inner2
f2 = outer2(23)
f2(12)
3、装饰器:
装饰器【Decorator】:使其他函数在不需要做任何代码的变动下,为函数添加功能,装饰器的返回值也是一个函数。
本质:装饰器的本质就是一个闭包,其作用是将一个函数作为参数,返回另一个函数
装饰器函数运行在函数定义的时候
装饰器需要返回一个可执行的对象
装饰器返回的可执行对象要兼容函数f的参数
import time
#1.简单的装饰器
def test():
print("hello")
# func就是需要被装饰的函数
def outer(func):
def inner():
# 增加新功能
print("new~~~~")
# 调用原函数
func()
return inner
f1 = outer(test)
f1()
# 练习:书写装饰器,计算test函数执行的时间
def outer(func):
def inner():
t1 = time.time()
func()
t2 = time.time()
print(t2 - t1)
return inner
f1 = outer(test)
f1()
#2.带有参数的装饰器
def getAge(age):
print(age)
# getAge(10)
# getAge(-36)
# 注意:被装饰的函数有参数,inner不一定需要设置参数,只有当需要在inner内部对参数进行操作的时候,则需要同步
def wrapper1(func):
def inner(a):
#数据的校验
if a < 0:
a = -a
func(a)
return inner
f = wrapper1(getAge)
f(10)
f(-36)
# 使用装饰器语法糖
# 注意:使用@,必须保证装饰器存在的情况下,才能给函数增加功能
def wrapper2(func):
def inner(a):
# 数据的校验
if a < 0:
a = -a
func(a)
return inner
@wrapper2
def getAge1(age):
print(age)
getAge1(-19)
# 参数为不定长参数的装饰器
# 使用场景:一个装饰器可以同时作用于多个不同函数的情况
def wrapper3(func):
def inner(*args,**kwargs):
# 新增的功能
print("abc")
#调用原函数
func(*args,**kwargs)
return inner
@wrapper3
def test(a,b):
print(a,b)
test(10,20)
@wrapper3
def test1():
print("gsjrg")
test1()
# 多个装饰器作用于同一个函数
def wrapper11(func):
def inner(*args,**kwargs):
# 新增的功能
print("装饰器~~~~11")
# 调用原函数
func(*args,**kwargs)
return inner
def wrapper22(func):
def inner(*args,**kwargs):
# 新增的功能
print("装饰器~~~~22")
# 调用原函数
func(*args,**kwargs)
return inner
@wrapper11 # func:check
@wrapper22 # func:被wrapper11装饰之后的函数
def check():
print("check")
check()
#总结:多个装饰器作用于同一个函数的时候,从上往下依次执行,但是,原函数只被调用一次
4、偏函数
通过设定默认参数,可以降低调用的难度,偏函数也可以起到这样的作用
概念:对函数的参数做一些控制的函数
注意:偏函数一般不需要自己定义,直接使用【functools模块其中提供了偏函数的使用】
import functools
print(int("23534"))
# print(int("abc345")) #ValueError: invalid literal for int() with base 10: 'abc345'
# 在int中有一个默认参数base,用来指明当前数据的进制
print(int("110"))
print(int("110",base=10))
print(int("1010",base=2))
print(int("1010",2))
# 自定义一个函数,设置一个默认参数base,默认值设置为2
def int2(x,base=2):
return int(x,base)
print(int2("1010"))
print(int2("1010",10))
# 系统的functools模块中提供了偏函数的实现
# 参数:已经存在的函数名 默认参数
int3 = functools.partial(int,base=2)
print(int3("1110"))
print(int3("1110",base=10))
# 思想:根据一个已经存在的函数,通过修改该函数参数的默认值,生成一个新的函数,被称为偏函数
三、高阶函数
1、filter():过滤
"""
filter(function,iterable) 通过一定的条件过滤可迭代对象中的元素
工作原理:把传入的函数依次作用于可迭代对象的每一个元素,根据返回的布尔值【True或者False】决定是否保留元素
如果返回True,则表示需要保留该元素;如果返回False,则表示需要过滤掉该元素
"""
# 将列表中的偶数筛选出来
list1 = [1,2,3,4,5,6,7,8]
# 自定义【追加】
newList1 = []
for num in list1:
if num % 2 == 0:
newList1.append(num)
print(newList1)
# 自定义【删除】
newList2 = list1.copy()
for num in newList2:
if num % 2 == 1:
newList2.remove(num)
print(newList2)
#方式三:列表生成式
newList3 = [num for num in list1 if num % 2 == 0]
print(newList3)
# filter
def func(num):
# 保留偶数元素
if num % 2 == 0:
return True
# 过滤奇数元素
return False
newList4 = list(filter(func,list1))
print(newList4)
# 将爱好为"无"的数据剔除掉
data = [['姓名', '爱好', '年龄'],['tom', '无', 10],['jack', '唱歌', 28]]
def func2(s):
if s == "无":
return False
return True
for line in data:
result = list(filter(func2,line))
print(result)
2、map():映射
"""
map(function,Iterable) 会根据的函数对指定的序列做出映射
function:函数
iterable:可迭代对象,序列
工作原理:函数会以序列中的每一个元素作为参数,返回包含函数的功能的新列表
功能:将传入的函数依次作用于序列中的每一个元素,并把结果作为新的iterable返回
"""
# 计算列表中各个元素的平方
list1 = [1,2,3,4,5]
# 自定义
newList1 = []
for num in list1:
newList1.append(num ** 2)
print(newList1)
# 列表生成式
newList2 = [num ** 2 for num in list1]
print(newList2)
# 生成器
newList3 = list((num ** 2 for num in list1))
print(newList3)
# map[def定义的函数]
def func(x):
return x ** 2
result = map(func,list1)
print(result)
print(type(result))
newList4 = list(result)
print(newList4)
"""
传给map的函数的要求:
a.参数只能有一个【默认将可迭代对象的一个元素传递给该函数】
b.该函数必须有返回值,否则得到的可迭代对象中的元素为None
"""
#方式五:map[匿名函数]
newList5 = list(map(lambda x:x ** 2,list1))
print(newList5)
# 已知有一个整数列表,将转换为字符串列表
#例如:[2,3,4,5]------>['2','3','4','5'] str()
list2 = [2,3,4,5]
newL1 = []
for num in list2:
newL1.append(str(num))
print(newL1)
newL2 = [str(num) for num in list2]
newL3 = list((str(num) for num in list2))
newL4 = list(map(str,list2))
print(newL4)
reduce():迭代【累积】
from functools import reduce
"""
导入模块:functools
reduce(function,iterable):函数会对序列中的元素进行累积
功能:用传给reduce的函数先序列中的第1,2个元素进行操作,
用得到的结果和第3个元素进行操作,用得到的结果和第4个元素进行操作。。。。
举例:
f,[a,b,c,d]
reduce(f,[a,b,c,d])
工作原理:f(f(f(a,b),c),d),类似于递归
"""
# 计算一个整数列表中元素的和
# 一:自定义
list1 = [1,2,3,4,5]
total = 0
for num in list1:
total += num
print(total)
# 二:reduce【def定义函数】
def mySum(x,y):
return x + y
result0 = reduce(mySum,list1)
print(result0)
"""
mySum(1,2)---->3
mySum(3,3)---->6
mySum(6,4)---->10
mySum(10,5)---->15
"""
# 三:reduce[匿名函数]
result1 = reduce(lambda x,y:x + y,list1)
print(result1)
"""
函数的注意事项:
a.必须有两个参数
b.必须设置返回值【报错:TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'】
"""
# 将[1,3,5,7,9]转换为整数13579
list2 = [1,3,5,7,9]
def func(x,y):
return x * 10 + y
result3 = reduce(func,list2)
print(result3)
# 自定义一个函数,实现str转换为int的函数 int(xx)
def charToNum(s):
# 自定义字符串和整型之间的映射关系
digits = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6}
return digits[s]
# 需求:“24356”------》24356
# a.产生映射关系
r0 = list(map(charToNum,"24356"))
print(r0)
#b.使用reduce累积
r1 = reduce(func,r0)
print(r1)
print(type(r1))
r2 = reduce(func,map(charToNum,"23456"))
print(r2)