433 lines
8.1 KiB
Markdown
433 lines
8.1 KiB
Markdown
# 认识函数
|
|
|
|
## 什么是函数
|
|
|
|
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
|
|
|
|
## 函数的定义与调用
|
|
|
|
```python
|
|
def my_len():
|
|
s = 'hello world'
|
|
length = 0
|
|
for i in s:
|
|
length = length + 1
|
|
print(length)
|
|
|
|
my_len()
|
|
```
|
|
|
|
```
|
|
定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
|
|
|
|
def 是固定的,不能变,他就是定义函数的关键字。
|
|
|
|
空格 为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。
|
|
|
|
函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能
|
|
|
|
括号:是必须加的,先别问为啥要有括号,总之加上括号就对了!
|
|
|
|
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
|
|
|
|
调用:就是 函数名() 要记得加上括号。
|
|
```
|
|
|
|
## 函数的返回值
|
|
|
|
```python
|
|
def my_len():
|
|
s = 'hello world'
|
|
length = 0
|
|
for i in s:
|
|
length = length + 1
|
|
return length
|
|
|
|
str_len = my_len()
|
|
print(str_len)
|
|
```
|
|
|
|
**return关键字的作用**
|
|
|
|
- return 是一个关键字,这个词翻译过来就是“返回”,所以我们管写在return后面的值叫“返回值”。
|
|
- 不写return的情况下,会默认返回一个None
|
|
- 一旦遇到return,结束整个函数。
|
|
- 返回的多个值会被组织成元组被返回,也可以用多个值来接收
|
|
|
|
```python
|
|
def ret_demo():
|
|
return 1,2,'a',['hello','world']
|
|
|
|
ret = ret_demo()
|
|
print(ret)
|
|
```
|
|
|
|
## 函数的参数
|
|
|
|
带参数的函数
|
|
|
|
```python
|
|
def my_len(s):
|
|
length = 0
|
|
for i in s:
|
|
length += 1
|
|
return length
|
|
|
|
ret = my_len('hello world!')
|
|
print(ret)
|
|
```
|
|
|
|
实际的要交给函数的内容,简称实参。
|
|
|
|
在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。
|
|
|
|
1. 按照位置传值:位置参数
|
|
|
|
```python
|
|
def maxnumber(x,y):
|
|
the_max = x if x > y else y
|
|
return the_max
|
|
|
|
ret = maxnumber(10,20)
|
|
print(ret)
|
|
```
|
|
|
|
1. 按照关键字传值:关键字参数。
|
|
|
|
```python
|
|
def maxnumber(x,y):
|
|
the_max = x if x > y else y
|
|
return the_max
|
|
|
|
ret = maxnumber(y = 10,x = 20)
|
|
print(ret)
|
|
```
|
|
|
|
1. 位置、关键字形式混着用:混合传参。
|
|
|
|
```python
|
|
def maxnumber(x,y):
|
|
the_max = x if x > y else y
|
|
return the_max
|
|
|
|
ret = maxnumber(10,y = 20)
|
|
print(ret)
|
|
```
|
|
|
|
位置参数必须在关键字参数的前面
|
|
|
|
对于一个形参只能赋值一次
|
|
|
|
1. 默认参数。
|
|
|
|
```python
|
|
def stu_info(name,age = 18):
|
|
print(name,age)
|
|
|
|
stu_info('aaron')
|
|
stu_info('song',50)
|
|
```
|
|
|
|
1. 默认参数是一个可变数据类型
|
|
|
|
```python
|
|
def demo(a,l = []):
|
|
l.append(a)
|
|
print(l)
|
|
|
|
demo('abc')
|
|
demo('123')
|
|
```
|
|
|
|
1. 动态参数
|
|
|
|
```python
|
|
def demo(*args,**kwargs):
|
|
print(args,type(args))
|
|
print(kwargs,type(kwargs))
|
|
|
|
demo('aaron',1,3,[1,3,2,2],{'a':123,'b':321},country='china',b=1)
|
|
|
|
##动态参数,也叫不定长传参,就是你需要传给函数的参数很多,不定个数,那这种情况下,你就用*args,**kwargs接收,args是元祖形式,接收除去键值对以外的所有参数,kwargs接收的只是键值对的参数,并保存在字典中。
|
|
```
|
|
|
|
## 命名空间和作用域
|
|
|
|
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;
|
|
|
|
在函数的运行中开辟的临时的空间叫做局部命名空间。
|
|
|
|
命名空间一共分为三种:
|
|
|
|
- 全局命名空间
|
|
- 局部命名空间
|
|
- 内置命名空间
|
|
|
|
取值顺序:
|
|
|
|
- 在局部调用:局部命名空间->全局命名空间->内置命名空间
|
|
- 在全局调用:全局命名空间->内置命名空间
|
|
|
|
作用域
|
|
|
|
- 全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
|
|
- 局部作用域:局部名称空间,只能在局部范围内生效
|
|
|
|
### globals和locals方法
|
|
|
|
```python
|
|
print(globals())
|
|
print(locals())
|
|
|
|
def func():
|
|
a = 12
|
|
b = 20
|
|
print(globals())
|
|
print(locals())
|
|
|
|
func()
|
|
```
|
|
|
|
**global**
|
|
|
|
1. 声明一个全局变量。
|
|
2. 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
|
|
|
|
```python
|
|
def func():
|
|
global a
|
|
a = 3
|
|
|
|
func()
|
|
print(a)
|
|
|
|
count = 1
|
|
def search():
|
|
global count
|
|
count = 2
|
|
|
|
search()
|
|
print(count)
|
|
```
|
|
|
|
对可变数据类型(list,dict,set)可以直接引用不用通过global
|
|
|
|
```python
|
|
li = [1,2,3]
|
|
dic = {'name':'aaron'}
|
|
|
|
def change():
|
|
li.append(4)
|
|
dic['age'] = 18
|
|
print(dic)
|
|
print(li)
|
|
|
|
change()
|
|
print(dic)
|
|
print(li)
|
|
```
|
|
|
|
**nonlocal**
|
|
|
|
1. 不能修改全局变量。
|
|
2. 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
|
|
|
|
```python
|
|
def add_b():
|
|
b = 1
|
|
def do_global():
|
|
b = 10
|
|
print(b)
|
|
def dd_nolocal():
|
|
nonlocal b # 应用了上一层的变量b
|
|
b = b + 20
|
|
print(b) # 发生了改变
|
|
dd_nolocal() # 调用函数,导致do_global的命名空间b也改变了
|
|
print(b)
|
|
do_global()
|
|
print(b)
|
|
add_b() # 最上面一层没有变化
|
|
```
|
|
|
|
## 函数的嵌套和作用域链
|
|
|
|
```python
|
|
def mymax(x,y):
|
|
m = x if x > y else y
|
|
return m
|
|
|
|
def maxx(a,b,c,d):
|
|
res1 = mymax(a,b)
|
|
res2 = mymax(res1,c)
|
|
res3 = mymax(res2,d)
|
|
return res3
|
|
|
|
ret = maxx(23,453,12,-13)
|
|
print(ret)
|
|
|
|
# 传入任意多的数字,甚至有重复的,还有非数字(忽略),得到最大的值
|
|
|
|
def my_max(x, y):
|
|
m = x if x > y else y
|
|
return m
|
|
|
|
|
|
def maxx(*nums):
|
|
temp_nums = []
|
|
for i in nums:
|
|
if type(i) is int:
|
|
temp_nums.append(i)
|
|
while len(temp_nums) > 1:
|
|
a_num = temp_nums.pop()
|
|
b_num = temp_nums.pop()
|
|
ret = my_max(a_num, b_num)
|
|
temp_nums.append(ret)
|
|
return temp_nums[0]
|
|
|
|
|
|
ret = maxx(123, 3345, 123, 9999, 123, 345, 345, 667, 123, 435, 657, 16, 21, "aabc", ["a", "b"])
|
|
print(f"数值类型中最大的是{ret}")
|
|
```
|
|
|
|
```python
|
|
def f1():
|
|
print("in f1")
|
|
def f2():
|
|
print("in f2")
|
|
f2()
|
|
|
|
f1()
|
|
```
|
|
|
|
## 函数名的本质
|
|
|
|
函数名本质上就是函数的内存地址
|
|
|
|
1. 可以被引用
|
|
|
|
```python
|
|
def func():
|
|
print('in func')
|
|
|
|
f = func
|
|
|
|
print(f)
|
|
f()
|
|
```
|
|
|
|
1. 可以被当作容器类型的元素
|
|
|
|
```python
|
|
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']()
|
|
```
|
|
|
|
1. 可以当作函数的参数和返回值
|
|
|
|
```python
|
|
def f1():
|
|
print('f1')
|
|
|
|
def func(argv):
|
|
argv()
|
|
return argv
|
|
|
|
f = func(f1)
|
|
f()
|
|
```
|
|
|
|
## 闭包
|
|
|
|
```python
|
|
def func():
|
|
name = 'aaron'
|
|
def inner():
|
|
print(name)
|
|
return inner
|
|
|
|
f = func()
|
|
f()
|
|
```
|
|
|
|
内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数
|
|
|
|
判断闭包函数的方法**closure**
|
|
|
|
```python
|
|
def func():
|
|
name = 'aaron'
|
|
def inner():
|
|
print(name)
|
|
print(inner.__closure__)
|
|
return inner
|
|
|
|
f = func()
|
|
f()
|
|
# 最后运行的结果里面有cell就是闭包
|
|
|
|
name = 'aaron'
|
|
def func():
|
|
def inner():
|
|
print(name)
|
|
print(inner.__closure__)
|
|
return inner
|
|
|
|
f = func()
|
|
f()
|
|
# 输出结果为None,说明不是闭包
|
|
```
|
|
|
|
```python
|
|
def wrapper():
|
|
money = 1000
|
|
def func():
|
|
name = 'apple'
|
|
def inner():
|
|
print(name,money)
|
|
return inner
|
|
return func
|
|
|
|
f = wrapper()
|
|
i = f()
|
|
i()
|
|
```
|
|
|
|
```python
|
|
def func(a,b):
|
|
def inner(x):
|
|
return a*x + b
|
|
return inner
|
|
|
|
func1 = func(4,5)
|
|
func2 = func(7,8)
|
|
print(func1(5),func2(6))
|
|
```
|
|
|
|
```python
|
|
from urllib.request import urlopen
|
|
def func():
|
|
content = urlopen('http://myip.ipip.net').read()
|
|
def get_content():
|
|
return content
|
|
return get_content
|
|
|
|
code = func()
|
|
content = code()
|
|
print(content.decode('utf-8'))
|
|
|
|
content2 = code()
|
|
print(content2.decode('utf-8'))
|
|
``` |