函数的概念
- 带名字的代码块,用于完成具体工作
- 可以反复执行
函数命名
1.使用英文字母,不要使用中文
2.使用数字,但不能以数字开头
3.不使用特殊符号,_除外
4.函数名大小写敏感
5.避免使用python的关键字
6.函数名尽量有意义
函数的定义
- 使用def定义
- 注意冒号
- 形参:定义函数时,定义的函数参数
函数的调用
- 先定义后调用,调用后函数才会执行
- 实参:调用函数时传递给函数的参数
def greet_user(username): #username为形参
"""
函数说明
"""
print("Hello! {0}!".format(username.title()))
greet_user("Leo")
#调用函数,并传递实参Leo
#参数传递的过程,本质是普通变量赋值;Leo存储在变量username中
函数参数传递
- 位置参数(普通参数):
- 形参与实参的位置顺序必须一一对应
- 关键字参数:
- 传递给函数的”名称-值”对
- 不用考虑参数位置,根据关键字指定参数
- 默认参数:
- 调用时未传递,则使用定义时的默认值
- 使用默认值时,在形参列表中,默认参数要放在位置参数和关键字参数之后
- 收集参数(*args与**kwargs):
- *args
- **kwargs
- 把没有位置、不能和定义时的参数位置相对应的参数,放入特定的元组或者字典
def describe_pet(animal_type, pet_name,pet_color='black'):
'''
返回宠物信息
:param animal_type:
:param pet_name:
:return:
'''
print('I have a {0} {1},My {1}\'s name is {2}'.format(pet_color,animal_type,pet_name.title()))
describe_pet('hamster','harry','brown') #调用传递位置参数
describe_pet('dog','willie') #调用时未传递pet_color,使用默认参数
describe_pet(pet_color='white',pet_name='jack',animal_type='dog') #调用传递关键字参数,参数顺序不影响结果
def build_profile(first, last, **kwargs):
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for k,v in kwargs.items():
profile[k] = v
return profile
print(build_profile('chen','yang',age=28, high='175cm', weigth='140kg'))
def stu(name='No Name', age=0, addr='No Address'):
print("I am a student")
print("我是{0},我今年{1}岁,我住在{2}".format(name,age,addr))
m_name = "Chen Yang"
m_age = 28
m_addr = "GuangZhou"
stu(m_name,m_age,m_addr) #普通调用
stu(addr=m_addr,age=m_age,name=m_name) #关键字参数调用,不用关注参数位置
stu(name=m_name,addr=m_addr) #默认参数调用,调用时未指定age,使用默认值0
def stu( *args):
print("Hi,大家好,我做下自我介绍:")
print(type(args))
for i in args:
print(i)
stu("Chen Yang",28,"GuangZhou","jingjing","single Dog")
stu("CY")
stu()
def stu( **kwargs):
print("Hi 大家好,我先做下自我介绍:")
print(type(kwargs))
for k,v in kwargs.items():
print(k,':',v)
stu(name="Chen Yang",age=28,addr="GuangZhou",lover="jingjing",worker='IT Dog')
print("*"*20)
stu(name="CY")
stu()
多种参数混合使用时的调用顺序问题
按照以下顺序
普通参数、关键字参数、收集参数tuple、收集参数dict
def stu(name, age, *args, hobby="没有", **kwargs):
print("Hi,我先做下自我介绍")
print("我是{0},我今年{1}".format(name,age))
if hobby == "没有":
print("我没有爱好,sorry")
else:
print("我的爱好是{0}".format(hobby))
print("*"*20)
for i in args:
print(i)
print("#"*20)
for k,v in kwargs.items():
print(k,":",v)
stu("Chen Yang",19,)
stu("Chen Yang",19,"游泳")
stu("Chen Yang",19,"zhangsan","lisi","wangwu",hobby="游泳",hobby1="发呆",hobby2="撩妹")
收集参数的解包问题
def stu( *args):
n = 0
for i in args:
n += 1
print(n,":",i)
l = ["zhangsan",19,23,"jingjing"]
stu(l) #此时args=(["zhangsan",19,23,"jingjing"],)
stu(*l) #此时args=("zhangsan",19,23,"jingjing")
**kwargs 与之类似
函数的返回值
1.过程函数,无返回值
2.有返回值的函数,return
3.return为当前函数返回一个值或一组值,多个值可以返回列表、字典等复杂数据
4.运行return语句后,函数执行结束
5.未写明,默认return None,None是python中的一个对象,不属于数字也不属于字符串
6.一个函数一个return语句,不要使用多个return
def get_formated_name(first_name, last_name):
'''
返回完整姓名
:param first_name:
:param last_name:
:return:
'''
return {1:first_name.title(),2:last_name.title()} #返回字典
while True:
f_name = input("(Press 'q' or 'Q' to quit!)\nPlease input your first name:")
if f_name == 'q' or f_name == 'Q':
break
l_name = input("Please input your last name:")
if l_name == 'q' or l_name == 'Q':
break
print('Hi! {0}'.format(get_formated_name(f_name,l_name)))
函数的嵌套
不推荐
函数的递归
函数主体内直接或间接的调用自己
递推:函数体内部调用自己,直到某一级递归结束
回归:递归函数从后往前返回
递归函数必须明确定义递归结束的条件
每次调用递归函数都会赋值函数中的所有变量,再执行递归函数,比较消耗资源
阶乘
def refunc(n):
i = 1
if n > 1:
i = n
n = n * refunc(n-1)
print('{0}!={1}'.format(i,n))
return n
refunc(10)
汉诺塔
这里写代码片
函数文档
查看函数文档
1.help(func),信息显示自动换行
2.func.__doc__,信息显示不换行\n
自定义函数文档
1.'这里是说明文档'
2.'''说明文档'''
匿名函数/lambda函数
print((lambda x:-x)(-2))
print((lambda x,y:x+y)(1,2))
lambda不是函数结构,是一种表达式
书写简单
缺点是不适合复杂程序
lambda var1,var2:表达式
匿名函数,函数名未和标识符进行绑定
lambda中只能使用简单的表达式,无法使用判断、循环等语句
Generator函数
一次产生一个数据项,并把数据项输出
yield与return原理不同,return返回值后程序终止,而yield返回值后程序不终止
相比于序列索引,Generator生成器的性能更好