目录
- 模块(Module)
- 定义
- 作用
- 导入
- 模块变量
- 加载过程
- 分类
- 搜索顺序
- 包(package)
- 定义
- 作用
- 导入
- 异常处理(Error)
- 异常
- 处理
- raise语句
- 自定义异常
- 迭代(了解)
- 可迭代对象(iterable)
- 迭代器对象(iterator)
- 生成器(generator)
- 生成器函数
- 内置生成器
- 枚举函数enumerate
- zip
- 生成器表达式
- 函数式编程
- 函数作为参数
- lambda表达式
- 内置高阶函数
- 作用域LEGB
- 变量名查找规则
- 函数作为返回值
- 闭包
- 函数装饰器decorators
模块(Module)
定义
包含一系列数据、函数、类的文件,通常以.py结尾
作用
让一些相关的代码,有逻辑的组织在一起,使结构更加清晰。
导入
【1】import
- 语法:import 模块名 [as 别名]
- 作用:将某个模块整体导入到当前模块
- 本质:使用变量名(模块名)关联指定模块代码。
- 使用:模块名.成员
- 导入方式:
导入模块名称
本质:将该模块作用域赋值给变量module01
import module01
module01.fun01()#调用module01中的函数
c01 = module01.MyClass01()#调用module01中的类
c01.fun02()#调用类中的方法
【2】from import
- 语法:from 模块名 import 成员 [as 别名]
- 作用:将模块内的一个或多个成员导入到当前模块的作用域中。
- 使用:成员
- 导入方式:
本质:将该模块指定成员赋值给变量fun01,MyClass01
from module01 import fun01,MyClass01
fun01()
c01 = MyClass01()
c01.fun02()
【3】from import *
- 语法:from 模块名 import *
- 作用:将某模块的所有成员导入到当前模块
- 模块中以单下划线(_)开头的属性,不会被导入,通常称这些成员为隐藏成员
- 导入方式:
from module01 import *
fun01()
c01 = MyClass01()
c01.fun02()
模块变量
__all__变量:定义可导出成员,仅对from xx import * 语句有效
# 只能导出该模块中的fun01()和class MyClass01
__all__ = ["fun01", "MyClass01"]
__doc__变量:文档字符串。(获取模块文档注释 “”" 注释 “”")
import module01
print(module01.__doc__)
__file__变量:模块对应的文件路径名
print(module01.__doc__)
__name__变量:模块自身名字,可以判断是否为主模块。当此模块作为主模块(第一个运行的模块)运行时,__name__绑定’__main__’,不是主模块,而是被其他模块导入时,存储模块名。
# 获取模块名称
print(module01.__name__) # module01 & __main__
if __name__ == "__main__": # 如果程序从当前模块运行,则执行下列的测试代码;如果当前模块被主模块导入,则下列测试代码不再执行
加载过程
在模块导入时,模块的所有语句都会执行。
如果一个模块已经导入,则再次导入时不再重复执行语句。
分类
- 内置模块(builtins):在解释器的内部可以直接使用。
- 标准库模块:安装python时自带的,经过导入后可直接使用。
e.g. 标准库模块——时间(time)
import time
# 返回时间戳(1970年后经过的浮点秒数)
print(time.time())
# 时间戳-->时间元祖(年 月 日 时 分 秒 星期 一年的第几天 夏令时)
print(time.localtime(1586232291.0553486)) #time.struct_time(tm_year=2020, tm_mon=4, tm_mday=7, tm_hour=12, tm_min=4, tm_sec=51, tm_wday=1, tm_yday=98, tm_isdst=0)
# 时间元祖-->时间戳
print(time.mktime(time.localtime()))
# 时间元祖-->字符串(时间的格式化)
print(time.strftime("%Y %m %d %H:%M:%S",time.localtime()))
# 字符串-->时间元祖
print(time.strptime("2019 04 18","%Y %m %d"))
- 第三方模块(通常开源):需要自行下载安装,再导入使用。
- 自定义模块:用户自己编写的模块,经过导入后可直接使用。
搜索顺序
搜索内建模块(builtins)
sys.path提供的路径,通常第一个是程序运行时的路径
# 列表,存储的是解释器导入模块时搜索的路径,可以通过append手动添加路径
print(sys.path)
包(package)
定义
将模块以文件夹的形式进行分组管理。
作用
让一些相关的模块组织在一起,使逻辑结构更加清晰。
导入
对应项目文件夹(比如:day14)–Mark Directory as–Sourcces Root
- 方式1:import 包.模块
import package01.module01
# 使用包.模块.成员
package01.module01.fun01()
- 方式2:from 包 import 模块
from package01 import module01
# 使用:模块.成员
module01.fun01()
- 方式3:from 包 import *
from package01 import *
# 在包的__init__.py文件中,定义__all__属性(__all__=["module01"])
module01.fun01()
- 方式4【推荐】:from 包.模块 import 成员
from package01.module01 import *
fun01()
注意:无论哪个文件都从根目录开始写起(导入)
异常处理(Error)
异常
- 定义:运行时检测到的错误。
- 现象:当异常发生时,程序不再向下继续执行,而转到函数的调用语句。
- 常见异常类型:
- 名称异常(NameError):变量未定义
- 数值异常(ValueError):值错误
- 类型异常(TypeError):不同类型数据进行运算
- 索引异常(IndexError):超出索引范围
- 属性异常(AttributeError):对象没有对应名称的属性
- 键异常(KeyError):没有对应名称的键
- 未实现异常(NotImplementedError):尚未实现的方法
- 异常基类Exception
处理
- 语法:
try:
可能触发异常的语句
except 错误类型1 [as 变量1]:
处理语句1
except 错误类型2 [as 变量2]:
处理语句2
except Exception [as 变量3]:
不是以上错误类型的处理语句
else:
未发生异常的语句
finally:
无论是否异常,一定执行的代码
- 作用:将程序由异常状态转换为正常流程
- 说明:
- as子句是用于绑定错误对象的变量,可以省略
- except子句可以有一个或者多个,用来捕获某种类型的错误
- else子句最多只能有一个
- finally子句最多只能有一个,如果没有except子句,必须存在。
- 如果异常没有被捕获到,会向上层(调用处)继续传递,直到程序终止运行。
raise语句
- 作用:抛出一个错误,让程序进入异常状态。
- 目的:在程序调用层数较深时,向主程序传递错误信息要层层return比较麻烦,所以建议人为抛出异常,可以直接传递错误信息。
自定义异常
- 定义
class 类名Error(Exception):
def __init__(self, 参数):
super().__init__(参数)
self.数据 = 参数
e.g. 自定义异常
class AgeError(Exception):
"""
封装错误信息
"""
def __init__(self,msg,code,age_value):
super().__init__(msg)
self.msg = msg
self.code = code
self.age_value = age_value
- 调用
try:
...
raise 自定义异常类名(参数)
...
except 定义异常类 as 变量名:
变量名.数据
e.g.
# raise AgeError("我不要",27,value)
try:
w01 = Wife(80)
print(w01.age)
except AgeError as e:
print("错误信息:", e.msg)
print("错误代码行号:", e.code)
print("输入的年龄是", e.age_value)
- 作用:封装错误信息
迭代(了解)
每一次对过程的重复称之为一次”迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。
可迭代对象(iterable)
for循环原理:
【1】获取迭代器对象
【2】循环迭代(调用迭代器的__next__方法)
【3】捕获StopIteration异常
list01=[1,2,3,4,5] # 可迭代对象:具有__iter__()方法,可以返回迭代器的对象
# for item in list01:
# print(item)
#1.获取迭代器对象
iterator = list01.__iter__()
while True:
try:#如果获取了全部元素,则执行except
# 2. 获取下一个元素(迭代过程)
item = iterator.__next__()
print(item)
# 3. 停止迭代(异常StopIteration)
except StopIteration:
break # 跳出循环体
e.g. 不使用for循环,获取字典所有元素
d01={"a":1,"b":2,"c":3}
iterator = d01.__iter__()
while True:
try:
key = iterator.__next__()
print(key,d01[key])
except:
break
- 定义:具有__iter__函数的对象,可以返回迭代器对象。
- 语法
- 创建:
class 可迭代对象类名:
def __iter__(self):
return 迭代器
- 使用:
for 变量名 in 可迭代对象:
语句
- 原理
迭代器 = 可迭代对象.__iter__()
while True:
try:
print(迭代器.__next__())
except StopIteration:
break
e.g.
class Skill:
pass
class SkillIterator:
"""
迭代器
"""
def __init__(self,target):
self.target = target
self.index = 0
def __next__(self):
# 返回下一个元素
# 如果索引越界,则抛出异常
if self.index > len(self.target)-1:
raise StopIteration()
# 返回下一个元素
item = self.target[self.index]
self.index += 1
return item
class SkillManager:
"""
可迭代对象
"""
def __init__(self,skills):
self.skills = skills
def __iter__(self):
# 创建迭代器对象 传递 需要迭代的数据
return SkillIterator(self.skills)
# 以下是客户端代码
manager = SkillManager([Skill(),Skill(),Skill()])
# 方式一
for item in manager:
print(item)
# 方式二
iterator = manager.__iter__()
while True:
try:
item = iterator.__next__()
print(item)
except:
break
迭代器对象(iterator)
- 定义:可以被next()函数调用并返回下一个值的对象。
- 语法:
class 迭代器类名:
def __init__(self, 聚合对象):
self.聚合对象 = 聚合对象
def __next__(self):
if 没有元素:
raise StopIteration
return 聚合对象元素
- 说明:聚合对象通常是容器对象
- 作用:使用者只需要通过一种方式(next),便可简单明了的获取聚合对象中的各个元素,无需了解其内部结构。
生成器(generator)
- 定义:能够动态(循环一次计算一次返回一次)提供数据的可迭代对象。
- 作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。
- 惰性(延迟)操作:通俗的讲在需要的时候(for)才计算结果,而不是一次构建出所有结果。即循环(next)一次,计算一次,返回一次。(惰性查找:节省内存;立即查找:灵活获取结果)
- 使用过的生成器对象,不会再被调用
生成器函数
- 定义:含有yield语句的函数,返回值为生成器对象。
- 语法:
- 创建:
def 函数名():
…
yield 数据
…
- 调用:
for 变量名 in 函数名():
语句
e.g.生成器函数示例
def my_range(stop):
start = 0
while start < stop:
yield start
start += 1
for item in my_range(5):
print(item)
e.g. 在list01中,挑出所有的偶数
list01=[23,3,4,556,677,68,8,98,98]
def get_even01(target):
for item in target:
if item % 2 == 0:
yield item
def get_even02(target):
result=[]
for item in target:
if item % 2 == 0:
result.append(item)
return result
# 两种方式结果一样,大数据下推荐第一种方法(yield生成器)
iter01 = get_even01(list01)
for item in iter01:
print(item)
iter02 = get_even02(list01)
for item in iter02:
print(item)
- 说明:
- 调用生成器函数将返回一个生成器对象,不执行函数体。
- yield翻译成“产生”或“生成”
- 执行过程
(1) 调用生成器函数,自动创建迭代器对象。
(2) 调用迭代器对象的__next__()方法才执行生成器函数体。
(3) 每次执行到yield关键字时返回数据,暂时离开。
(4) 待下次调用__next__()方法继续执行。
内置生成器
枚举函数enumerate
- 语法:
for 变量 in enumerate(可迭代对象):
语句
for 索引, 元素 in enumerate(可迭代对象):
语句
- 作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。
list01=["a","b","c"]
for item in enumerate(list01):
# (索引,元素)
print(item) # (0,"a") (1,"b") (2,"c")
for index,element in enumerate(list01):
print(index,element) # 0 a 1 b 2 c
zip
- 语法:
for item in zip(可迭代对象1,可迭代对象2...):
语句
- 作用:将多个可迭代对象中对应的元素组合成一个元组,生成的元组个数由最小的可迭代对象决定。
list01 = [101,102,103]
list02 = ["A","B","C"]
for item in zip(list01,list02):
print(item) # (101,'A')
生成器表达式
- 定义:用推导式形式创建生成器对象
- 语法:变量 = ( 表达式 for 变量 in 可迭代对象 [if 真值表达式] )
list01 = [2,3,4,6]
# 列表推导式[]
result = [item**2 for item in list01]
print(result)
# 生成表达式
result = (item**2 for item in list01)
for item in result:
print(item)
e.g. 练习:使用列表推导式与生成器表达式,获取list02中大于3的数据
list02 = [2,3,4,5]
res01 = [item for item in list02 if item>3] # 列表推导式:执行所有操作,保存所有结果
res02 = (item for item in list02 if item>3) # 生成器表达式:返回生成器对象
for item in res01: # 从结果中获取数据
print(item)
for item in res02: # 循环一次,计算一次,返回一次
print(item)
函数式编程
- 定义:用一系列函数解决问题。
- 函数可以赋值给变量,赋值后变量绑定函数。
- 允许将函数作为参数传入另一个函数。
- 允许函数返回一个函数。
- 高阶函数:将函数作为参数或返回值的函数。
def fun01():
print("fun01执行")
# 将函数值赋值给变量a(没有执行fun01)
a = fun01
# 调用变量a,间接执行函数fun01
a()
# --------------------------------
# 将方法fun01作为方法的参数func进行传递
def fun02(func):
print("fun02执行")
# 对于fun02的定义者而言,不知道也不需要知道func的具体逻辑
func()
fun02(fun01)
函数作为参数
将核心逻辑传入方法体,使该方法的适用性更广,体现了面向对象的开闭原则。
e.g.三个函数只有if条件不同的封装方法
# 相同点
def find_demo(target,func):
for item in target:
# 本行代码,使用 形参func将不变的与变化的隔离开
if func(item):
yield item
# 提取不同点
def condition01(item):
return item>5
def condition02(item):
return item % 2 != 0
def condition03(item):
return item<3
lambda表达式
- 定义:是一种匿名方法。
- 作用:作为参数传递时语法简洁,优雅,代码可读性强。随时创建和销毁,减少程序耦合度。
- 语法
- 定义:变量 = lambda 形参: 方法体
- 调用:变量(实参)
- 说明:
- 形参没有可以不填
- 方法体只能有一条语句,且不支持赋值语句。
e.g. lambda表达式(匿名方法) 【语法:lambda 参数:方法体】
# 无参
a01 = lambda : print("我是lambda方法")
a01()
# 含参
a02 = lambda a: print("我是lambda方法,参数是",a)
a02(400)
# return 带返回值
a03 = lambda : True # return True
a03()
e.g. lambda表达式的应用
解决步骤:
- 逐个解决问题
- 将共性提取到ListHelper中
- 将变化用lambda表示
class ListHelper:
@staticmethod
def find_all(target,func_condition):
for item in target:
if func_condition(item):
yield item
list01 = [1,2,33,4,45,6]
for item in ListHelper.find_all(list01,lambda item:item>5):
print(item)
内置高阶函数
- map(函数,可迭代对象):使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
list01=[
Enemy(101,"玄冥大佬",200,800,5),
Enemy(102,"玄冥小佬",150,700,3),
Enemy(103,"qtx",800,1000,50),
Enemy(104,"吕泽玛利亚",0,300,2),
Enemy(105,"赵金多",500,900,10)
]
# 映射出所有敌人的名字
# e为list01中的对象
for item in map(lambda e:,list01):
print(item)
- filter(函数,可迭代对象):根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
# 过滤出编号大于102的敌人
# e为list01中的对象
for item in filter(lambda e:e.id>102,list01):
print(item.id)
- sorted(可迭代对象,key = 函数,reverse = bool值):排序,返回值为排序结果。
# 按照血量升序排列
# e为list01中的对象
# 不对list01产生任何变化,而是产生新的列表
for item in sorted(list01,key = lambda e:e.hp):
print(item.hp)
# 按照血量降序排列
for item in sorted(list01,key = lambda e:e.hp,reverse=True):
print(item.hp)
- max(可迭代对象,key = 函数):根据函数获取可迭代对象的最大值。
# 获取攻击力最大的敌人
result = max(list01,key = lambda e:e.atk)
print(result.name)
- min(可迭代对象,key = 函数):根据函数获取可迭代对象的最小值。
作用域LEGB
- 作用域:变量起作用的范围。
- Local 局部作用域:函数内部。
- Encolsing 外部嵌套作用域:函数嵌套。
def fun01():
# fun01局部变量L
# E外部嵌套作用域
a = 1
def fun02():
b = 2 # fun02局部变量L
# print("fun02:",a) # 可以访问外部嵌套变量a==1
# a = 2222222 # 没有修改外部变量a,而是创建了新的局部变量a
# print("fun02:",a) # a==2222222
nonlocal a # 声明外部嵌套变量a(内部改外面)
a = 2222
print("fun02:",a) # a == 2222
fun02()
print("fun01:",a) # a == 2222
fun01()
- Global 全局作用域:py文件内部
- Builtins内建模块作用域:builtins.py
变量名查找规则
由内到外:L —> E —> G —> B
局部变量:
- 在方法体内部定义的变量
- 调用函数时才被创建,函数结束后自动销毁。
全局变量:
- 定义在.py文件中的变量
- 函数体内部可以访问,但是不能直接修改(先使用global语句声明才能修改)。
函数作为返回值
逻辑连续,当内部函数被调用时,不脱离当前的逻辑。
闭包
- 三要素:
- 必须有一个内嵌函数。
- 内嵌函数必须引用外部函数中变量。
- 外部函数返回值必须是内嵌函数。
- 语法
- 定义:
def 外部函数名(参数):
外部变量
def 内部函数名(参数):
使用外部变量
return 内部函数名
- 调用:
变量 = 外部函数名(参数)
变量(参数)
e.g. 闭包示例
def fun01():
print("fun01执行喽")
a = 1
def fun02():
print("fun02执行喽")
print("外部变量是:",a)
return fun02
# 得到的是内部函数
result = fun01()
# 调用内部函数,因为内部函数使用了外部变量,所以称之为闭包
result() # 可以使用外部变量,说明外部函数在调用后没有释放
# 执行结果:
# fun01执行喽
# fun02执行喽
# 外部变量是:1
e.g. 压岁钱案例
def give_gift_money(money):
"""
获取压岁钱
"""
print("得到了%d压岁钱" %money)
def child_buy(target, price):
"""
孩子需要买的东西
"""
nonlocal money
if money > price:
money -= price
print("孩子花了%d钱,买了%s,剩下%s钱。" %(price,target,money))
else:
print("压岁钱不够了")
return child_buy
action = give_gift_money(10000)
action("98K",3500)
- 定义:在一个函数内部的函数,同时内部函数又引用了外部函数的变量。
- 本质:闭包是将内部函数和外部函数的执行环境绑定在一起的对象。
- 优点:内部函数可以使用外部变量。
- 缺点:外部变量一直存在于内存中,不会在调用结束后释放,占用内存。
- 作用:实现python装饰器。
函数装饰器decorators
- 定义:在不改变原函数的调用以及内部代码情况下,为其添加新功能的函数。
- 语法
def 函数装饰器名称(func):
def 内嵌函数(*args, **kwargs):
需要添加的新功能
return func(*args, **kwargs)
return 内嵌函数
@ 函数装饰器名称
def 原函数名称(参数):
函数体
原函数(参数)
e.g. 装饰器的使用
def print_func_name(func):
# 包装新旧功能
def wrapper(*args, **kwargs): # 函数包装后实际上执行的是wrapper函数
# 增加新功能
print(func.__name__)
# 旧功能
return func(*args, **kwargs)
return wrapper # 返回包装器
@print_func_name # say_hello = print_func_name(say_hello)
def say_hello(name):
print(name,"hello")
return "haha"
@print_func_name
def say_goodbye(name,age):
print(name,age,"goodbye")
return "hehe"
print(say_hello("张无忌"))
print(say_goodbye("赵敏", 25))
e.g.打印执行时间
import time
def print_execute_time(func):
# 包装新旧功能
def wrapper(*args, **kwargs):
# 记录执行前的时间
start_time = time.time()
result = func(*args, **kwargs)
# 统计执行时间
execute_time = time.time() - start_time
print("执行时间是:",execute_time)
return result
return wrapper # 返回包装器
- 本质:
使用 @ 函数装饰器名称 修饰原函数,等同于:
原函数名称 = 函数装饰器名称(原函数名称)
创建与原函数名称相同的变量,关联内嵌函数;故调用原函数时执行内嵌函数。 - 装饰器链:一个函数可以被多个装饰器修饰,执行顺序为从近到远。