第五章.函数
5.1三元运算(三目运算)
v = 前面 if 条件 else 后面
if 条件:
v = '前面'
else:
v = '后面'
# 让用户输入值,如果值是整数,则转换成整数,否则赋值为None
data = input('>>>')
value = int(data) if data.isdecimal() else None
5.2函数编程
5.2.1面向过程编程
可读性差/可重用性差
# 发送邮件的程序
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('要发送的内容。', 'plain', 'utf-8')
msg['From'] = formataddr(["李邵奇", '自己邮箱地址'])
msg['To'] = formataddr(["老板", '要发送目标邮箱地址'])
msg['Subject'] = "情爱的导演"
server = smtplib.SMTP("smtp.126.com", 25)
server.login("自己邮箱地址", "自己邮箱密码")
server.sendmail('自己邮箱地址', ['要发送目标邮箱地址', ], msg.as_string())
server.quit()
5.2.2函数型编程
-
本质:将N行代码拿到别处并给他起个名字,以后通过名字就可以找到这段代码并执行。
-
适用于代码重复执行或代码量特别多超过一屏,可以选择通过函数进行代码的分割。
# 函数的定义
def 函数名():
# 函数内容
pass
# 函数的执行
函数名()def get_list_first_data():
v = [11,22,33,44]
print(v[0])
get_list_first_data() # 注意:函数如果不被调用,则内部代码永远不会被执行。
5.3参数
-
可以传任意参数,任意类型
-
严格按照顺序传参数:位置方式传参位于关键字传参之前
def get_list_first_data(aaa): # aaa叫形式参数(形参)
v = [11,22,33,44]
print(v[aaa])
get_list_first_data(1) # 2/2/1调用函数时传递叫:实际参数(实参)
get_list_first_data(2)
get_list_first_data(3)
get_list_first_data(0)
# 1. 请写一个函数,函数计算列表 info = [11,22,33,44,55] 中所有元素的和。
def get_sum():
info = [11,22,33,44,55]
data = 0
for item in info:
data += item
print(data)
get_sum()
# 2. 请写一个函数,函数计算列表中所有元素的和。
def get_list_sum(a1):
data = 0
for item in a1:
data += item
print(data)
get_list_sum([11,22,33])
get_list_sum([99,77,66])
v1 = [8712,123,123]
get_list_sum(v1)
# 3. 请写一个函数,函数将两个列表拼接起来。
def join_list(a1,a2):
result = []
result.extend(a1)
result.extend(a2)
print(result)
join_list([11,22,33],[55,66,77]
# 4. 计算一个列表的长度
def my_len(arg):
count = 0
for item in arg:
count += 1
print(count)
v = [11,22,33]
my_len(v)
len(v)
5.3.1位置传参【执行】
def func(a1,a2):
print(a1,a2)
func(1,3)
5.3.2关键字传参【执行】
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) # 错误
5.3.3默认参数【定义】
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)
5.3.4万能参数(打散)
*args
-
可以接受任意个数的位置参数,并将参数转换成元组。
-
调用函数无 *
def func(*args):
print(args)
func(1,2,3,4) -
调用函数有 *
def funcs(*args):
print(args)
func(*(1,2,3,4))
func(*[1,2,3,4])
**kwargs
-
可以接受任意个数的关键字参数,并将参数转换成字典。
-
调用函数无 **
def func(**kwargs):
print(kwargs)
func(k1=1,k2="alex") -
调用函数有**
def func(**kwargs):
print(kwargs)
func(**{'k1':'v2','k2':'v2'}) # kwargs={'k1':'v2','k2':'v2'}
5.4返回值
默认返回值:None
def func(arg):
# ....
return 9 # 返回值为9 默认:return None
val = func('adsfadsf')
# 1. 让用户输入一段字符串,计算字符串中有多少A字符的个数。有多少个就在文件a.txt中写多少个“李邵奇”。
def get_char_count(data):
sum_counter = 0
for i in data:
if i == 'A':
sum_counter += 1
return sum_counter
def write_file(line):
if len(line) == 0:
return False # 函数执行过程中,一旦遇到return,则停止函数的执行。
with open('a.txt',mode='w',encoding='utf-8') as f:
f.write(line)
return True
content = input('请输入:')
counter = get_char_count(content)
write_data = "李邵奇" * counter
status = write_file(write_data)
if status:
print('写入成功')
else:
print('写入失败')
# 1. 写函数,计算一个列表中有多少个数字,打印: 列表中有%s个数字。
# 提示:type('x') == int 判断是否是数字。
"""
# 方式一:
def get_list_counter1(data_list):
count = 0
for item in data_list:
if type(item) == int:
count += 1
msg = "列表中有%s个数字" %(count,)
print(msg)
get_list_counter1([1,22,3,'alex',8])
# 方式二:
def get_list_counter2(data_list):
count = 0
for item in data_list:
if type(item) == int:
count += 1
return count
v = get_list_counter1([1,22,3,'alex',8])
msg = "列表中有%s个数字" %(v,)
print(msg)
"""
# 2. 写函数,计算一个列表中偶数索引位置的数据构造成另外一个列表,并返回。
"""
# 方式一:
def get_data_list1(arg):
v = arg[::2]
return v
data = get_data_list1([11,22,33,44,55,66])
# 方式二:
def get_data_list2(arg):
v = []
for i in range(0,len(arg)):
if i % 2 == 0:
v.append(arg[i])
return v
data = get_data_list2([11,22,33,44,55,66])
"""
# 3. 读取文件,将文件的内容构造成指定格式的数据,并返回。
"""
a.log文件
alex|123|18
eric|uiuf|19
...
目标结构:
a. ["alex|123|18","eric|uiuf|19"] 并返回。
b. [['alex','123','18'],['eric','uiuf','19']]
c. [
{'name':'alex','pwd':'123','age':'18'},
{'name':'eric','pwd':'uiuf','age':'19'},
]
"""
5.5作用域
注意:全局变量以后必须全部大写
5.5.1 global/nonlocal
-
py文件:全局作用域
-
函数:局部作用域。
-
一个函数是一个作用域
def func():
x = 9
print(x)
func()
print(x) -
作用域中查找数据规则:优先在自己的作用域找数据,自己没有就去 "父级" -> "父级" -> 直到全局,全部么有就报错。注意:父级作用域中的值到底是什么?
x = 10
def func():
x = 9
print(x)
def x1():
x = 999
print(x)
func() # 9
#原因:只是调取了函数func,所以x会得到一值,而函数X1没被调取,故不运行。x = 10
def func():
x = 8
print(x)
def x1():
print(x)
x1()
x = 9
x1()
x = 10 #8
print(x) #8
#9
func() #10 -
子作用域中只能 找到父级中的值 ,默认无法重新为父级的变量进行赋值。(global/nonlocal可以强制做)
#例一:
x = 10
def func(): #8
x = 8 #这一步是在自己的作用域中在创建一个x,而父级的x并没有改变
print(x)
func()
#例二:
data = [11,22,33]
def func():
data.append(44) #直接将将44追加进data,而不是赋值
print(data)
func() #[11,22,33,44]
print(data) #[11,22,33,44]#对全局变量进行赋值
#**************global***************
#例一:
data = ['张三','李四']
def func():
global name #global后面添加想要被重新赋值的全局变量
data = ['王二']
func()
print(data) #['王二']
#例二:
name = "老男孩"
def func():
name = 'alex'
def inner():
global name
name = 999
inner()
print(name) #'alex'
func()
print(name) #999
#************nonlocal***************
name = "老男孩"
def func():
name = 'alex'
def inner():
nonlocal name # 找到上一级的name
name = 999
inner()
print(name) #999
func()
print(name) #"老男孩"
-
5.5.2 递归
递归就是函数自己调用自己(效率低)
def func():
print(1)
func()
func()
# 递归的返回值
def func(a):
if a == 5:
return 100000
result = func(a+1) + 10
v = func(1)
name = 'alex'
def func():
def inner():
print(name)
return inner
v =func()
5.6函数相关
5.6.1函数小高级
5.6.1.1.函数名当作变量来使用
def func():
return 123
func_list1 = [func,func,func]
func_list2 = [func(),func(),func()]
print(func_list1) #func为函数的内存地址
print(func_list2)
info = {
'k1':func,
'k2':func(),
}
print(info)
5.6.1.2.函数可以当作参数进行传递
def func(arg):
v1 = arg()
print(v1)
def show():
print(666)
result = func(show)
print(result)
5.6.2函数中高级
5.6.2.1.函数可以做返回值
def func()
print(123)
def bar()
return func
v = bar()
v()
5.6.2.2.闭包
为函数创建一块区域(内部变量供自己使用),为他以后执行提供数据。
注意:函数在何时被创建
5.6.2.3.高阶函数
-
对函数进行赋值
-
把函数作为参数进行传递
-
把函数当做返回值
5.6.2.3 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
# 练习题1 USER_LIST = [] def func0(x): v = USER_LIST.append(x) #这一步是将x追加到USER_LIST,是对全局变量进行修改,本身不能产生一个新值,所以v接收不到值,导致最后结果输出为None return v result = func0('alex') print(result) #None # 练习题2 def func0(x): v = x.strip() #这一步是对字符串进行操作,去掉x两边空格,会产生一个列表 return v result = func0(' alex ') print(result) #'alex'
总结:列表所有方法基本上都是返回None;字符串的所有方法基本上都是返回新值
5.7内置函数
5.7.1输入输出:
-
input()
-
print()
5.7.2数学相关:
-
max,找最大值
v = [1,2,311,21,3]
result = max(v)
print(result) #311 -
min,找最小值
v = [1,2,311,21,3]
result = min(v)
print(result) #1 -
sum,求和
v = [1,2,311,21,3]
result = sum(v)
print(result) #338 -
abs,绝对值
v = -12
result = abs(v)
print(result) #12 -
float,转换成浮点型(小数)
v = 55
v1 = float(55)
print(v1) #55.0 -
divmod,两数相除的商和余数
#法一:
a,b = divmod(1001,10)
print(a,b) #100 1
#法二:
a = divmod(1001,10)
print(a) #结果得到的是一个元组(100,1)分页展示:
# 练习题 请通过分页对数据进行展示
"""
要求:
每页显示10条数据
让用户输入要查看的页面:页码
"""
USER_LIST = []
for i in range(1,836):
temp = {'name':'你少妻-%s' %i,'email':'123%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)
5.7.3强制转换:
-
str()
-
bool()
-
int()
-
list()
-
tuple()
-
dict()
-
set()
5.7.4.进制转换
-
bin,将十进制转换为二进制(0b 开头)
num = 13
v1 = bin(num)
print(v1) #0b1101 -
oct,将十进制转换为八进制(0o 开头)
num = 13
v1 = oct(num)
print(v1) #0o15 -
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,将十进制转换成十六进制(0x 开头)
num = 16
v1 = hex(num)
print(v1)
5.7.5编码相关
-
chr:将十进制数字转换为unicode编码中的字符串。
v = chr(100)
print(v) #d -
ord:根据字符在unicode编码中的的对应关系找到其对应的十进制
num = ord('中')
-
应用
import random
v = random.randint(起始位置,结束位置) #得到一个随机生成做一个随机生成码:
import random #导入随机模块
def get_random_code(length=6): #创建一个随机生成码,字符串默认长度为6
data = []
for i in range(length): #进行字符串长度次循环
v = random.randint(0,100) #生成1~100内的随机数
data.append(chr(v)) #将这个随机数转换为二进制数加入到列表中
return ''.join(data) #调用随机模块并将得到的返回值赋值给code
code = get_random_code()
print(code)
5.7.6其他
-
len
-
open
-
range
-
id
-
type查看类型
class Foo:
pass
obj = Foo()
if type(obj) == Foo: #查看obj是是不是Foo类的对象
print('obj是Foo类的对象') -
issubclass 判断参数 class 是否是类型参数 xx 的子类
class Base:
pass
class Base1(Base):
pass
class Foo(Base1):
pass
class Bar:
pass
print(issubclass(Bar,Base)) #False
print(issubclass(Foo,Base)) #True -
isinstance
class Base(object):
pass
class Foo(Base):
pass
obj = Foo()
print(isinstance(obj,Foo)) # 判断obj是否是Foo类或其基类的实例(对象)
print(isinstance(obj,Ba -
super
#例一:
class Base(object):
def func(self):
print('base.func')
return 123
class Foo(Base):
def func(self):
v1 = super().func()
print('foo.func',v1)
obj = Foo()
obj.func()
# super().func() 去父类中找func方法并执行class Bar(object):
def func(self):
print('bar.func')
return 123
class Base(Bar):
pass
class Foo(Base):
def func(self):
v1 = super().func()
print('foo.func',v1)
obj = Foo()
obj.func()
# super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)class Bar(object):
def func(self):
print('bar.func')
return 123
class Base(Bar):
pass
class Foo(Base):
def func(self):
v1 = super().func()
print('foo.func',v1)
obj = Foo() #'bar.func'
obj.func() #'foo.func',123
# super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
5.7.7高级一点的内置函数
1.map
-
格式:map(v1,v2)
v1必须是一个函数,v2必须是一个可迭代类型(能被for循环)。循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回。
-
例子:
v1 = [11,22,33,44]
result = map(lambda x :x+100,v2) #自动将新生成的元素加入到一个新列表中
print(result) #<map object at 0x0000000002928B70>
print(type(result)) #<class 'map'>
print(list(result)) #特殊,必须加list()
#[111, 122, 133, 144]
2.filter
过滤器,该函数有两个参数,第一个参数是一个函数,第二个是一个序列,
函数的返回值是使得第一个参数中的函数为True的序列中的元素.
#法一:
v1 = [11,22,33,'qwe',44,'rt']
def func(x):
if type(x) == int: #判断数据类型是不是数字
return True
return False
result = filter(func,v1) #result接受的是使得第一个参数中的函数为True的序列中的元素.
print(list(result)) #[11, 22, 33, 44]
#法二:
v1 = [11,22,33,'qwe',44,'rt']
result = filter(lambda x:True if type(X) == int else False,v1)
print(list(result)) #[11, 22, 33, 44]
#法三:
v1 = [11,22,33,'qwe',44,'rt']
result = filter(lambda x:type(x) == int,v1)
print(list(result))
3.reduce
在Python中是一个函数,使用它需要引入**.用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果
-
格式:reduce(函数,有两参数 ,可迭代对象,可选,初始参数)
#法一:
import functools
v1 = ['wo','hao','xiang','ni']
def func(x,y):
return x+y
result = functools.reduce(func,v1)
print(result)
#法二:
import functools
v1 = ['wo','hao','xiang','ni']
result = functools.reduce(lambda x,y:x+y,v1)
print(result)
5.8装饰器
5.8.1目的
在不改变原函数的基础上,在函数执行前后自定义功能
5.8.2 应用场景
想要为函数扩展功能时可以用装饰器
5.8.2.1普通装饰器
#基本格式:
def func(arg):
def inner(*args,**kwargs)
print('before')
data = arg(*args,**kwargs)
print('after')
return data
return inner
#例一:
def func(arg):
def inner():
data = arg()
return inner
def f1():
print(123)
return 666
v1 = func(f1) #arg = f1 返还一个inner函数
result = v1() #执行inner函数
print(result) #None 因为inner()执行后没有返回值,默认返回None
#例二:
def func(arg):
def inner():
return arg()
return inner
def f1():
print(123)
return 666
v1 = func(f1) #arg = f1 返还一个inner函数
result = v1() #执行inner函数,返还f1函数——>打印123,返还666
print(result) #666
5.8.2.2带参数的装饰器
应用场景:flask框架 / django缓存 / 写装饰器实现被装饰的函数要执行N次
def x(counter):
def wrapper(func):
def inner(*args,**kwargs):
data = func(*args,**kwargs) # 执行原函数并获取返回值
return data
return inner
return wrapper
练习题
# 习题一:
# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。
def xxx(counter):
def wrapper(func):
def inner(*args,**kwargs):
v = []
for i in range(counter):
data = func(*args,**kwargs) # 执行原函数并获取返回值
v.append(data)
return v
return inner
return wrapper
5.9迭代器
5.9.1基本知识
-
用途:对某种对象(str/list/tuple/dict/set类创建的对象-可迭代对象)中的元素进行逐一获取
-
表象:具有
__next__
方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取) -
判断:内部是否有 next方法 。
#法一:
v = [11,22,33,44]
v1 = iter(v) #将列表转换为迭代器
print(v1)
#法二:
v = [11,22,33,44]
v1 = v.__iter__()
print(v1) #将列表转换为迭代器 -
想获取每个值:反复调用"v1 = v1.next()"
v = [11,22,33,44]
#列表转换为迭代器
v1 = iter(v)
result1 = v1.__next__()
print(result1) #11
result2 = v1.__next__()
print(result2) #22
result3 = v1.__next__()
print(result3) #33
result4 = v1.__next__()
print(result4) #44
result5 = v1.__next__()
print(result5) #报错
#字符串转换为迭代器
v1 = 'alex'
v2 = iter(v1)
while True:
v3 = v2.__next__()
print(v3)
#程序跑到最后会出错,显示StopIteration错误,表示迭代已完成
#改进:
v1 = 'alex'
v2 = iter(v1)
while True:
try:
v3 = v2.__next__()
print(v3)
except Exception as e:
break -
for循环:
v = [11,22,33]
for item in v: #1.内部会将v转换为迭代器
print(item) #2.内部反复执行:迭代器.__next__()
#3.取完后程序不报错
5.10生成器(函数的变异)
-
判断:内部是否包含yield
-
总结:函数中如果存在yield,那么该函数就是一个生成器函数,调用生成器函数会返回一个生成器,生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值。
def func():
print('F1')
yield 1
print('F2')
yield 2
print('F3')
yield 3
v1 = func() #函数内部代码不会执行,返还一个生成器对象
for item in v1:
print(item) -
读取大文件
def func():
# 分批去读取文件中的内容,将文件的内容返回给调用者。
cursor = 0
while True:
f = open('db', 'r', encoding='utf-8') # 通过网络连接上redis
# 代指 redis[0:10]
f.seek(cursor)
data_list =[]
for i in range(10):
line = f.readline()
if not line:
return
data_list.append(line)
cursor = f.tell()
f.close() # 关闭与redis的连接
for row in data_list:
yield row
for item in func:
print(item)
5.11推导式
5.11.1 列表推导式
目的:方便生成列表
#基本格式:
v1 = [i for i in 可迭代对象 ]
v2 = [i for i in 可迭代对象 if 条件 ] #条件为true才进行添加
# 示例:
v1 = [ i for i in 'alex' ]
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]()
v6 = [lambda :i for i in range(10)]
result = v6[5]()
# 新浪微博面试题
v7 = [lambda x:x*i for i in range(10)]
# 1.请问 v7 是什么?
# 2.请问 v7[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]
5.11.2 集合推导式
# 目的:方便的生成一个集合
# 格式:
v1 = { i for i in 'alex' }
5.11.3 字典推导式
# 目的:方便的生成一个字典
# 格式:
v1 = { 'k'+str(i):i for i in range(10)}