函数

1、函数的基本知识

1.1 、break

跳出当前执行的循环体;

1.2 、return

跳出当前执行的函数,结束一个函数;
        return
return None 基本不用
return 返回1个值
return 多个值----:return value1,value2....,多个返回值用多个变量进行接收,有多少个返回值就得用多少个变量接收
多个变量可以用一个变量进行接收,这时候这个变量接收值以后就是元组,其实返回值就是一个元组
元组是可以解包的: a,b,c = (1,3,4),那么a = 1,b = 2,c = 4

1.3 、站在形参角度上

按照位置传参,按照参数的位置一一对应去赋值传实参
按照关键字传参,就是形参里面是什么名称,调用函数传实参的时候就用什么名称
混着用可以:但是 必须先按照位置传参,再按照关键字传参数
不能给同一个变量传多个值

1.4、站在实参角度上

位置参数:必须传,且有几个参数就传几个值
默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的,默认的参数就是函数的形参里面已经定义实参的那种
先定义位置参数,后定义默认参数
动态参数 : 可以接受任意多个参数,
参数名之前加*,习惯参数名args,但关键字参数接收不了,接收的是按位置传参数的值,组织成一个元组
参数名之前加**,习惯参数名kwargs,接收的是按关键字传参数的值,组织成一个字典

1.5、函数放参数的顺序

函数放参数顺序:位置参数,*args,默认参数,**kwargs

1.6、动态参数的另一种传参方式

第一种:可变位置参数*args

1 def sum(*args):
2     n = 0
3     for i in args:
4         n+=i
5     return n
View Code

结果:

1 3
2 6
3 10
View Code

第二种:可变关键字参数**kwargs

1 def func2(**kwargs):
2     print(kwargs)
3 func2(a = 1, b = 2, c = 3)
View Code

结果:

1 {'a': 1, 'b': 2, 'c': 3}
View Code

下面代码结果是

1 def func3(*args,**kwargs): #组合式动态形参函数,那么先args后kwargs,且传实参也得是这个顺序
2     print(args,kwargs)
3 
4 func3(1,2,3,a = 5,c = 9)
5 func3(1,2,3,a = 5,c = 9)

结果:

1 (1, 2, 3) {'a': 5, 'c': 9}
2 (1, 2, 3) {'a': 5, 'c': 9}
View Code

下面代码结果是

1 def func4(*args):
2     print(args)
3 L = [1,2,3,4]
4 func4(*L) 

结果:

1 #从实参角度上看,给一个序列加上*,就是将这个序列按照顺序打散
2 (1, 2, 3, 4)
3 {'a': 2, 'b': 8}
View Code

下面代码结果是:

1 def func5(**kwargs):
2     print(kwargs)
3 l5 = {'a':2,'b':8}
4 
5 func5(**l5)

结果是:

1 {'a': 2, 'b': 8}
View Code

 

1.7、函数的注释

1 def func():
2     '''
3     这个函数是实现什么功能
4     参数1:
5     参数2:
6     参数3:
7     :return: 返回的是什么
8     '''

 

1.8、默认参数的陷阱问题

总体原则:当默认参数是一个可变数据类型(可哈希)时候,那么每一次调用函数的时候,如果不传值就共用这个数据类型的资源

下面代码结果是:

1 def func2(l = []):
2     l.append(1)
3     print(l)
4 func2()   
5 func2([])  
6 func2()    
7 func2()   
 1 def func2(l = []):
 2     l.append(1)
 3     print(l)
 4 func2()    #不传参数,那么用默认的参数
 5 func2([])  #传了个自己的空列表,那么不用默认的空列表
 6 func2()    #不传参数,那么接着用默认的参数
 7 func2()    #不传参数,那么接着用默认的参数
 8 
 9 结果:
10 [1]
11 [1]
12 [1, 1]
13 [1, 1, 1]
View Code

下面代码的结果是:

1  def func2(l = {}):
2     l['k'] = 'v'
3      print(l)
4  func2()    
5  func2()   
6 func2()    

结果:

