函数
函数就是用来实现一些特特定功能的小的程序或方法
使用函数的优点:
1> 增加了代码的重用率
2> 减少了代码量
3>提高了代码的可维护性
主体结构:
def 函数名([参数1],[参数2],[..]):
函数体..
函数的调用:
函数名(实参1,..)
函数参数相关
参数1-形参和实参
1> 形参(在定义函数的时候, 括号内的变量)
2> 实参(在函数调用的时候, 传入的参数)
参数2-关键字参数
用法:函数名(形参名=值)
实例:
def demo(a,b,c):
pass
demo(c=10,a=20,b=30) # 函数调用, 关键字参数
函数参数-带默认值的操作
用法:def 函数名(形参名=默认值):
实例:
# def func(a=10,b=10): # ok
# def func(a, b=10) # ok
def func(a=10, b): # error 错误给形参默认值的操作
pass
注意:
1>函数在定义的时候, 如果有形参, 且没有默认值, 必须要传实参
2>如果没有形参不能传实参
3>如果形参没有默认值, 那么实参的个数必须和形参的个数相同
4>如果形参有默认值, 可以不用传实参
5>形参和实参一 一对应
6> 当给形参默认值时, 必须遵循默认值的规则
函数的返回值
用法: return 值
实例:
def sum(x,y):
print("输出的内容")
return x+y # 函数返回
print(sum(1,2)) # 返回值为3
注意:
1> return 会把值返回给调用处(就是函数名()的位置)
2> 函数执行遇到return就函数返回, 下面的代码不在执行
return可以返回多个值
def demo():
return 1,2,3 # 返回元组 即(1,2,3)
函数的不定长参数
(1) 任意数量的实参(以元组的形式去接收变量)
主体结构:
def 函数名(*args): # 注意:args只是变量名可以随便取,推荐用args
pass
示例:
def demo(*args):
print(args) # *可以将按位置传递进来的参数转换成元组(tuple)类型
print(type(args)) # type() 用于查看值的类型, 打印tuple
demo(1,2,3,4) # ok 会打印(1,2,3,4) tuple
demo(1) # (1,) # 注意: 元组类型,括号内必须带逗号
demo() # () 空元组
(2) 任意数量的关键字参数(以字典的形式去接收不确定实参)
主体结构:
def 函数名(**kwargs):
pass
函数名(x=1, y=2,z=3)
示例:
def demo(**kwargs) # 推荐使用kwargs命名
print(kwargs) # **可以将按关键字传递进来的参数转换成字典(dict)类型
print(type(kwargs)) # type() 函数查看值的类型 打印dict类型
demo(x=1,y=2) # ok {'x': 1, 'y': 2}
(3) 将参数为字典的值变成为关键字参数传入函数
主体结构:
def 函数名(**kwargs):
pass
myDict = {'x':1, 'y':2} # 字典的值
函数名(**myDict) # 等价于 函数名(x=1,y=2) 这里需要传入关键字参数
示例:
def func(**kwargs):
print(kwargs)
myDict = {'x':1, 'y':2}
func(**myDict) # ok {'x': 1, 'y': 2}
(4) *args和**kwargs的组合使用
主体结构:
def 函数名(*args, **kwargs):
pass
示例:
def func(*args, **kwargs):
print(args)
print(kwargs)
func(x=1,y=3) # 打印 () {'x':1,'y':2} 传入关键字参数赋值给了kwargs
func(1,2,x=3) # 打印(1,2) {'x':3}
关于函数内变量值的修改
可变类型(可以对变量内部分值,修改删除):如列表,字典, 在函数内修改, 函数外部也会发生变化
不可变类型:整数,字符串,元组,在函数内部进行修改的时候,其实是创建一个同名的局部变量(不能对部分进行修改删除,只能重新赋值)
可变类型实例:
myDict = {'name':'张三', 'age':18}
def update():
print(myDict)
myDict[‘name’] = '李四' # ok 修改了全局变量, 只是变量中部分被修改,
print(myDict) # {'name': '李四', 'age': 18}
update() # 函数调用
print(myDict) # 在函数外打印 {'name': '李四', 'age': 18}
myDict = {'name': "张三", "age": 18}
def update():
myDict = {'name':'李四'} # 创建了局部变量, 函数外部获取不到
print(myDict) # {'name':'李四'}
update() # 函数调用
print(myDict) # {'name': "张三", "age": 18}
不可变类型的实例:
myStr = 'abcd'
def demo():
print(myStr)
myStr[1] = '1' # error 不能修改部分内容的值
myStr = 'a' # 创建一个局部变量myStr, 函数外访问不到
demo()
print(myStr) # 打印全局变量 'abcd'
变量的作用域
全局变量: 在函数外部定义的变量成为全局变量
局部变量:在函数内部定义的变量成为局部变量
注意:
1> 在函数内部可以获取到函数外部的全局变量
2> 在函数往外部获取不到函数内部定义的局部变量
3> 我们所学的if else while for 中定义的变量也为全局变量
1. 在函数外部定义的全局变量函数内外部都可以获取
myStr = "abcd"
def demo():
print(myStr) # abcd
2. 在函数内部定义的变量成为局部变量,函数外部获取不到
def demo():
myStr = 'a'
print(myStr) # a
demo() # 函数调用
print(myStr) # NameError
3.使用global关键字 将变量声明为函数内外使用同一个,可以在函数内对变量的值进行整体的修改
# 如果不使用global
myInt =18
def demo():
myInt = 20
print(myInt) # 重新定义了函数内部的局部变量
demo()
print(myInt) # 18
# 使用global
myInt = 18
def demo():
global myInt
myInt = 20 # 修改的是全局变量
demo()
print(myInt) # 20
# 使用global还可以将函数内部的局部变量变为全局变量
def demo():
global age
age = 18
demo()
print(age) #18
4. nolocal关键字 当函数发生多层嵌套时, 将函数外层和里面的变量声明为同一个变量
要修改嵌套作用域(例如:函数向上一层, 非全局作用域)中的变量则需要使用
因为如果直接修改上一层函数中的变量,会创建局部变量覆盖上一层的变量
实例:
name = '张三'
def a():
name = '李四'
def b():
name = '王五'
def c():
nonlocal name # 修改外层(非全局)变量 name = '王五',不会影响其他变量,如果找不到nonlocal后面的name会一直向上层函数找,找不到报错
name = '赵六'
print('我是函数c', name) # 打印赵六
c()
print('我是函数b', name) # 打印赵六
b()
print('我是函数a', name) # 打印李四
a()
print(name) # 张三
lambda 表达式(匿名函数)
主体结构: 变量名=lambda [形参]:代码
1. 没有任何参数的lambda表达式
func = lambda:print('我是lambda表达式')
print(func) # <function <lambda> at 0x....>
func() # 通过加括号进行函数调用
2. 带返回值的lambda表达式
a = 10
func = lambda:a
print(func()) # 打印返回值 10
3.带形参
func = lambda x,y:x+y
print(func(1,2)) # 3
4. 带形参默认值
func = lambda x=1,y=2:x+y
print(func()) # 3
print(func(y=2,x=2)) # 4 还可以使用关键字参数
5.自调用
(lambda x,y:x+y)(1,2)
函数的导入方式
from 库名 import 包名
from 库名 import 包名 as 别名
from 库名.包名 import 方法名1,方法名2,..
import 包名 as 别名
__name__:
系统属性,作用是在运行的时候检测该模块是被导入还是被直接执行, 如果模块被导入,__name__
为模块的名字,如果被直接执行,__name__
的值为__main__
注意:
1> 注意包名和库名起一个规范的见名知意的名字
2> 可以使用import 包名来避免和其他名字的冲突,还以起别名来避免冲突