Python函数

 

  1.初识函数定义与返回

 1 # 函数
 2 # 定义函数
 3 def my_len():
 4     i = 0
 5     for k in s:
 6         i += 1
 7     return i
 8 
 9 # 函数没有返回值时,函数返回的是None,只写return时返回的也是None,return None也是返回None
10 
11 # 函数return返回一个值的情况下:可以返回任何数据类型
12 
13 # 函数return返回多个值的情况下(相当于返回了一个元组。元组、列表、字典都是可以解包的):可以多个变量接收,有多少个返回值就用多少个变量接收
14                          # 返回多个值用一个变量接收,得到的是一个元组
15 def func2():
16     return 1, 2, 3
17 
18 r = func2()
19 print(r)    # (1, 2, 3)
20 
21 # 元组、列表、字典都是可以解包的
22 a, b, c = (1, 2, 3)
23 
24 a, b, c = [1, 2, 3]
25 
26 a, b, c = {'1' : '2', '3' :'4', '5' : '6'}  # 随机将键赋值给每个变量
27 
28 print(a)
View Code

  

  2.函数参数(1)

 1 # 函数参数,    形参与实参
 2 def my_len1(s):
 3     i = 0
 4     for k in s:
 5         i += 1
 6     return i
 7 
 8 s = 'afasfsdf'
 9 
10 print(my_len1(s))
View Code

  2.函数参数(2)

  1 # 函数参数
  2 
  3     # 没有参数
  4         # 定义函数和调用函数时括号里都不写
  5     # 有一个参数
  6         # 传什么是什么
  7     # 有多个参数
  8         # 位置参数,参数位置一一对应,
  9             # 站在实参的角度上:
 10                 # 按照形参名(关键字)传参
 11                 # 混着用:必须先按照位置传参,再按照形参名(关键字)传参
 12                         # 不能给同一个形参传多个值
 13             # 站在形参的角度上
 14                 # 位置参数:必须传,多传少传都不行
 15                 # 默认参数:可以不传,如果不传就是用默认的参数,如果传了使用传的
 16         # 默认参数:关键字参数: 参数名 = '默认值'
 17         # 动态参数: 可以接收任意多个参数
 18             #参数名之前加*,习惯为*args,属于位置参数,必须在前,接收的是位置参数,组织成一个元组
 19             #参数名之前加**,习惯我**kwargs,属于关键字参数,必须先定义位置参数,在定义关键字参数,传参时也是,先传位置参数,在传关键字参数。
 20         # 顺序:位置参数、*args(属于位置参数)、默认参数、**kwargs
 21             # 这是函数传参固定的顺序
 22 
 23 
 24 def my_sum(a, b):       #位置参数
 25     return a + b
 26 
 27 print(my_sum(1, 2))     # 位置参数,1传个了a,2传给了b
 28 
 29 ret = my_sum(b = 1, a = 2)  # 按键形参名(关键字)传参
 30 print(ret)
 31 
 32 print(my_sum(2, b = 3)) # 必须先按照位置传参,再按照形参名(关键字)传参
 33 
 34 
 35 # 定义函数的时候,必须先定义位置参数,后定义默认参数
 36 def classmate(name, sex = ''):     # 默认参数:可以不传,如果不传就是用默认的参数,如果传了使用传的
 37     print('{} : {}'.format(name, sex))
 38 
 39 classmate('wuhengyi')
 40 classmate('fqq', '')
 41 
 42 
 43 
 44 # 定义函数的时候,动态参数,*是关键字,参数名之前加*,参数名习惯用args
 45 # 先定义位置参数,在定义动态参数,在定义默认参数
 46 def sum(*args):     # args元组的形式
 47     n = 0
 48     for i in args:
 49         n += i
 50     return n
 51 
 52 sum(12, 2)
 53 sum(1, 2, 3)
 54 print(sum(1, 2, 3, 4))
 55 
 56 
 57 def func(*args, l = []):
 58     print(args)
 59 
 60 func(1, 2, 3 ,'srg', {1: 'a'}, l = ['123', 42])
 61 
 62 
 63 # 动态参数,**kwargs,是字典的形式
 64 def func1(**kwargs):
 65     print(kwargs)
 66 
 67 
 68 func1(a = 1, b = 2, c = 3)      # {'b': 2, 'a': 1, 'c': 3}
 69 func1(a = 1, b = 2)     # {'b': 2, 'a': 1}
 70 func1(a = 1)
 71 
 72 
 73 # 动态参数有两种,特点是可以接收任意多个参数
 74     # *args     : 接收的是按照位置传参的值,组织成一个元组
 75     # **kwargs  : 接收的是按照关键字传参的值,组织成一个字典
 76 
 77 # 先按位置传,在按关键字传。函数传参的规则,先传位置参数,在传关键字参数。所以*args必须在**kwargs之前。
 78 # 函数传参固定顺序,位置参数、*args、默认参数、**kwargs
 79 def func2(a1, b1, *args, default = 1, **kwargs):
 80     print(a1, b1, args, kwargs)
 81 
 82 func2(1, 2, 3, 4, 5, a= '1', b = 'b', c = 'ccc')
 83 
 84 
 85 # 动态参数的另一种传参方式
 86 def func(*args):    # 站在形参的角度上,给变量加上*,就是组合所有传进来的值
 87     print(args)
 88 
 89 func(1, 2, 3, 4)
 90 
 91 l = [1, 2, 3, 4, 5]
 92 func(*l)    # 站在实参的角度上给一个序列(list, tuple)加上*,就是将这个序列按照顺序打撒
 93             # (1, 2, 3, 4, 5)
 94 
 95 # 动态参数的另一种传参方式
 96 def func(**kwargs):
 97     print(kwargs)
 98 
 99 dic = {'a' : 1, 'b' :2}