1 #如果是空字典,那么里面其实是重复把key的值固定为v
2 {'k': 'v'}
3 {'k': 'v'}
4 {'k': 'v'}
View Code

下面代码的结果是:

1 def func2(k,l = {}):
2     l[k] = 'v'
3     print(l)
4 func2(1)   
5 func2(2)    
6 func2(3)   

结果:

1 {1: 'v'}
2 {1: 'v', 2: 'v'}
3 {1: 'v', 2: 'v', 3: 'v'}
View Code

 1.9  函数的命名空间

#命名空间 有三种
#内置命名空间 —— python解释器
# 就是python解释器一启动就可以使用的名字存储在内置命名空间中
# 内置的名字在启动解释器的时候被加载进内存里
#全局命名空间 —— 我们写的代码但不是函数中的代码
# 是在程序从上到下被执行的过程中依次加载进内存的
# 放置了我们设置的所有变量名和函数名
#局部命名空间 —— 函数
# 就是函数内部定义的名字
# 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了

#在局部:可以使用全局、内置命名空间中的名字
#在全局:可以使用内置命名空间中的名字,但是不能用局部中使用
#在内置:不能使用局部和全局的名字的

#依赖倒置原则:(内置的名字空间 (全局的名字空间 (局部的名字空间) ) ):内部的可以到上层找,但上层不能到更里层找

#在正常情况下,直接使用内置的名字
#当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
#当我自己有的时候 我就不找我的上级要了
#如果自己没有 就找上一级要 上一级没有再找上一级 如果内置的名字空间都没有 就报错
# 多个函数应该拥有多个独立的局部名字空间,不互相共享
1 def input():
2     print('in input now')
3 def func():
4     # input = 1
5     print(input)
6 func()
这段代码打印的是什么呢
1 <function input at 0x00000000004D2F28>
结果

 

# 对于不可变数据类型 在局部可是查看全局作用域中的变量
# 但是不能直接修改
# 如果想要修改,需要在程序的一开始添加global声明
# 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效


# 作用域两种
# 全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 ——globals()
# 局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) ——locals()

1 a = 1
2 def func():
3     global a
4     a += 1
5 func()
6 print(a)

代码的结果是;

1 结果就是:2
结果是
1 a = 1
2 b = 3
3 def func2():
4     x = 'aaa'
5     y = 'ccc'
6     print(locals())
7 func2()
1 {'y': 'ccc', 'x': 'aaa'}
结果是

 

1 a = 1
2 def func3():
3     global a #这里会代替外面全局的变量a,这样名字实际被改了
4     a = 2
5 func3()
6 print(a)
7 print(globals()) #globals永远打印全局的名字
8 print(locals()) #locals放在全局,那么它的局部就是全局;如果放在局部,那么就是局部
1 2
2 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000275BBA8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python Project/05/Day10/函数的命名空间.py', '__cached__': None, 'a': 2, 'func3': <function func3 at 0x00000000020B2F28>}
3 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000275BBA8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python Project/05/Day10/函数的命名空间.py', '__cached__': None, 'a': 2, 'func3': <function func3 at 0x00000000020B2F28>}
结果是

 1.10 函数的嵌套

函数的嵌套:内部函数可以使用外部函数的变量

1 def outer():
2     def inter():
3         print(2)
4     inter()
5 outer()
1 2
结果是
1 def outer():
2     b = 5
3     def inter():
4         print(b)
5         print('in the inter')
6     inter()
7 outer()
1 5
2 in the inter
结果是
定义为gloabl的函数中的变量,那么该变量是全局的变量,局部变量如果同名那么是没有修改的
不可变数据类型在它的下级函数不能被修改,只能查看
 1 b = 2
 2 def outer():
 3     b = 5
 4     def inter():
 5         print(b)
 6         c = 4
 7         print('in the inter')
 8         def interb():
 9             #c += 1  #不可变数据类型在它的下级函数不能被修改,只能查看
10             global b
11             b += 1
12             print(c)
13             print(b)
14             print('in the interb')
15         interb()
16     inter()
17 outer()
18 print(b)
1 5
2 in the inter
3 4
4 3
5 in the interb
6 3
结果是

