- 函数是一个组织好的 ,可以重复使用的代码段 ,函数可以提高代码的重复利用率
- 函数封装的目的为了复用,减少冗余代码
- python有许多的内置函数可供使用
- 你也可以自己定义函数,这通常被称之为自定义函数
- 函数是可调用对象
1. 函数的定义
def 函数名(参数列表):
函数体(代码块)
[return返回值]
函数名就是标识符,命名要求一样
语句块必须缩进,约定4个空格
Python的函数没有Return语句,隐式会返回一个None
定义中的参数列表成为形式参数,简称是形参
函数定义,只是一个声明,不会执行,需要调用
调用时写的参数是实际参数,简称是实参
先看几个示例
def hello_word():
pass
def print_diamond(count):
pass
def get_max(a, b, c):
pass
关于上面这段代码,你要记住下面3个结论
示例1, 定义并调用没有参数的函数
def hello_word():
print('hello world')
hello_word()
示例2, 定义并调用有一个参数的函数
def print_diamond(count):
"""
输出菱形
"""
for i in range(count):
if i <= count//2:
print(" "*(count//2-i) + "*"*(2*i + 1))
else:
print(" "*(i - count//2) + "*"*((count-i)*2-1))
print_diamond(11)
示例3, 定义并调用有三个参数的函数
def get_max(a, b, c):
max_number = a
if b > max_number:
max_number = b
if c > max_number:
max_number = c
return max_number
max_num = get_max(22, 23, 21)
print(max_num)
3、函数参数
- 函数调用,将实参的值赋值给形参
- 形参本身没有实际值,在函数调用时,传入什么实参,形参就装有什么意义
- 形参:在函数定义时,相当于变量名, 实参: 在函数调用阶段传入的值称为实际参数,简称实参,相当于变量名
- 在调用阶段,实参(变量值)会赋值给形参(变量名)
- 实参与形参的绑定关系只能在函数体内使用,函数调用时生效
3.1)形参和实参的具体使用
位置参数
def f(x,y,z):
sum = x+y+z
print(sum)
f(1,2,3) #调用
按照参数定义顺序传入实参 (x=1,y=2,z=3)
位置实参: 按位置先后进行传参 (按照从左到右的顺序依次定义的参数)
A: 位置形参: 按从左到右的顺序直接定义的变量名 (函数定义阶段)
def func(x,y):
print(x,y)
特点: 必须被传值B: 位置实参: 函数调用传入的值 (在函数调用阶段)
func(2,3)
func(y=2,x=5)关键字参数
指名道姓的进行传参,可以颠倒位置传参,名字指向谁,就是谁
注意: 位置实参需要出现在关键字实参之前
特点: 指名道姓的进行传参,可以颠倒位置传参
- 默认参数(形参)
在定义函数阶段,就已经被赋值的形参,称为默认参数
def f(x,y,z=5):
sum = x+y+z
print(sum)
f(1,3)
#在定义阶段就已经被赋值,就意味着在调用阶段,可以不用赋值
- 可变参数
在形参前使用表示形参是可变参数,放在一个元组里
形参前面使用*符号,,表示可以接收多个关键字参数,收集的实参名称和值组成一个字典
def add(nums):
sum=0
for x in nums:
sum += x
return sum
add([1,3,5])
add((2,4,5))
传入一个可迭代对象,迭代元素求和
一个形参可以匹配任意个参数
def add(*nums): #放在一个元组里
sum=0
for x in nums:
sum += x
print(sum)
add(3,6,9)
在形参前使用*表示形参是可变参数
收集多个实参为一个tuple
#关键字参数的可变参数
def showconfig(**kwargs):
for k,v in kwargs.items():
print('{} = {}'.format(k,v))
showconfig(host='127.0.0.1',port='8080',username='wayne')
形参前面使用**符号,表示可以接收多个关键字参数
收集的实参名称和值组成一个字典
总结:
- 位置可变参数和关键字可变参数
- 不能为同一个形参重复赋值
- 位置可变参数在形参前使用一个星号*
- 关键字可变参数在形参前使用2个星号**
- 位置可变和关键字可变参数都可以收集若干个实参,位置: tuple,关键字:dict
- 混合使用的时候,可变参数放在参数列表的最后,普通参数需要放在参数列表前面,位置可变参数需要在关键字参数之前
- 位置形参必须在默认值形参的前面
def fn(x,y,*args,**kwargs):
print(x)
print(y)
print(args)
print(kwargs)
fn(3,5,7,9,10,a=1,b='python') # x=3,y=5,(7,9,10),{'a':1,'b':'python'}
fn(3,5,a=1,b='python') #3,5,(),{'a': 1, 'b': 'python'}
fn(7,9,y=5,x=3,a=1,b='python') #TypeError: fn() got multiple values for argument 'y'
- keyword-only参数
如果在一个星号参数后,或者一个位置可变参数后,出现一个普通参数,该参数不是普通的参数,而是keyword-only参数
def fn(*args,x):
print(x)
print(args)
fn(3,5,x=7)
fn(3,5) #错误fn() got multiple values for argument 'y'
def fn(**kwargs,x):
print(x)
print(kwargs)
fn(3,5)
报错
File "<ipython-input-47-89a0d4d3df0a>", line 1
def fn(**kwargs,x):
^
SyntaxError: invalid syntax
def fn(*,x,y):
print(x,y)
fn(x=5,y=6)
*号之后,普通形参都变成必须给出的keyword-only参数
def fn(y,*args,x=5):
print('x={},y={}'.format(x,y))
print(args)
fn(1,2,3,x=10) #x=10,y=1 (2, 3)
fn(1,2,y=3,x=10) #TypeError: fn() got multiple values for argument 'y'
说明: x是keyword-only参数
4、函数嵌套
python中以函数为作用域,在作用域中定义的相关数据(变量)只能被当前作用域或子作用域使用
name="xhaihua"
print(name) #xhaihua
def func():
print(name) #xhaihua
func()
其实,函数也是定义在作用域中的数据,在执行函数时候,也同样优先在自己的作用域中寻找,没有则向上
作用域,例如
def func():
print('xhaihua')
func()
def execute():
print('开始')
func() #xhaihua
print('结束')
execute()
函数可以定义在全局作用域,其实函数也可以定义在局部作用域,这样函数被局部作用域和子作用域中调用(函数的嵌套)
def func():
print('666')
def handless():
print("1234")
def inner():
print('aaa')
inner()
func()
print('结束')
handless()
嵌套函数示例: 生成图片验证码(简单版)
pip install pillow
代码示例如下:
'''
#把msyh.ttc拷贝到项目目录下
import random
from PIL import Image,ImageDraw,ImageFont
def create_image_code(img_file_path,text=None,size=(60,30),node="RGB",bg_color=(255,255,255)):
_letter_cases='abcdefghjkmnpqrstuywx'
_upper_cases= _letter_cases.upper()
_numbers = ''.join(map(str,range(3,10)))
chars = ''.join((_letter_cases,_upper_cases,_numbers))
width,heigh = size
img = Image.new(node,size,bg_color)
draw = ImageDraw.Draw(img)
def get_chars():
return random.sample(chars,6)
def create_lines():
line_num = random.randint(*(1,2))
for i in range(line_num):
begin = (random.randint(0,size[0]),random.randint(0,size[1]))
end = (random.randint(0,size[0]),random.randint(0,size[1]))
draw.line([begin,end],fill=(0,0,0))
def create_points():
chance = min(108,max(0,int(2)))
for w in range(width):
for h in range(heigh):
tmp=random.randint(0,180)
if tmp>100 - chance:
draw.point((w,h),fill=(0,0,0))
def create_node():
if text:
code_string = text
else:
char_list = get_chars()
code_string = ''.join(char_list)
font = ImageFont.truetype('msyh.ttc',size=15)
draw.text([0,0],code_string,"green",font=font)
create_lines()
create_points()
code = create_node()
with open(img_file_path,mode='wb') as img_object:
img.save(img_object)
return code
code = create_image_code("a2.png")
print(code)
作用域总结:
- 优先在自己的作用域找,自己没有就去上级作用域
- 在作用域中寻找值时,要确保值是什么
- 分析函数的执行,并确保函数的作用域
5、闭包
闭包简而言之就是将数据封装在一个包(区域)中,使用的时候在去里面取(本质上闭包是基于函数
嵌套的一种特殊嵌套)
场景1: 将数据封装到包里,防止污染全局
def func(age):
name="xhaihua"
def f1():
print(name,age)
def f2():
print(name,age)
f1()
f2()
场景2: 封装数据在一个包,使用的时候去取
def task(age):
def inner():
print(age)
return inner
v1 = task(11) # v1 = inner
v1() #v1() = inner()
#
def task(age):
def inner():
print(age)
return inner
inner_func_list = []
for val in [11,22,33]:
inner_func_list.append(task(val))
inner_func_list[0]()
inner_func_list[1]()
inner_func_list[2]()
import requests
from concurrent.futures.thread import ThreadPoolExecutor
#下载文件
def task(url):
res = requests.get(
url=url,
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36"
}
)
return res.content
#保存文件
def outer(file_name):
def done(arg):
content = arg.result()
with open(file_name,mode='wb') as file_object:
file_object.write(content)
return done
#线程池
POOL = ThreadPoolExecutor(10)
video_list = [
("乌云.mp4","https://video.699pic.com/videos/93/62/02/b_Uc9dpeHc9DhE1592936202_10s.mp4"),
("光线.mp4","https://video.699pic.com/videos/81/39/90/a_ImItRvbQye9G1592813990_10s.mp4")
]
for item in video_list:
#print(item[0],item[1])
#取线程池取,让其做事情
future = POOL.submit(task, url=item[1])
#执行保存
future.add_done_callback( outer(item[0]))
6、装饰器
def func():
print("我是func函数")
value = (11,22,33,44)
return value
def outer(origin):
def inner():
print("before")
res = origin()
print("after")
return res
return inner
func = outer(func)
result = func()
print(result)
python中支持特殊语法,在某个函数上方使用: @函数名
在python内部会自动执行:函数名()
def outer(origin):
def inner():
print("before")
res = origin()
print("after")
return res
return inner
@outer
def func():
print("我是func函数")
value = (11,22,33,44)
return value
result = func()
print(result)