- 函数是一个组织好的 ,可以重复使用的代码段 ,函数可以提高代码的重复利用率
- 函数封装的目的为了复用,减少冗余代码
- python有许多的内置函数可供使用
- 你也可以自己定义函数,这通常被称之为自定义函数
- 函数是可调用对象
1. 函数的定义
def 函数名(参数列表):函数体(代码块)[return返回值]函数名就是标识符,命名要求一样语句块必须缩进,约定4个空格Python的函数没有Return语句,隐式会返回一个None定义中的参数列表成为形式参数,简称是形参函数定义,只是一个声明,不会执行,需要调用调用时写的参数是实际参数,简称是实参
先看几个示例
def hello_word():passdef print_diamond(count):passdef 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 = aif b > max_number:max_number = bif c > max_number:max_number = creturn max_numbermax_num = get_max(22, 23, 21)print(max_num)
3、函数参数
- 函数调用,将实参的值赋值给形参
- 形参本身没有实际值,在函数调用时,传入什么实参,形参就装有什么意义
- 形参:在函数定义时,相当于变量名, 实参: 在函数调用阶段传入的值称为实际参数,简称实参,相当于变量名
- 在调用阶段,实参(变量值)会赋值给形参(变量名)
- 实参与形参的绑定关系只能在函数体内使用,函数调用时生效
3.1)形参和实参的具体使用
位置参数
def f(x,y,z):sum = x+y+zprint(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+zprint(sum)f(1,3)#在定义阶段就已经被赋值,就意味着在调用阶段,可以不用赋值
- 可变参数
在形参前使用表示形参是可变参数,放在一个元组里
形参前面使用*符号,,表示可以接收多个关键字参数,收集的实参名称和值组成一个字典
def add(nums):sum=0for x in nums:sum += xreturn sumadd([1,3,5])add((2,4,5))传入一个可迭代对象,迭代元素求和一个形参可以匹配任意个参数def add(*nums): #放在一个元组里sum=0for x in nums:sum += xprint(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 1def 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) #xhaihuadef func():print(name) #xhaihuafunc()
其实,函数也是定义在作用域中的数据,在执行函数时候,也同样优先在自己的作用域中寻找,没有则向上
作用域,例如
def func():print('xhaihua')func()def execute():print('开始')func() #xhaihuaprint('结束')execute()
函数可以定义在全局作用域,其实函数也可以定义在局部作用域,这样函数被局部作用域和子作用域中调用(函数的嵌套)
def func():print('666')def handless():print("1234")def inner():print('aaa')inner()func()print('结束')handless()
嵌套函数示例: 生成图片验证码(简单版)
pip install pillow代码示例如下:'''#把msyh.ttc拷贝到项目目录下import randomfrom PIL import Image,ImageDraw,ImageFontdef 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 = sizeimg = 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 = textelse: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 codecode = 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 innerv1 = task(11) # v1 = innerv1() #v1() = inner()#def task(age):def inner():print(age)return innerinner_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 requestsfrom 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 valuedef outer(origin):def inner():print("before")res = origin()print("after")return resreturn innerfunc = outer(func)result = func()print(result)
python中支持特殊语法,在某个函数上方使用: @函数名
在python内部会自动执行:函数名()
def outer(origin):def inner():print("before")res = origin()print("after")return resreturn inner@outerdef func():print("我是func函数")value = (11,22,33,44)return valueresult = func()print(result)
