函数
一. global与nonlocal关键字
1.1 global
"""
如果想要在局部修改全局的不可变类型, 需要提前加关键字global申明
如果想要在局部修改全局的可变类型, 不需要加关键字global申明
"""
# 不可变数据类型
x = 111
def index():
x = 222 # 并不是在修改全局的x 而是在局部名称空间中创建了一个新的x
# 如果想要在局部名称空间中修改全局名称空间中的名字 那么需要使用关键字申明
global x # 申明 修改的是全局x而不是产生新的x
x = 666
index()
print(x) # 不使用 global 则是 111, 否则是 666
# 可变数据类型
l1 = [111, 222, 333]
def index():
l1.append(444)
index()
print(l1)
1.2 nonlocal
"""
局部名称空间嵌套的情况下 内层如果想要修改外层
情况1数据是不可变类型
需要使用关键字nonlocal
情况2数据是可变类型
不需要使用关键字nonlocal
"""
# 不可变数据类型
def index():
x = 111 # 在index的局部产生一个x=111
def f1():
x = 222 # 在f1的局部产生一个x=222
print(x)
nonlocal x
x = 333
f1()
print(x)
print(l1)
index()
# 可变数据类型
def index():
l1 = [11, 22, 33]
def f1():
l1.append(44)
f1()
print(x)
print(l1)
index()
二. 闭包函数
2.1 特性
1. 函数嵌套函数;
2. 函数内部可以引用函数外部的参数和变量;
3. 参数和变量不会被垃圾回收机制回收.
2.2 优缺点
优点是:
1. 变量被保存起来没有被销毁,随时可以被调用
2. 只有函数内部的子函数才能读取局部变量,可以避免全局污染
缺点是:
1. 如果闭包使用不当,就会导致变量不会被垃圾回收机制回收,造成内存泄露
三. 装饰器
3.1 简易版装饰器
def get_time(func):
start_time = time.time() # 函数执行之前获取一个时间戳
func()
end_time = time.time() # 函数执行之后获取一个时间戳
print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
def home():
time.sleep(3)
print('from home')
get_time(home)
3.2 进阶版本装饰器
# 解决参数问题
def outer(func_name):
def get_time(*args, **kwargs):
start_time = time.time()
func_name(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return get_time
3.3 完整版本装饰器
# 解决返回值问题
def outer(func_name):
def get_time(*args, **kwargs):
start_time = time.time()
res = func_name(*args, **kwargs) # 执行真正的index函数
end_time = time.time()
print(end_time - start_time)
return res # return '不要急躁' # 如何在此处返回真正index函数的返回值
return get_time
3.4 装饰器模板(重要)
'''编写装饰器其实有一套固定的代码 不需要做任何理解'''
def outer(func_name): # func_name用于接收被装饰的对象(函数)
def inner(*args, **kwargs):
print('执行被装饰函数之前 可以做的额外操作')
res = func_name(*args, **kwargs) # 执行真正的被装饰函数
print('执行被装饰函数之后 可以做的额外操作')
return res # 返回真正函数的返回值
return inner
3.5 装饰器修复技术
# 做到比真的还要真 但是本质其实没有变
from functools import wraps # 导入模块
def outer(func_name):
@wraps(func_name)
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的操作')
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
print('from index')
@outer
def home():
'''这是home函数的注释'''
print('from home')
# help(home) # help可以查看指定函数的注释信息
# help(len)
# index() # 目前的以假乱真 有瑕疵
# print(index)
# help(home)
# help(index)
# print(home)
# print(index)
home()
index()
3.6 多层装饰器
# 判断七句print执行顺序
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')
index()
# 结果:
"""
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
"""
3.7 有参装饰器
def outer(source_data):
def login_auth(func_name): # 不能修改 只能接收一个被装饰对象名字
def inner(*args, **kwargs): # 不能修改 是专门用来给被装饰的对象传参的
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 校验用户数据 数据的来源可以有很多 比如全局字典 全局列表 文本文件 数据库
# 数据的来源不同 处理方式就不同 对应的代码编写就不一样
# 分支结构处理 然后根据不同的参数提示 匹配不同的流程
if source_data == '1':
print('使用字典的方式处理数据')
elif source_data == '2':
print('使用列表的方式处理数据')
elif source_data == '3':
print('使用文件操作处理数据')
else:
print('其他操作情况')
res = func_name(*args, **kwargs)
return res
return inner
return login_auth
@outer('3')
def index():
print('from index')
3.8 装饰器语法糖
def outer(func_name): # func_name用于接收被装饰的对象(函数)
def inner(*args, **kwargs):
a = 1
if a > 2:
res = func_name(*args, **kwargs) # 执行真正的被装饰函数
return res # 返回真正函数的返回值
return inner
方式一:
@outer
def index():
print('index')
方式二:
def index():
print('index')
index = outer(index)
四. 三元表达式
值1 if 条件 else 值2
条件如果成立则使用值1 (if前面的数据)
条件如果不成立则使用值2 (else后面的数据)
username = input('username>>>:').strip()
res = '管理员' if username == 'kiven' else 'DSB'
五. 各种生成式
>>>没有元组生成式<<<
5.1 列表生成式
"""列表生成式中值允许出现for和if 不能出现else 因为会产生歧义(for和if都能结合else)"""
# 需求:将列表中所有的人名后面加上_DSB
name_list = ['kunkun', 'kevin', 'tony', 'oscar', 'jerry']
# 列表生成式完成需求
res = [name+'_SB' for name in name_list]
print(res) # ['kunkun_SB', 'kevin_SB', 'tony_SB', 'oscar_SB', 'jerry_SB']
# 列表生成式复杂用法:具备筛选能力
res = [name+'_SB' for name in name_list if name == 'kunkun']
print(res)
res = [name+'_SB' for name in name_list if name != 'kunkun']
print(res)
5.2 字典生成式
# 需求:将下面两个列表分别制作成字典的键值
l1 = ['name', 'age', 'pwd']
l2 = ['jason', 18, 123]
res = {l1[i]: l2[i] for i in range(len(l1))}
print(res) # {'name': 'jason', 'age': 18, 'pwd': 123}
res = {l1[i]: l2[i] for i in range(len(l1)) if i == 1}
print(res) # {'age': 18}
5.3 集合生成式
res = {i for i in range(10)}
print(res, type(res))
res = {i for i in range(10) if i != 2}
print(res, type(res))
六. 常见内置函数(重要)
6.1 map映射
# 需求:元素全部自增10
l1 = [11, 22, 33, 44, 55]
1. 方式一:(列表生成式)
res = [item + 10 for item in l1]
print(res)
2. 方式二:(内置函数)
def index(n):
return n + 10
res = map(index, l1)
print(res) # <map object at 0x000001F3064EEE80>
print(list(res)) # [21, 32, 43, 54, 65]
||
||
相当于
||
\/
res = map(lambda x: x + 10, l1) # lambda 自带的内置函数
print(res) # <map object at 0x000001F3064EEE80>
print(list(res)) # [21, 32, 43, 54, 65]
6.2 zip拉链
# 需求:将两个列表中的元素一一对应成对即可----------------> 生成器也可以
l1 = [11, 22, 33, 44]
l2 = ['jason','kevin','tony','oscar']
res = zip(l1,l2) # 结果是一个迭代器
print(res) # 目前想看里面的数据 用list转换一下即可
print(list(res)) # [(11, 'jason'), (22, 'kevin'), (33, 'tony'), (44, 'oscar')]
'''zip可以整合多个数据集, 如果数据集之间个数不一致 那么依据短的'''
l1 = [11, 22, 33, 44]
l2 = ['jason','kevin','tony','oscar']
l3 = [1,2,3,4]
l4 = [55,66,77,88]
res = zip(l1,l2,l3,l4)
print(list(res)) # [(11, 'jason', 1, 55), (22, 'kevin', 2, 66), (33, 'tony', 3, 77), (44, 'oscar', 4, 88)]
6.3 filter过滤
# 需求:筛选出大于30的元素
l1 = [11, 22, 33, 44, 55, 66]
def index(x):
return x > 30
res = filter(index,l1)
print(list(res)) # [33, 44, 55, 66]
||
||
相当于
||
\/
res = filter(lambda x:x>30, l1)
print(list(res)) # [33, 44, 55, 66]
6.4 reduce归总
以前是内置函数 现在是某个模块下面的子函数
from functools import reduce # 导入
# 需求:讲列表中所有的元素相加
l1 = [11, 22, 33]
def index(x,y):
return x + y
res = reduce(index,l1)
print(res) # 66
||
||
相当于
||
\/
res = reduce(lambda x, y: x + y, l1)
print(res) # 66
res = reduce(lambda x, y: x + y, l1, 100)
print(res) # 166
6.5 常见内置函数 1
# 1.abs() 获取绝对值(不考虑正负号)
# print(abs(-123))
# print(abs(123))
# 2.all()与any()
# l1 = [0, 0, 1, 0, True]
# print(all(l1)) # False 数据集中必须所有的元素对应的布尔值为True返回的结果才是True
# print(any(l1)) # True 数据集中只要所有的元素对应的布尔值有一个为True 返回的结果就是True
# 3.bin() oct() hex() 产生对应的进制数
# print(bin(100))
# print(oct(100))
# print(hex(100))
# 4.bytes() 类型转换
# s = '你好啊 hello world!'
# print(s.encode('utf8')) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a hello world!'
# print(bytes(s, 'utf8')) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a hello world!'
'''针对编码解码 可以使用关键字encode与decode 也可以使用bytes和str'''
# s1 = '天黑了 抓紧进屋吧!!!'
# 编码
# res = bytes(s1, 'utf8')
# print(res)
# 解码
# res1 = str(res, 'utf8')
# print(res1)
# 5.callable() 判断当前对象是否可以加括号调用
# name = 'jason'
# def index():pass
# print(callable(name)) # False 变量名不能加括号调用
# print(callable(index)) # True 函数名可以加括号调用
# 6.chr()、ord() 字符与数字的对应转换
# print(chr(65)) # A 根据数字转字符 依据ASCII码
# print(ord('A')) # 65 根据字符转数字 依据ASCII码
# 7.dir() 返回数据类型可以调用的内置方法(查看对象内部可调用的属性)
# print(dir(123))
# print(dir('jason'))
# 8.divmod()
"""
可以使用在网站的分页制作上
问
总共250条数据 每页展示25条 需要多少页 10页
总共251条数据 每页展示25条 需要多少页 11页
总共249条数据 每页展示25条 需要多少页 10页
"""
# print(divmod(250,25)) # (10, 0) 第一个参数是整数部分 第二个是余数部分
# print(divmod(251,25)) # (10, 1)
# print(divmod(249,25)) # (9, 24)
# def get_page_num(total_num,page_num): # 后面django分页器使用
# more,others = divmod(total_num, page_num)
# if others:
# more += 1
# print('需要%s页'%more)
# get_page_num(1000,30)
# 9.enumerate() 枚举
# name_list = ['jason', 'kevin', 'oscar', 'tony']
# for name in name_list:
# print(name)
# for i,j in enumerate(name_list):
# print(i,j) # i类似于是计数 默认从0开始
# for i,j in enumerate(name_list,start=1):
# print(i,j) # 还可以控制起始位置
# 10.eval() exec() 识别字符串中的python代码 使用频率很低
# print('print("有点饿了")')
# eval('print("有点饿了111")')
# exec('print("有点饿了222")')
res = """
for i in range(10):
print(i)
"""
# eval(res) 只能识别简单逻辑的python代码
# exec(res) 能够识别具有与一定逻辑的python代码
6.6 常见内置函数 2
# 1.help() 查看注释信息
# help(len)
# 2.id() 返回一串相当于内存地址的数字
# print(id('jason'))
# 3.int() 类型转换、机制转换
# 4.isinstance() 判断数据类型
# print(type('jason') is str) # 类型判断 别扭的很 不推荐
# print(isinstance('jason', str)) # True
# print(isinstance('jason', int)) # False
# 5.pow() 幂指数
# print(pow(10,2))
# 6.round() 四舍五入
# print(round(11, 1)) # 第二个参数控制需要保留几位小数部分
# print(round(11.29, 1))
# print(round(11.59, 1))
# 7.sum()求和
# print(sum([11,2,2,3,4,3,2]))
七. 函数与方法
1. 函数:就是普通函数,有几个值就要传几个值
2. 方法[面向对象]:是绑定给对象,类,绑定给谁谁来调用,会自动传值,谁来调用就会把谁传入
3. 总结:只要能自动传值,就是方法,有几个值传几个值就是函数
区分方法和函数
# 导入
from types import MethodType, FunctionType
def add(a, b):
return a + b
class Person:
# 方法:绑定给对象的【不一定是方法】
def speak(self):
print('人说话')
@classmethod
def test(cls):
print('类的绑定方法')
@staticmethod
def ttt():
print('static')
p = Person()
print(isinstance(add, MethodType)) # False
print(isinstance(add, FunctionType)) # True
print(isinstance(p.speak, MethodType)) # True
print(isinstance(p.speak, FunctionType)) # False
print(isinstance(Person.speak, FunctionType)) # True
print(isinstance(Person.speak, MethodType)) # False
print(isinstance(Person.test, FunctionType)) # False
print(isinstance(Person.test, MethodType)) # True
print(isinstance(p.test, FunctionType)) # False
print(isinstance(p.test, MethodType)) # True
# 静态方法,本质就是个函数,有几个值就要传几个值
print(isinstance(p.ttt, FunctionType))
print(isinstance(p.ttt, MethodType))
八. 偏函数
1. python内置给咱们一个偏函数,可以把函数包裹一下,提前传参
from functools import partial
def add(a, b, c):
return a / b + c
# 正常使用
res=add(4,5,6)
print(res)
# 使用偏函数,提前传值
res = partial(add, 4, 5)
print(res) # functools.partial(<function add at 0x000002C4025C71F0>, 4)
print(res(6))