为什么要用函数
函数的作用与要求:
方便与提高了代码的使用率,同时也便于维护。函数尽量以功能为主,结果最好不要直接打印
函数的构成:
def func(obj):
return True
初识函数定义与调用
一、函数有“def”声明 ,“func”代表函数名,“obj”为函数的参数(形参),
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 print(length) #函数调用 mylen()
总结一:
定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
def 是固定的,不能变,必须是连续的def三个字母,不能分开。。。它们要相亲相爱的在一起。
空格 为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。
函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能
括号:是必须加的,先别问为啥要有括号,总之加上括号就对了!
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
调用:就是 函数名() 要记得加上括号
函数的返回值
二、return :return 后面的值可以为任意值,返回什么接受什么。如果只返回return ,则接受到的为空(None),不写return == ‘None’,
返回多个值吗,接收到的为元组,返回多值需要和接受变量一致
函数的参数
三、函数的参数:参数分为实参与形参
(1)实参---参数可以传任意类型,传什么接受什么。站在传参的角度有两种方式:(1)按照位置传参,(2)按照关键字传参(3)位置参数和关键字参数可以混用,但是位置参数必须在前。
(2)形参---分为位置参数、默认参数(关键字参数),动态参数,位置参数必须在关键字参数前面。(3)动态参数:*args,在位置参数之后,关键字参数之前,接受多余的位置参数,以元组的形式返回(4)**kwargs,位于默认参数之后,接收多余的关键字参数(5)调用函数的时候有两种用法(*str),(**dic)
函数的命名空间(名称空间)
(1)内置命名空间 吗(python解释器启动后,就可以使用的)
五、第一类对象条件:(1)函数名可以当作参数,(2)可以当返回值(3)可以作为一个结构的元素(在dict中,输入键,就可以调用该函数)
本章小结
定义函数的规则:
1.定义:def 关键词开头,空格之后接函数名称和圆括号()。 2.参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号分割。 参数可以定义多个,也可以不定义。 参数有很多种,如果涉及到多种参数的定义,应始终遵循位置参数、*args、默认参数、**kwargs顺序定义。 如上述定义过程中某参数类型缺省,其他参数依旧遵循上述排序 3.注释:函数的第一行语句应该添加注释。 4.函数体:函数内容以冒号起始,并且缩进。 5.返回值:return [表达式] 结束函数。不带表达式的return相当于返回 None def 函数名(参数1,参数2,*args,默认参数,**kwargs): """注释:函数功能和参数说明""" 函数体 …… return 返回值
调用函数的规则:
1.函数名() 函数名后面+圆括号就是函数的调用。 2.参数: 圆括号用来接收参数。 若传入多个参数: 应按先位置传值,再按关键字传值 具体的传入顺序应按照函数定义的参数情况而定 3.返回值 如果函数有返回值,还应该定义“变量”接收返回值 如果返回值有多个,也可以用多个变量来接收,变量数应和返回值数目一致 无返回值的情况: 函数名() 有返回值的情况: 变量 = 函数名() 多个变量接收多返回值: 变量1,变量2,... = 函数名()
命名空间和作用域
命名空间的本质:存放名字与值的绑定关系
在python之禅中提到过:命名空间是一种绝妙的理念,让我们尽情的使用发挥吧!
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值:
在局部调用:局部命名空间->全局命名空间->内置命名空间
x = 1 def f(x): print(x) print(10)
在全局调用:全局命名空间->内置命名空间
x = 1 def f(x): print(x) f(10) print(x)
在全局引用内置max
print(max)
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
在全局调用globals和locals
print(globals()) print(locals())
在局部调用globals和locals
def func(): a = 12 b = 20 print(locals()) print(globals()) func()
global关键字
a = 10 def func(): global a a = 20 print(a) func() print(a)
函数的嵌套和作用域链
函数的嵌套调用
def max2(x,y): m = x if x>y else y return m def max4(a,b,c,d): res1 = max2(a,b) res2 = max2(res1,c) res3 = max2(res2,d) return res3 # max4(23,-7,31,11)
函数的嵌套定义
def f1(): print("in f1") def f2(): print("in f2") f2() f1()
def f1(): def f2(): def f3(): print("in f3") print("in f2") f3() print("in f1") f2() f1()
函数的作用域链
def f1(): a = 1 def f2(): print(a) f2() f1()
def f1(): a = 1 def f2(): def f3(): print(a) f3() f2() f1()
def f1(): a = 1 def f2(): a = 2 f2() print('a in f1 : ',a) f1()
nonlocal关键字
# 1.外部必须有这个变量
# 2.在内部函数声明nonlocal变量之前不能再出现同名变量
# 3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效
def f1(): a = 1 def f2(): nonlocal a a = 2 f2() print('a in f1 : ',a) f1()
函数名的本质
函数名本质上就是函数的内存地址
1.可以被引用
def func(): print('in func') f = func print(f)
2.可以被当作容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']()
3.可以当作函数的参数和返回值
*不明白?那就记住一句话,就当普通变量用
第一类对象的概念
第一类对象(first-class object)指 1.可在运行期创建 2.可用作函数参数或返回值 3.可存入变量的实体。
闭包
def func(): name = 'eva' def inner(): print(name)
闭包函数:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
def func(): name = 'eva' def inner(): print(name) return inner f = func() f()
判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
闭包嵌套
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
闭包函数获取网络应用
from urllib.request import urlopen def index(): url = "http://www.xiaohua100.cn/index.html" def get(): return urlopen(url).read() return get xiaohua = index() content = xiaohua() print(content)
本章小结
命名空间:
一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
作用域(包括函数的作用域链):
小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)
在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错
函数的嵌套:
嵌套调用
嵌套定义:定义在内部的函数无法直接在全局被调用
函数名的本质:
就是一个变量,保存了函数所在的内存地址
闭包:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数