python基础4--函数
一、函数基础
1、函数的基本结构
# 函数的定义
def 函数名():
# 函数内容
pass
# 函数的执行
函数名()
2、参数
- 函数可以传递任意数据类型,任意个数的参数
def func(a1,a2,a3):# a1,a2,a3叫形式参数(形参)
print(a1,a2,a3)
func(1,"a",True)#调用时传递的参数叫实际参数(实参)
- 位置传参(调用函数语句)
def func(a1,a2):
print(a1,a2)
func(1,3)
- 关键字传参(调用函数语句)
关键字传参数和位置传参可以混合使用,位置传入的参数在前,关键字参数在后
def func(a1, a2):
print(a1, a2)
func(a2=99,a1=2)
def func1(a1, a2, a3):
print(a1, a2, a3)
# func(1, 2, a3=9)
# func(1, a2=2, a3=9)
# func(a1=1, a2=2, a3=9)
# func(a1=1, 2,3) # 错误
-
参数默认值
编写函数时,可给每个形参指定默认值。在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。
def func(a1,a2,a3=9,a4=10): print(a1,a2,a3,a4) func(11,22) func(11,22,10) func(11,22,10,100) func(11,22,10,a4=100) func(11,22,a3=10,a4=100) func(11,a2=22,a3=10,a4=100) func(a1=11,a2=22,a3=10,a4=100)
-
默认参数注意事项
函数的默认值慎用可变类型,不传参数时共用一个内存地址
# 如果要想给value设置默认是空列表 # 不推荐(坑) def func(data,value=[]): pass # 推荐 def func(data,value=None): if not value: value = []
def func(data,value=[]): value.append(data) return value v1 = func(1) # [1,] v2 = func(1,[11,22,33]) # [11,22,33,1]
def func(a,b=[]): b.append(a) return b l1 = func(1) l2 = func(2,[11,22]) l3 = func(3) print(l1,l2,l3) # [1,3] [11,22,2] [1,3]
def func(a,b=[]): b.append(a) print(b) func(1) func(2,[11,22,33]) func(3) # [1] # [11, 22, 33, 2] # [1, 3]
-
万能参数(打散)
1、*args
可以接受任意个数的位置参数,并将参数转换成元组
def func(*args): print(args) func(1,2,3,True,[11,22,33,44]) # 输出为(1,2,3,True,[11,22,33,44]) 元组 func(*(1,2,3,4,5)) # 如果不加*号,函数会将序列当成一个元素加入到元组中,*相当于拆包.
拆包
def func(*args): print(args) func(*(1,2,3,4)) func(*[1,2,3,4])
2、**kwargs
可以接受任意个数的关键字参数,并将参数转换成字典。
def func(**kwargs): print(kwargs) func(k1=1,k2="yhp")
拆包
def func(**kwargs): print(kwargs) func(**{'k1':'v1','k2':'v2'}) # kwargs={'k1':'v1','k2':'v2'}
3、*args,**kwargs
可以接受任意个位置参数和关键字参数
def func(*args,**kwargs): print(args,kwargs) func(1,2,3,4,5,k1=2,k5=9,k19=999) func(*[1,2,3],k1=2,k5=9,k19=999) func(*[1,2,3],**{'k1':1,'k2':3}) func(111,222,*[1,2,3],k11='yhp',**{'k1':1,'k2':2}) # (1, 2, 3, 4, 5) {'k1': 2, 'k5': 9, 'k19': 999} # (1, 2, 3) {'k1': 2, 'k5': 9, 'k19': 999} # (1, 2, 3) {'k1': 1, 'k2': 3} # (111, 222, 1, 2, 3) {'k11': 'yhp', 'k1': 1, 'k2': 2}
3、作用域
函数外定义的变量作用域为全局,函数内定义的变量作用域为函数内部,称为局部变量,函数内优先使用局部变量,如果未定义,去父级函数找,最后去全局中查找。函数内变量的值取决于函数调用前,值为多少。
a = 1 def s1(): #注意:在调用之前选择参数值到底是多少. x1 = 666 print(x1) print(a) print(b) b = 2 s1() a = 88888 def s2(): print(a,b) s1() s2()
子作用域中只能 找到父级中的值 ,默认无法重新为父级的变量进行赋值。(global/nonlocal可以强制做)
对于容器类可变类型,函数可以改变其元素
name = [1,2,43] def func(): name.append(999) print(name) func() print(name)
global
name = ["yhp",'happier'] def func(): global name name = '我' func() print(name)
global只能改变全局,不能改变父级
name = "yhp" def func(): name = 'happier' def inner(): global name name = '我' inner() print(name) func() print(name)
nonlocal
name = "yhp" def func(): name = 'happier' def inner(): nonlocal name # 找到上一级的name name = '我' inner() print(name) func() print(name)
4、返回值
- 函数没有返回值时,默认返回None
- 函数有返回值时,语句为:return 返回值.返回值可以是任意东西.
- 函数执行到return 语句,就返回,后面的语句不执行.
- 若返回值为多个,默认将其添加到元组中,返回一个元组.
def compare_num(a,b):
v=a if a>b else b
return v
def func(a,b,c,d):
return a,b,c,d
v = func(1,'happier',[11,22,33,44,55],{'k1':'v1'})
print(v) # (1,'happier',[11,22,33,44,55],{'k1':'v1'}) 元组,
5、函数变量
函数本身也是一种数据类型,函数名对应程序入口地址
- 函数名当作变量来使用
def func():
print(123)
func_list = [func, func, func]
for item in func_list:
v = item()
print(v)
- 函数可以当作参数进行传递
def func(arg):
v1 = arg()
print(v1)
def show():
print(666)
result = func(show)
print(result)
- 函数可以做返回值
name = 'yhp'
def func():
print(name)
def bar():
return func
v = bar()
v()
6、闭包
闭包概念:为函数创建一块区域并为其维护自己数据,以后执行时方便调用。【应用场景:装饰器 / SQLAlchemy源码】
内层函数调用外层函数值,而不执行,变量保持引用,开辟空间内存不释放。
eg1:
def func(name):
def inner():
print(name)
return inner
v1 = func('happier')
v2 = func('yhp')
v1()
v2()
eg2:
info = []
def func(i):
def inner():
print(i)
return inner
for item in range(10):
info.append(func(item))
info[0]()
info[1]()
info[4]()
二、函数进阶
1、装饰器
装饰器:在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。
def func(arg):
def inner():
v = arg()
return v
return inner
# 第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
# 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)=inner
@func
def index():
print(123)
return 666
print(index)
注意
def wrapper(fun):
def inner(*args,**kwargs):
return fun(*args,**kwargs)
print('wrapper')
return inner
@wrapper
def func2():
print('func2')
# 直接执行输出wrapper
# ################## 普通装饰器 #####################
def wrapper(func):
def inner(*args,**kwargs):
print('调用原函数之前')
data = func(*args,**kwargs) # 执行原函数并获取返回值
print('调用员函数之后')
return data
return inner
@wrapper
def index():
pass
# ################## 带参数装饰器 #####################
#flask框架 + django缓存 + 写装饰器实现被装饰的函数要执行N次
def x(counter):
def wrapper(func):
def inner(*args,**kwargs):
data = func(*args,**kwargs) # 执行原函数并获取返回值
return data
return inner
return wrapper
@x(9)
def index():
pass
装饰器建议编写格式
def 外层函数(参数):
def 内层函数(*args,**kwargs):
return 参数(*args,**kwargs)
return 内层函数
装饰器应用格式
@外层函数
def index():
pass
index()
2、lambda表达式
用于表示简单的函数,也称作匿名函数。
# 三元运算,为了解决简单的if else的情况,如:
if 1 == 1:
a = 123
else:
a = 456
a = 123 if 1 == 1 else 456
# lambda表达式,为了解决简单函数的情况,如:
def func(a1,a2):
return a1 + 100
func = lambda a1,a2: a1+100
func1 = lambda : 100
func2 = lambda x1: x1 * 10
func3 = lambda *args,**kwargs: len(args) + len(kwargs)
3、迭代器
对可迭代对象(str/list/tuple/dict/set类创建的对象)中的元素进行逐一获取,有__next__
方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取,不可后退)。
1、创建迭代器
- iter(可迭代对象)
- 可迭代对象.
__iter__()
2、获取迭代器的值
迭代器想要获取每个值:反复调用 val = v1.__next__()
直到报错:StopIteration错误,表示已经迭代完毕。
v1 = "happier"
v2 = iter(v1)
while True:
try:
val = v2.__next__()
print(val)
except StopIteration as e:
break
如何判别一个对象是否是迭代器? 内部是否有__next__方法
。
for循环实现逻辑
v1 = [11,22,33,44]
for item in v1:
print(item)
# 1.内部会将v1转换成迭代器
# 2.内部反复执行 迭代器.__next__()
# 3.取完不报错
可迭代对象
- 内部具有
__iter__()
方法且返回一个迭代器。(*)
v1 = [11,22,33,44]
result = v1.__iter__()
- 可以被for循环
可迭代对象->iter->迭代器->next方法
4、生成器
函数中如果存在yield,那么该函数就是一个生成器函数,调用生成器函数会返回一个生成器,生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值。
python中yield的用法很像return,都是提供一个返回值,但是yield和return的最大区别在于,return一旦返回,则代码段执行结束,但是yield在返回值以后,会交出CUP的使用权,代码段并没有直接结束,而是在此处中断,当调用send()或者next()方法之后,yield可以从之前中断的地方继续执行。
# 生成器函数(内部是否包含yield)
def func():
print('F1')
yield 1
print('F2')
yield 2
print('F3')
yield 100
print('F4')
# 函数内部代码不会执行,返回一个 生成器对象 。
v1 = func()
# 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。
for item in v1:
print(item)
def func():
count = 1
while True:
yield count
count += 1
if count == 100:
return
val = func()
for item in val:
print(item)
yeild from
yield from iterable本质上等于 for item in iterable: yield item的缩写版
def show():
yield 88
yield 99
def func():
yield 1
yield from show()
yield 2
obj = func()
for item in obj:
print(item)
1
88
99
2
在两层嵌套的情况下,值的传递方式是,先把值传递给外层生成器,外层生成器再将值传递给内层生成器,内层生成器在将值反向传递给外层生成器,最终yield出结果。
def fun_inner():
i = 0
while True:
i = yield i
def fun_outer():
yield from fun_inner()
if __name__ == '__main__':
outer = fun_outer()
outer.send(None)
for i in range(5):
print(outer.send(i))
python3才有,一个generator生成器将其部分操作委派给另一个生成器。其产生的主要动力在于使生成器能够很容易分为多个拥有send和throw方法的子生成器,像一个大函数可以分为多个子函数一样简单。Python的生成器是协程coroutine的一种形式,但它的局限性在于只能向它的直接调用者yield值。这意味着那些包含yield的代码不能想其他代码那样被分离出来放到一个单独的函数中。这也正是yield from要解决的.
https://www.cnblogs.com/cnkai/p/7514828.html
https://wenkefendou.gitbooks.io/python3-learning/content/yield_from.html
5、推导式
1. 列表推导式
"""
目的:方便的生成一个列表。
格式:
v1 = [i for i in 可迭代对象 ]
v2 = [i for i in 可迭代对象 if 条件 ] # 条件为true才进行append
"""
v1 = [ i for i in 'happier' ]
v2 = [i+100 for i in range(10)]
v3 = [99 if i>5 else 66 for i in range(10)]
def func():
return 100
v4 = [func for i in range(10)]
v5 = [lambda : 100 for i in range(10)]
result = v5[9]()
def func():
return i
v6 = [func for i in range(10)]
result = v6[5]()
v7 = [lambda :i for i in range(10)]
result = v7[5]()
v8 = [lambda x:x*i for i in range(10)]
# 1.请问 v8 是什么?
# 2.请问 v8[0](2) 的结果是什么?
def num():
return [lambda x:i*x for i in range(4)]
# num() -> [函数,函数,函数,函数]
print([ m(2) for m in num() ]) # [6,6,6,6]
# ##################### 筛选 #########################
v9 = [i for i in range(10) if i > 5]
2. 集合推导式
v1 = { i for i in 'happier' }
注意:重复值会被覆盖
3. 字典推导式
v1 = { 'k'+str(i):i for i in range(10) }
注意:键值重复会被覆盖
4.生成器推导式
def func():
for i in range(10):
yield i
v1 = func()
v2 = (i for i in range(10)) # 生成器推导式,创建了一个生成器,内部循环为执行。
# 没有元组推导式,加括号是生成器推导式
def my_range(counter):
for i in range(counter):
yield i
# 生成器函数
# 请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
# 前者是列表推导式,直接在内存中生成列表[1-10],后者是生成器推导式,内部循环不执行,只有for 循环才执行.
6、递归
函数自己调用自己。(效率低)
斐波那契数列
def func(a,b):
print(b)
func(b,a+b)
func(0,1) #1 1 2 3 5
def func(a):
if a == 5:
return 100000 # 注意递归的返回值
result = func(a+1) + 10
return result
v = func(1) #100040
7、内置函数
-
输入输出
- input
-
强制转换
- int()
- bool()
- list()
- str()
- tuple()
- dict()
- set()
-
数学相关
-
abs() 绝对值
-
float() 转换成浮点数
-
max() 找到最大值
-
min() 找到最小值
-
sum() 求和
-
pow() 乘方
v = pow(2,3) print(v)# 2的3次方
-
round
v = round(1.127,2) print(v) #四舍五入保留几位小数
-
divmod() 两数相除的商和余数
a,b = divmod(1001,5) print(a,b)
请通过分页对数据进行展示 """ 要求: 每页显示10条数据 让用户输入要查看的页面:页码 """ USER_LIST = [] for i in range(1,999): temp = {'name':'yhp-%s' %i,'email':'666%s@qq.com' %i } USER_LIST.append(temp) # 数据总条数 total_count = len(USER_LIST) # 每页显示10条 per_page_count= 10 # 总页码数 max_page_num,a = divmod(total_count,per_page_count) if a>0: max_page_num += 1 while True: pager = int(input('要查看第几页:')) if pager < 1 or pager > max_page_num: print('页码不合法,必须是 1 ~ %s' %max_page_num ) else: """ # 第1页:USER_LIST[0:10] -> 0123456789 # 第2页:USER_LIST[10:20] # 第3页:USER_LIST[20:30] ... """ start = (pager-1) * per_page_count end = pager * per_page_count data = USER_LIST[start:end] for item in data: print(item)
-
-
进制转换相关
-
bin,将十进制转化成二进制
num = 13 v1 = bin(num) print(v1)
-
oct,将十进制转换成八进制
num = 8 v1 = oct(num) print(v1)
-
int,将其他进制转化成十进制
# 二进制转化成十进制 v1 = '0b1101' result = int(v1,base=2) print(result) # 八进制转化成十进制 v1 = '0o1101' result = int(v1,base=8) print(result) # 十六进制转化成十进制 v1 = '0x1101' result = int(v1,base=16) print(result)
-
hex,将十进制转换成十六进制
num = 16 v1 = hex(num) print(v1)
# 1字节等于8位 # IP: 192.168.12.79 -> 001010010 . 001010010 . 001010010 . 001010010 # 1. 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。 ip = "192.168.12.79" ip_list = ip.split('.') # ['192','168','12','79'] result = [] for item in ip_list: result.append(bin(int(item))) print(','.join(result)) # 2. 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制: # 0010100100001010010001010010001010010 -> 十进制的值。 # 3232238671 ip='192.168.12.79' bit_str='' ip_list=ip.split(".") for i in ip_list: bit=bin(int(i))[2:] long=len(bit) if long<8: bit=(8-long)*"0"+bit bit_str+=''.join(bit) num=int(bit_str,base=2) print(num)
-
-
编码相关
-
chr,将十进制数字转换成 unicode 编码中的对应字符串。
v = chr(99) print(v)
-
ord,根据字符在unicode编码中找到其对应的十进制。
num = ord('中')
-
应用:random模块
import random def get_random_code(length=6): data = [] for i in range(length): v = random.randint(65,90) data.append(chr(v)) return ''.join(data) code = get_random_code() print(code)
import random # 导入一个模块 v = random.randint(起始,终止) # 得到一个随机数
-
8、高级内置函数
直接上例子:
# coding=utf-8
pool1 = [1,2,3,4]
pool2 = ['a','b','c','d']
## map()
r1 = list(map(lambda x: x*2,pool1))
print(r1) #[2, 4, 6, 8]
## reduce()
from functools import reduce
r2 = reduce(lambda x,y: x*y,pool1,100)
print(r2) #2400
## filter()
r3 = list(filter(lambda x: x>2,pool1))
print(r3) #[3, 4]
## zip()
r4 = list(zip(pool1,pool2))
print(r4) #[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
map
map()函数的主要作用是可以把一个方法依次执行在一个可迭代的序列上,比如List等,具体的信息如下:
- 基础语法:map(fun, iterable)
- 参数:fun是map传递给定可迭代序列的每个元素的函数。iterable是一个可以迭代的序列,序列中的每一个元素都可以执行fun
- 返回值:map object
好了,大白话就是利用map我们可以把一个函数fun 执行到序列iter的每一个元素上,用例子非常好理解~
def add_one(n):
return n + 1
numbers = [1, 2, 3, 4, 5]
result = map(add_one, numbers)
print(result)
print(type(result))
print(list(result))
Out:<map object at 0x00000260F508BE80>
<class 'map'>
[2, 3, 4, 5, 6]
lambda函数版:
numbers = (1, 2, 3, 4, 5) # 迭代对象为tuple
result = map(lambda x: x + 1, numbers)
print(list(result)) # 输出对象为list
Out:[2, 3, 4, 5, 6]
# List of strings
words = ['paris', 'xiaobai','love']
# 把数组中每个元素变为List
test = list(map(list, words))
print(test)
Out: [['p', 'a', 'r', 'i', 's'], ['x', 'i', 'a', 'o', 'b', 'a', 'i'], ['l', 'o', 'v', 'e']]
nums = [3,"23",-2]
print(list(map(float,nums)))
Out: [3.0, 23.0, -2.0]
filter
filter()方法借助于一个函数来过滤给定的序列,该函数测试序列中的每个元素是否为真。
- 基础语法:filter(fun, iterable)
- 参数:fun测试iterable序列中的每个元素执行结果是否为True,iterable为被过滤的可迭代序列
- 返回值:可迭代的序列,包含元素对于fun的执行结果都为True
简而言之就是filter可以帮助我们根据给出的条件过滤一组数据并返回结果
# 过滤元音的方法
def fun(variable):
letters = ['a', 'e', 'i', 'o', 'u']
if (variable in letters):
return True
else:
return False
# 给定序列
sequence = ['I', 'l', 'o', 'v', 'e', 'p', 'y','t','h','o','n']
# 根据条件得出结果
filtered = list(filter(fun, sequence))
print(filtered)
Out:['o', 'e', 'o']
# 判断为正数
def positive(num):
if num>0:
return True
else:
return False
#判断偶数
def even(num):
if num % 2==0:
return True
else:
return False
numbers=[1,-3,5,-20,0,9,12]
positive_nums = list(filter(positive, numbers))
print(positive_nums) # 输出正数 list
even_nums = tuple(filter(even,numbers))
print(even_nums) #输出偶数 tuple
Out:[1, 5, 9, 12]
(-20, 0, 12)
总结:要先有一个,能返回True或者False的方法,或者表达式作为过滤条件就行了
lambda函数版:
numbers = [0, 1, 2, -3, 5, -8, 13]
# 提取奇数
result = filter(lambda x: x % 2, numbers)
print("Odd Numbers are :",list(result))
# 提取偶数
result = filter(lambda x: x % 2 == 0, numbers)
print("Even Numbers are :",list(result))
#提取正数
result = filter(lambda x: x>0, numbers)
print("Positive Numbers are :",list(result))
Out:Odd Numbers are : [1, -3, 5, 13]
Even Numbers are : [0, 2, -8]
Positive Numbers are : [1, 2, 5, 13]
reduce
Reduce是一个非常有用的函数,用于在列表上执行某些计算并返回结果。它将滚动计算应用于列表中的连续值。例如,如果要计算整数列表的累积乘,或者求和等等
- 基础语法:reduce(function, iterable)
- 参数:fun是连续作用于iterable每一个元素的方法,新的参数为上一次执行的结果,iterable为被过滤的可迭代序列
- 返回值:最终的function返回结果
在Python 2中,reduce()是一个内置函数。但是,在Python 3中,它被移动到functools模块。因此,要使用前我们需要导入,这里我的环境是Python 3.6
from functools import reduce # Python 3
def multiply(x, y):
return x*y
numbers = [1,2,3,4]
print(reduce(multiply, numbers))
Out:24
lambda函数:
from functools import reduce # Python 3
numbers = [1,2,3,4]
result_multiply = reduce((lambda x, y: x * y), numbers)
result_add = reduce((lambda x,y: x+y), numbers)
print(result_multiply)
print(result_add)
Out:24
10
zip
zip()的目的是映射多个容器的相似索引,以便它们可以仅作为单个实体使用。
- 基础语法:zip(*iterators)
- 参数:iterators为可迭代的对象,例如list,string
- 返回值:返回单个迭代器对象,具有来自所有容器的映射值
>>> list(zip([1,23,3],[213,45,2])) #两个列表长度一致
[(1, 213), (23, 45), (3, 2)]
>>> list(zip([1,23,3],[213,45,2,34,54])) #两个列表长度不一致,以短的为准
[(1, 213), (23, 45), (3, 2)]
keys = ['name','age']
values = ['xiaobai',18]
my_dict = dict(zip(keys,values))
print(my_dict)
Out:{'name': 'xiaobai', 'age': 18}
zip可以支持多个对象,比如下面的例子
name = [ "xiaobai", "john", "mike", "alpha" ]
age = [ 4, 1, 3, 2 ]
marks = [ 40, 50, 60, 70 ]
# using zip() to map values
mapped = list(zip(name, age, marks))
print ("The zipped result is : "mapped)
Out:The zipped result is : [('xiaobai', 4, 40), ('john', 1, 50), ('mike', 3, 60), ('alpha', 2, 70)]
解包:
names, ages, marks = zip(*mapped)
print ("The name list is : ",names)
print ("The age list is : ",ages)
print ("The marks list is : ",marks)
Out: The name list is : ('xiaobai', 'john', 'mike', 'alpha')
The age list is : (4, 1, 3, 2)
The marks list is : (40, 50, 60, 70)