100 
101 func(**dic)     # {'a': 1, 'b': 2}  **可以打散一个字典,将打散的键值对传递给**kwargs,**kwargs将值组合成一个dict
102 
103 # 函数的注释,在函数里开始加,先说函数实现了什么的功能,在说参数的参数类型,参数作用,在说返回值
104 def func():
105     '''
106     这个函数实现了什么功能
107     参数1:数据类型,作用
108     参数2:数据类型,作用
109     :return: 是字符串或者列表的长度
110     '''
111     pass
112 
113 
114 # 函数
115     # 内置函数
116         
117     # 自定义函数
118         # 有参数的、没参数的、位置参数、*args、默认参数、**kwargs
View Code

   

  补充默认参数

 1 # 默认参数, 形参因为是list,list是可变数据类型,在内存中,内存里面的内容是可以变得,相当于指针。形参是dict是一样的
 2 def qqxing(l = []):
 3     l.append(1)
 4     print(l)
 5 
 6 l = []
 7 
 8 qqxing(l)
 9 
10 print(l)

 

  3.函数的命名空间

 1 # 命名空间和作用域
 2     # 内置命名空间,python内部集成
 3         # 就是python解释器一启动就能识别的,如关键字、print、len等等,存储在内置命名空间中
 4         # 内置的名字在启动解释器的时候被加载到内存中
 5     # 全局命名空间
 6         # 在程序从上到下被执行的过程中依次加载到内存中,当前文件,从上到下
 7     # 局部命名空间,由函数弄出
 8         # 函数内部定义的名字
 9         # 当调用函数的时候 才会产生这个名字的命名空间 随着函数执行结束这个名字的局部命名空间消失
10 
11 #
12 # 在局部:可以使用全局命名空间的东西(之前),可以使用内置命名空间中的东西
13 # 在全局:可以使用内置空间中的东西,不能使用函数内局部空间的东西
14 # 在内置命名空间中:python是不能使用我们全局和局部的空间的。
15 
16 # 三种命名空间之间的加载与取值顺序
17     # 加载顺序:内置命名空间(程序运行前健在)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用函数时才加载)
18 
19 # 当再全局命名空间中定义了内置命名空间中同名的名字,在全局会使用全局的定义的
20 # 当局部命名空间中定义了与全局命名空间中同名的名字,在局部会使用局部定义的
21 # 自己命名空间中有的则使用自己的,如果自己命名空间没有的会去上一层命名空间中的
22 
23 
24 
25 # 作用域有两种
26     # 全局作用域,内置命名空间和全局命名空间的都是作用于全局作用域的
27     # 局部作用域
28 
29 # 对于不可变数据类型 在局部可查看全局作用域中的变量,但是不能直接修改,如果想要修改,需要global声明
30 a = 1
31 def func5():
32     global a    # 如果在局部想要操作修改全局的,必须在局部中声明全局中的变量
33     a += 1
34 func5()
35 print(a)
36 
37 a = 1
38 b = 2
39 def func6():
40     x = 'aaaa'
41     y = 'bbbb'
42     print(locals())  # 使用locals()可以查看局部作用域空间中所有的变量和对应值,存放到一个dict中展示。在局部显示局部的,在全局显示全局的名字与对应值
43 
44 func6()
45 
46 print(globals())    # 可以查看全局作用域中的名字域对应值,以dict形式展示
View Code

  

  三目运算

1 # 三目运算
2 
3 print(5 if 2 > 1 else 4)    # 如果2 大于 1 返回5 否则返回 4
4 
5 def max(a, b):
6     return a if a > b else b
7 
8 print(max(1, 2))
View Code

 

  4.函数的嵌套和作用域链

 1 # 函数嵌套调用
 2 
 3 print(5 if 2 > 1 else 4)    # 如果2 大于 1 返回5 否则返回 4
 4 
 5 def max(a, b):
 6     return a if a > b else b
 7 
 8 def the_max(x, y, z):
 9     c = max(x, y)   # 函数嵌套