1.10.1  nonlocal的使用

onlocal声明了上面一层的局部变量,离被使用b最近的局部变量,即往外找找到最近一层的那个变量b,只能用于局部变量
如果往上找没找到局部的变量那么报错,全局的变量是不行的,即nonlocal对全局变量无效。
 1 b = 2
 2 def outer():
 3     b = 5
 4     def inter():
 5         print(b)
 6         print('in the inter')
 7         def interb():
 8             nonlocal b 
 9             b +=1
10             print(b)
11             print('in the interb')
12         interb()
13     inter()
14     print(b)
15 outer()
16 print(b)
1 5
2 in the inter
3 6
4 in the interb
5 6
6 2
结果是

1.10.2 一个函数的函数名就是一个内存地址

1 def fun():
2     print(33)
3 fun2 = fun
4 fun2()
5 lis  = [fun,fun2] #函数名可以作为容器类型的元素
6 print(lis)
7 for i in lis:
8     i()
1 33
2 [<function fun at 0x00000000003E2F28>, <function fun at 0x00000000003E2F28>]
3 33
4 33
结果是

1.10.3   函数可以作为另一个函数的参数

1 def func():
2     print(44)
3 def func2(f):
4     f()
5 func2(func)
1 44

1.10.4 函数名可以作为另一个函数的返回值

1 def func():
2     print(44)
3 def func2(f):
4     f()
5     return f   #函数名可以作为函数的返回值
6 a = 0
7 a = func2(func) #函数名可以作为函数的参数
8 print(a)
9 a()
1 44
2 <function func at 0x0000000001D22F28>
3 44
结果是

1.10.5 一类对象(first-class objet)指

1 1、可在允许期创建
2 2、可用作函数参数或返回值
3 3、可存入变量的实体

 1.11 闭包

闭包:嵌套函数,内部函数调用外部函数的变量;其实就是一个函数A里面嵌套了另一个函数B,并且函数B里面使用了函数A的变量,那么函数B为闭包;  如果函数B没有使               用函数A里面的变量,但使用了全局变量,那么函数B就不是闭包。

检测一个函数是否为闭包的形式:
print(inner.__closure__) #这是检测inner()是否为闭包
1 def outer():
2     b = 2
3     def inner():
4         print(b) 
5     inner()
6     print(inner.__closure__) 
7 outer()
8 print(outer.__closure__)
1 2
2 (<cell at 0x00000000003FEEB8: int object at 0x000000001D8E60C0>,) #表示inner()函数是闭包
3 None #表示outer()函数不是闭包
4 
5 函数中如果没有print(b)这句话,即调用上一层变量这么个操作的 话,那么inner()函数就不是闭包
结果&解析
1 b = 1
2 def outer():
3     def inner():
4         print(b) #这里调用的是全局表里的b,所以不是闭包
5     print()
6 outer()

1.11.1 闭包的常用形式:

在函数外部使用函数内部的函数,在在函数外部使用嵌套的函数。

闭包的作用:在多次调用同一函数时候,可以节省空间的作用

1 def func():
2     a = 77
3     def func2():
4         print(a)
5     return func2
6 func3 = func()
7 func3()
1 77
2 分析:实际上func3()就等价于调用了func2()
View Code
1 from urllib.request import urlopen
2 def func():
3     url = 'http://www.ifeng.com/'
4     def get():
5         ret = urlopen(url).read()
6         print(ret)
7     return get
8 get_net = func()
9 get_net()
1 b'<!DOCTYPE html>\n<html xmlns:wb="http://open.weibo.com/wb">\n<head>\n    <meta charset="utf-8">\n
2 ...........
3 ...........
4 还有很多,不再写出来
5 其实结果就是网页的源码
6 这里如果我们多次调用嵌套函数get()时候就可以起到调用的时候才生成ural这个常量的空间,用完就释放空间的作用,这样起到节省空间的作用
结果&分析

 





 

posted @ 2019-04-02 06:30  xiaofeiAI  阅读(180)  评论(0编辑  收藏  举报