函数基础部分
1.什么是函数?
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。
2.定义函数
定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
def 是固定的,不能变,他就是定义函数的关键字。
空格:为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。
函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能(变量的命名规范)
括号:是必须加的,先别问为啥要有括号,总之加上括号就对了!
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
调用:就是 函数名() 要记得加上括号。
3.函数调用和参数
函数要先定义,后执行。定义完了之后不调用,就不执行
def userinfo(name,age,sex="男"): #其中sex是默认参数,name,age是未知参数
info = "姓名是%s,年龄是%s,性别是%s"%(name,age,sex)
return info
user=userinfo('kobe',age=18,sex="女") #其中kobe是未位置参数,age,sex是关键字参数
print(user) 函数名():不管是在哪个地方出现都是在调用函数----->函数真正执行的时候是函数的内存地址加上扩号() 函数的参数:
形参--->函数定义的时候
位置参数 a,b 传参的时候一一对应从实参处接受
默认参数 a=1 在定义的时候就设定好值了 实参--->函数调用的时候
位置参数 1,2, 传参的时候一一对应给形参
关键字参数 a=1 通过形参的名字指定传值
混合:
形参 def func(a,b,d,f=1):
实参 func(1,2,3,f=2) 传参--->将实参传递给形参的过程
#形式参数-->变量名后面()里面的参数
#实际参数-->实际上要传递的参数
#传参-->将实参传递给形参的过程叫做传参,
#位置参数-->形参和实参是有一个位置的关系,能一一对应,叫做位置参数
#默认参数-->定义默认参数的时候,有时候传递的实参和接受的形参数量并不一定相等
#关键字参数-->这样就不需要记住每一个参数的位置了,只需要在调用的函数的时候,给参数进行赋值就可以
注意:位置参数优先级要高于关键字参数(如果位置参数传递不正确的话会报错)
4.函数的返回值
1.没有return就默认返回None
2.写了return 没有写返回值 默认返回None
3.多个返回值的时候,返回的是一个元组
4.一个返回值的时候,返回的就是返回值本身
5.return 下面的代码不执行,并且结束这个函数 返回值作用:
1,结束整个函数。return下面的代码都不执行
2,给函数的执行者(调用者)返回值。 返回值返回给谁:
谁调用函数就把返回值返回给谁
5.初识函数其他知识点
1.函数先定义后执行,定义完了之后不调用,就不执行
2.print(函数名) --->函数的内存地址---><function userinfo at 0x0000000001D31E18>
3.函数执行过程:定义--->调用---->函数体代码
4.谁调用了函数,函数的返回值就返回给谁。如果返回值是1个,就返回字符串,2个以上的话,就返回元组
5.函数名():不管在哪个地方都是在调用函数
6.传递参数时:位置参数要高于关键字参数,一定要将位置参数--对应之后,只进行关键字赋值
7.三元运算符:c = a if a>b else b--->如果a>b就将a的值返回给c,否则就将b的值返回给c (通常在不确定到底是什么数值的时候用到)
other
1.全局变量必须要定格去定义,不能定义在缩进里面
2.()叫做调用操作符,[]叫做索引操作符
3.如果直接要是用一个便令,默认使用全局的
函数进阶部分
1.动态参数
*agrs:接受的位置参数,返回元组
**kwargs:接受关键字参数,返回字典 动态参数:
动态参数的用途:在不明确接受参数的数量时,使用*args和**kwargs来接受参数,分别返回
注意:*args和**kwargs中的英文字母可以是任意的符合变量定义规范的数据类型,但是通常不这么做!
动态参数出现位置:
动态位置参数>动态关键字(默认)参数
形参:位置参数>动态位置参数>默认参数>动态关键字(默认)参数
实参:位置参数>关键字参数
动态参数中*的作用:
实参:
*args在实参处调用时,*将可迭代对象打散,字典是将键值取出
**kwargs在实参处调用时,将字典打散,形成关键字参数,{键:值}相互对应
形参:
*args在形参处出现时,*代表的是将接收到的位置参数聚合成元组
**kwargs在形参处出现时,**代表的是将接收到的关键字参数聚合成字典
2.函数注释
def info(user,name):
"""
:param user:
:param name:
:return:
"""
print(1)
#在函数体内,连续输入三个双引号的因为字符,然后回车
查看注释: func名.__doc__
查看文件名: func名.__name__
查看文件路径:
import os
print(os.path.abspath(__file__))
3.命名空间:把同名的变量区分出不同的作用域
在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来。
但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已!
只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空. 我们给存放名字和值的关系的空间起一个名字叫: 命名空间. 我们的变量在存储的时候就 是存储在这片空间中的.
命名空间的分类:
内置空间: 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
全局空间: 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
内置空间: 在函数中声明的变量会放在局部命名空间
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值顺序:找不到就报错
在局部调用:局部命名空间->全局命名空间->内置命名空间
在全局调用:全局命名空间->内置命名空间 作用域:作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效,函数内部生效
global:在局部修改全部变量,如果没有就创建一个新的。
nonlocal:在局部空间内,修改离自己最近的变量,如果上一层没有就继续向上找,直到找到局部变量的顶层,局部空间内没有可以修改的变量,就报错。
4.函数嵌套
1. 只要遇见了()就是函数的调用. 如果没有()就不是函数的调用
2. 如果看见了print(函数名)是打印函数的内存地址
global:
global:
1,声明一个全局变量。
2,在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
ps:对可变数据类型(list,dict,set)可以直接引用不用通过global。
代码示例:
a = 100
def func():
global a # 加了个global表示不再局部创建这个变量了. 而是直接使用全局的a
a = 28
print(a)
func()
print(a)
nonlocal
nonlocal:
1,不能修改全局变量。
2,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
代码示例:
a = 10
def func1():
a = 20
def func2():
nonlocal a
a = 30
print(a)
func2()
print(a)
func1() 结果:
加了nonlocal
30
30 加nonlocal
30
20
函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。
other
函数名本质上就是函数的内存地址或对象。
1.可以被引用
2.可以被当作容器类型的元素
3.可以当作函数的参数和返回值
4.如果记不住的话,那就记住一句话,就当普通变量用 闭包函数:内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
闭包函数的常用实践:
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法 代码实现:
def func():
name = 'eva'
def inner():
print(name)
#print(inner.__closure__)有cell元素,就是闭包元素
return inner #返回的时inner的内存地址
f = func()
f()
在函数列表中出现的*,表示强制其后的参数强制使用关键字方式传参!