10     return max(c, z)
11 
12 print(the_max(1, 2, 3))
13 
14 
15 # 函数嵌套定义
16 
17 # 作用域链
18 # 当outer()调用时,outer被执行,执行内容为先在outer局部命名空间定义了一个a,之后又在outer局部命名空间a之后定义了一个函数inner,inner属于outer局部命名空间但在a的后面,定义完inner后,调用了inner,调用inner时发现inner局部空间中没有a,所以去outer的局部命令空间看有没有a,发现有,所以使用了outer局部命名空间中的a
19 def outer():
20     h = 1
21     def inner():
22         nonlocal h  # nonlocal 只能用于局部变量, 向上一层的局部找h,如果上一层局部有h,则使用h,如果上一层局部没有则继续往上一层局部找,如果局部没有则报错。找离当前函数向上最近一层的局部变量
23         print('inner')
24         h += 1   # 不能用global,global修改的是全局的\
25         print(h)    # 2
26     inner()
27 
28 outer()
29 
30 
31 # 函数名的本质是执行内存地址的一个名字,
32 
33 def func():
34     print(123)
35 
36 func2 = func    # 函数可以复制,这不就是函数指针的形式
37 func2()
38 l = [func, func2]   # 函数名可以作为容器类型的元素
39 print(l)
40 for i in l:     # 函数指针数组概念,遍历list中没有一个函数,拿到地址后解引用运行
41     i()
42 
43 def func():
44     print(123)
45 
46 def wahaha(f):
47     f()
48     return f
49 
50 wahaha(func)    # 函数名可以作为函数的参数,很好理解,函数指针传递. 函数可以返回函数名(就是返回内存地址)
View Code

  5. 闭包

 1 # 闭包:肯定是嵌套函数,内部函数用到了外部函数的变量就算是闭包
 2 
 3 # inner() 就是一个闭包
 4 # def outer():
 5 #     a = 1
 6 #     def inner():
 7 #         print(a)
 8 #     print(inner.__closure__)    # (<cell at 0x000001EFBAD4B198: int object at 0x000000005B545320>,)  打印能看到cell就说明是一个闭包
 9 # outer()
10 
11 
12 # 闭包的正确使用方法,将闭包函数的函数名返回出去,外部定义一个对象去接收者个函数名值,这个对象可以运行这个闭包函数
13 def outer():
14     a = 5   # 当outer被调用退出后,a的变量值不会因作用域的结束而消失,inner可以随意使用,延长了a的生命周期,可以上inner闭包函数直接使用
15     def inner():
16         print(a)
17     return inner    #
18 inn = outer()   #
19 
20 inn()   # 这种方式调用,会直接掉用inner,inner用到了outer的a,outer的a此时会在内存中,值保留
21 
22 
23 
24 # 闭包的应用, urllib是python自带的模块,就是自带的python文件,那个python文件的名字叫做urllib.py.. 这个urllib模块有很多方法,是关于url请求的
25 # import urllib   # 导入urllib模块
26 from urllib.request import urlopen      # 从urllib模块中只导入一个方法urlopen. urlopen方法可以打开一个网页
27 
28 # www.xiaohua100.cn/index.html   校花网
29 # ret = urlopen('http://www.xiaohua100.cn/index.html').read()     # 获取这个网页内容
30 # print(ret)
31 
32 # 闭包的应用
33 # 如果不用闭包,下面的这个函数每次调用的时候都会创建一个url,然后填充网址,然后打开这个网页将内容读取出来赋值给ret,每次调用都如此,这样很不好
34 # def get_url():
35 #     url = 'http://www.xiaohua100.cn/index.html'
36 #     ret = urlopen(url).read()     # 获取这个网页内容
37 #     print(ret)
38 
39 # 闭包的应用
40 # 下面的这个函数用的了闭包,好处就是我们可以调用一此get_url后,得到inner的函数名地址,之后每次想要打开着个url的时候,直接运行inner这个闭包就行,这个inner闭包的url变量就会直接使用get_url的url
41 def get_url():
42     url = 'http://www.xiaohua100.cn/index.html'
43     def inner():
44         ret = urlopen(url).read()     # 获取这个网页内容
45         print(ret)
46     return inner
47 
48 get_func = get_url()    # 以后想要执行inner的时候,直接调用get_func就行,这时url变量不会反复创建被赋值,节省了运行时间
49 
50 get_func()
View Code

 

转载于:https://www.cnblogs.com/whylinux/p/9551563.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值