Files
python-book/01.基础语法/03.python认识函数.md
2025-09-09 11:09:08 +08:00

433 lines
8.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 认识函数
## 什么是函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
## 函数的定义与调用
```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)
```
对可变数据类型listdictset可以直接引用不用通过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'))
```