函数的基本使用
函数的参数
1,函数的使用
"""
1 什么是函数
函数是盛放功能的容器,说白了,把实现某一功能的一组代码
扔到一个函数中,就做成了一个小工具,该工具可以重复使用
实现某一功能的工具-》函数
事先准备工具的过程-》函数的定义
遇到应用场景拿来就用-》函数的调用
2 为何要用函数
没有用函数前,程序存在的问题有
1、代码冗余、程序的组织结构不清晰、可读性差
2、可扩展性差
3 如何用函数
原则:先定义、后调用
"""
一 定义函数的语法
def 函数名(参数1,参数2,参数3,...):
"""函数注释"""
代码1
代码2
代码3
return 返回值
def haha():
print('*' * 10)
print('hello world'.center(10,' '))
print('*' * 10)
# 打印haha这个函数的内存地址
print(haha)
# <function haha at 0x1009b61f0>
# 调用函数haha
haha()
# **********
# hello world
# **********
PS:
只有函数才能调用!!!
# 会报错
x=10
x()
# x()
# TypeError: 'int' object is not callable
2,定义与调用之间的关系
def say():
print('*' * 20)
print('hello world'.center(20, ' '))
print('*' * 20
# 以上少了个括号,语法错误会报错
# SyntaxError: unexpected EOF while parsing
# 逻辑错误不会报错,age没有定义,加上引号才不会报错
def say():
print('*' * 20)
print('hello world'.center(20, ' '))
print('*' * 20)
print(age)
# 执行的时候会报错
say()
# NameError: name 'age' is not defined
#例1:
def hh():
aa()
print(11)
print(hh)
# <function hh at 0x1048b21f0>
hh()
#NameError: name 'aa' is not defined
总结:
# 以上aa()没有定义,打印hh这个函数额内存地址时候不会报错;只有在调用hh的时候才会报错
#例2
def hh():
aa()
print('x')
hh()
# 会报错,因为x没有定义,NameError: name 'aa' is not defined
#例3
def hh():
print('x')
x=3
hh()
#x
# 以上虽然 x=3没有在函数前定义,但是调用函数前是有x的定义的,所以不会报错
3,定义的3种格式
#示例:两值比较,获取大的数字
# 空函数:为了先定义好函数的模版
# pass充当占位符,程序设计的开始没想好具体功能,pass显得结构清晰
def auth_user():
'''注册功能'''
pass
# 无参函数
def foo():
x=10
y=3
if x>y:
print(x)
else:
print(y)
foo()
# 10
# 有参函数
def foo1(x,y):
if x > y:
print(x)
else:
print(y)
foo1(2,4)
# 4
或可以修改无参函数如下
def foo2():
x=input('>>>>>')
y=input('>>>>>')
x=int(x)
y=int(y)
if x>y:
print(x)
else:
print(y)
foo2()
# >>>>>9
# >>>>>8
# 9
例(以下两个代码一样的效果):
def say(char,size,msg): # say -> 函数的内存地址
print(f'{char}'*size)
print(f'{msg}'.center(size,' '))
print(f'{char}'*size)
def say1(char,size,msg): # say -> 函数的内存地址
print(char*size)
print(msg.center(size,' '))
print(char*size)
say1('#',40,'hahaha')
# ########################################
# hahaha
# ########################################
4,函数的返回值
# return的返回值: 函数内可以有多个return,但是只要执行1次,整个函数就立即终止
# return可以返回任意类型的值,并且可以返回多个
# return的用途
#例1
def max(x,y):
if x > y:
return x
else:
return y
data=max(3,5)
print(data * 3)
# 15
#例2
def foo(x,y,z):
return x,y,z
res=foo(1,2,3)
print(res)
# (1, 2, 3)
#return跟列表,也是返回元祖类型
def foo(x,y,z):
return x,y,z
res=foo(1,2,[1,5])
print(res)
(1, 2, [1, 5])
例3:
1)
def foo1():
user=input('your name:')
password=input('your password:')
return (user,password)
# 以上没有返回值
res=foo1()
print(res)
# your name:zx
# your password:123
# ('zx', '123')
2)
# 不加return值或者return空返回值为None
def foo1():
user=input('your name:')
password=input('your password:')
#return (user,password)
res=foo1()
print(res)
# your name:zx
# your password:123
# None
5,调用函数的3种方式
# 比较数字大写,显示数字较大的那个
def max2(x, y):
if x > y:
return x
else:
return y
#1, 语句形式(返回的是空)
max2(10, 20)
#2, 表达式形式(赋值,输出)
res = max2(10,20)
print(res)
# 20
res = max2(10,20) * 12
print(res)
# 240
#3, 可以把函数调用传给另外一个函数
res = max2(max2(10,20),30)
print(res)
# 30
6,函数的参数格式
1) 行参和实参
形参: 在函数定义阶段括号内定义的参数(变量名),称之为形式参数,简称形参
实参: 在函数调用阶段括号内传入的值(变量值),称之为实际参数,简称实参
2)行参
# 行参:
1)位置行参
2)默认行参
位置行参:在函数定义阶段按照位置定义的形参
特点:必须被传值
# 正确示例:
def foo(x,y):
print(x)
print(y)
foo(1,2)
# 1
# 2
# 错误示例:
def foo(x,y):
print(x)
print(y)
# 以下都会报错
foo(1,)
foo(,4)
foo()
默认行参:函数定义阶段就已经为某个形参赋值了
特点:可以不用为其传值
正确示例:
def foo(x,y=666):
print(x)
print(y)
foo(3)
# 3
# 666
foo(2,9)
# 2
# 9
注意:
1 位置形参必须在前
def foo(y=666,x):
pass
2 默认形参的值通常应该为不可变类型
例:
def reg(name,age,gender='male'):
print(name,age,gender)
reg('zx',13,'female')
# zx 13 female
# 不赋值即默认值
reg('egon',21)
# egon 21 male
3) 实参
# 位置参数
def register(name,age,sex):
print('Name:%s Age:%s Sex:%s' %(name,age,sex))
register('zx',3,'male') # 必须要传值
# Name:zx Age:3 Sex:male
# 定义关键字参数:在函数调用阶段按照key=value的形式传值
def register(name,age,sex):
return
register(name='bb',sex=3,age=9)
# Name:bb Age:9 Sex:3
# 混合使用
register('lili',sex='male',age=18)
注意:
def register(name,age,sex):
print('Name:%s Age:%s Sex:%s' %(name,age,sex))
register(name='lili',18,sex='male') # 会报错,位置实参必须在前面
register('lili',18,sex='male',name='pp') # 会报错,不能多赋值/不能为用一个行参赋值
PS:
默认参数必须在位置参数之后
默认参数的值仅在函数定义阶段被赋值一次
# 定义阶段arg已经赋值于x
x=1
def foo(arg=x):
print(arg)
x=4 # 这里的x修改与args无关
foo()
# 1
默认参数的值通常应设为不可变类型
def foo(n, arg=[]):
arg.append(n)
return arg
res=foo(1)
print(res)
# [1]
res1=foo(2)
print(res1)
# [1, 2]
res2=foo(3)
print(res2)
# [1, 2, 3]
# 每次调用是在上一次的基础上向同一列表增加值
def foo(n, arg=None):
if arg is None:
arg = []
arg.append(n)
return arg
res=foo(1)
print(res)
# [1]
res1=foo(2)
print(res1)
# [2]
7,可变长参数
1)可变长度的位置参数
args 在行参名前面加上*,在调用函数的时候,
溢出的位置实参都会被接收,以元祖的形式赋值给该行参
# 例1
def foo(x,y,*args):
print(x)
print(y)
print(args)
foo(1,2,3,4,5)
# 1
# 2
# (3, 4, 5)
# 例2(列表类型)
def foo(x,y,*args):
print(x)
print(y)
print(args)
# 先定义好一个列表
L=[4,5,6]
# 实参调用列表,传值给args
foo(1,2,*L)
# 1
# 2
# (4, 5, 6)
# 注意以上实参调用要加上*,不然会被会被默认为一个普通的位置参数
foo(1,2,L)
# 1
# 2
# ([4, 5, 6],)
# 例3: 多值求和
def add(*args):
res=0
for i in args:
res+=i
return res
res1=add(1,2,3)
print(res1)
# 6
2)可变长度的关键字参数
# 形参名前加**,在调用函数时,溢出的关键字参数,都会被接收,以字典的形式保存下来赋值给该形参
# 例1
def foo(x,**kwargs):
print(x)
print(kwargs)
foo(x=1,y=2,z=3)
# 1
# {'y': 2, 'z': 3}
# 例2:字典传值给参数
def foo(x,**kwargs):
print(x)
print(kwargs)
# 事先定义好一个字典
L={'a':1,'b':2,'c':3}
# 字典传入参数调用
foo(999,**L)
# 999
# {'a': 1, 'b': 2, 'c': 3}
#PS:如果不加上**,会报错,因为foo只需要一个位置参数,却传入了三个
foo(999,L)
# TypeError: foo() takes 1 positional argument but 2 were give
# 例3: 行参为默认/位置,实参也可以**的形式
def foo(x,y,z=3):
print(x)
print(y)
print(z)
foo(**{'x':1,'y':2})
# 1
# 2
# 3
3)命名关键字参数
# 在python3中,定义行参数时,加上*作为一个分隔符,*之后的额参数必须用key value的方式传入值(必须要传值)
def register(name,age,*,sex,height):
print(name,age,sex,height)
# 正确示例
register('lili',18,sex='male',height='1.8m')
# lili 18 male 1.8m
register(name='lili',age=18,sex='male',height='1.8m')
# 错误示例(会报错)
#register('lili',13,'female','1.2m')
# 如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了
def register(name,age,*args,sex,gender):
print('Name:%s,Age:%s,Args:%s,Sex:%s,Gender:%s' %(name,age,args,sex,gender))
register('pp',12,1,2,3,4,sex='female',gender=12)
# Name:pp,Age:12,Args:(1, 2, 3, 4),Sex:female,Gender:12
# 错误示例:
register('pp',12,1,2,3,4,'female',12)
# TypeError: register() missing 2 required keyword-only arguments: 'sex' and 'gender
只要在*后面的参数都是命名关键字参数!!!!!!
4)组合使用
# 可变参数*args与关键字参数kwargs通常是组合在一起使用的,如果一个函数的形参为*args与kwargs,那么代表该函数可以接收任何形式、任意长度的参数
def func(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs):
func(*args,**kwargs)
# 在为函数wrapper传参时,其实遵循的是函数func的参数规则
wrapper(1,2,3)
# 1 2 3
总结:
!!!!!!!!
**kwargs中的args和kwargs被替换成其他名字并无语法错误,
但使用args、kwargs是约定俗成的。
*在形参中: 会溢出的位置实参存成元组然后赋值给紧跟其后的形参名
*在实参参中: *会将后面的值打散成位置实参
**在形参中:会溢出的关键字实参存成字典然后赋值给紧跟其后的形参名
**在实参中:*会将后面的字典打散成关键字实参
!!!!!!
网友评论