使用pycharm和jupter notebook。
一个模块就是一个包含python代码的文件,后缀名为.py即可,模块就是个python文件。
模块直接引入(加入模块命名以数字开头,需要借助importlib),语法如下
#1.将一整个模块导入
import module_name
module_name.function_name
module_name.class_name
#2.有选择性的导入
from module_name import function_name, class_name
function_name #不需要前缀,直接使用
class_name
#3.导入所有,正常使用也不需要前缀
from module_name import *
例如:新建模块test,新建.py文件p02,在p02中引入test模块:
运行(Ctrl+Shift+F10)结果如下:
python语法中不允许以数字开头的命名方式,但是借助importlib包可以实现导入以数字开头的模块名称。如下:
例如:
结果如下:
模块的搜索路径:加载模块的时候,系统会在哪些地方寻找此模块
import sys
sys.path 属性可以获取路径列表
sys.path.append(dir)
包是一种组织管理代码的方式,包里面存放的是模块。
用于将模块包含在一起的文件夹就是包。
/---包
/---/--- __init__.py 包的标志文件
/---/--- 模块1
/---/--- 模块2
/---/--- 子包(子文件夹)
/---/---/--- __init__.py 包的标志文件
/---/---/--- 子包模块1
/---/---/--- 子包模块2
import package_name
可以使用__init__.py中的内容,使用方式是:
package_name.func_name
package_name.class_name.func_name()
案例
新建一个包pkg01,在项目根目录下新建一个p04.py。
__init__.py:
def inInit():
print("I am in init of package")
p04.py:
import pkg01
pkg01.inInit()
运行结果:
import package.module
#使用方法
package.module.func_name
package.module.class.func()
package.module.class.var
from package_name import module1, module2, module3, ... #这种导入方法不执行__init__中的内容
#使用方法
module.func_name
from package_name import *
#使用方法
func_name()
class_name.func_name()
class_name.var
from package_name.module import *
#使用方法
func_name()
class_name.func_name()
import 完整的包或者模块的路径
__init__.py中如果为空,或者没有__all__,那么只可以把__init__中的内容导入;__init__如果设置了__all__的值,那么则按照__all__指定的子包或者模块进行导入,不会载入__init__中的内容。
'__all__' = ['module1', 'module2', 'package1' ......]
案例
新建包pkg02,在其下新建文件p01.py,在根目录下新建p07.py。
p01.py:
class Student():
def __init__(self, name="NoName", age=18):
self.name = name
self.age = age
def say(self):
print("My name is {0}".format(self.name))
def sayHello():
print("Hi,欢迎来到学院")
#此判断语句建议一直作为程序的入口
if __name__ == '__main__':
print("我是模块呀,叫我干啥?")
p07.py:
from pkg02 import *
stu = p01.Student()
stu.say()
运行结果:
用于区分不同位置不同功能但相同名称的函数或者变量的一个特定前缀。
作用是防止命名冲突。
广义上的错误分为错误和异常。
BaseException 是所有异常的基类
AssertError 断言语句(assert)失败
AttributeError 尝试访问未知的对象属性
EOFError 用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError 浮点计算错误
GeneratorExit generator.close()方法被调用的时候
ImportError 导入模块失败的时候
IndexError 索引超出序列的范围
KeyError 字典中查找一个不存在的关键字
KeyboardInterrupt 用户输入中断键(Ctrl+c)
MemoryError 内存溢出(可通过删除对象释放内存)
NameError 尝试访问一个不存在的变量
NotImplementedError 尚未实现的方法
OSError 操作系统产生的异常(例如打开一个不存在的文件)
OverflowError 数值运算超出最大限制
ReferenceError 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError 一般的运行时错误
StopIteration 迭代器没有更多的值
SyntaxError Python的语法错误
IndentationError 缩进错误
TabError Tab和空格混合使用
SystemError Python编译器系统错误
SystemExit Python编译器进程被关闭
TypeError 不同类型间的无效操作
UnboundLocalError 访问一个未初始化的本地变量(NameError的子类)
UnicodeError Unicode相关的错误(ValueError的子类)
UnicodeEncodeError Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError Unicode转换时的错误(UnicodeError的子类)
ValueError 传入无效的参数
ZeroDivisionError 除数为零
不能保证程序永远正常运行,但是必须保证程序在最坏的情况下得到的问题被妥善处理。
python的异常处理模块全部语法为:
try:
尝试实现某个操作,
若无异常,任务可以完成,
若有异常,将异常从当前代码块扔出去尝试解决异常(一旦出错,从出错的地方直接进入except)
#越具体的错误越往前放,当不清楚是哪一类异常时,可以直接使用BaseException
#越是父亲类的异常越往后放
except 异常类型:
解决方案1:用于尝试在此处处理异常解决问题
except 异常类型2::
...
except (异常类型1, 异常类型2...)
...
else:
如果没有出现任何异常,将会执行此代码
finally:
有无异常都要执行
除了except(至少一个)以外,else和finally都是可选的。
案例
在某些情况下,用户希望自己引发一个异常,可以使用raise关键字来引发异常。
raise error_name
案例1
案例2(自己定义异常)
只要是raise异常,则推荐自定义异常。
在自定义异常的时候,一般包含以下内容:
最终目的是,一旦发生异常,方便程序员快速定位错误现场。
日历相关模块。
获取一年的日历
参数:
判断是否是闰年
获取指定年份之间的闰年个数
时间戳,一个时间表示方法,根据不同语言,可以是整数或浮点数,是从1970年1月1日0时0分0秒到现在经历的秒数。
32位系统能够支持到2038年。
UTC时间又称为世界协调时间,以英国格林尼治天文所在地区时间作为参考时间,也叫作世界标准时间。
中国时间是UTC+8 东八区
夏令时就是在夏天的时候将时间调快一小时,本意是督促大家早睡早起省蜡烛,每天变成25个小时。
一个包含时间内容的普通元组。
提供日期和时间的运算和表示。
datetime常见属性:
from datetime import datetime
跟操作系统相关,主要是文件操作。
与系统相关的操作,主要包含在三个模块里:
绝对路径:总是从根目录上开始;
相对路径:基本以当前环境为开始的一个相对的地方。
ls是列出当前文件和文件夹的系统命令。
归档和压缩
归档:把多个文件或文件夹合并到一个文件中
压缩:用算法把多个文件或文件夹无损或有损合并到一个文件中
随机数,所有的随机模块都是伪随机。
参考博客https://www.cnblogs.com/yyds/p/6901864.html
使用logging提供的模块级别的函数记录日志
案例:
在当前路径下会自动生成testLog.log文件:
logging日志模块四大组件记录日志
案例
需求:
1)要求将所有级别的所有日志都写入磁盘文件中
2)all.log文件中记录所有的日志信息,日志格式为:日期和时间 - 日志级别 - 日志信息
3)error.log文件中单独记录error及以上级别的日志信息,日志格式为:日期和时间 - 日志级别 - 文件名[:行号] - 日志信息
4)要求all.log在每天凌晨进行日志切割
在当前路径下生成all.log和error.log。
all.log:
error.log:
Python语言的高级特性。
函数式编程是基于Lambda演算的一种编程方式
Python函数式编程知识借鉴函数式编程的一些特点,可以理解为一半函数式一半Python。
函数存在的最大意义就是最大程度复用函数,但存在的一定的问题:如果函数很小、很短,则会很啰嗦,此时如果函数调用的次数少,则会造成浪费,对于阅读者来说,造成阅读流程的被迫中断。
lambda表达式(匿名函数):
lambda表达式用法:
高阶函数:把函数作为参数使用的函数。
函数名称就是一个变量。
以上代码得出结论:函数名称是变量;funB和funA只是名称不同;既然函数名称是变量,那么就可以被当做参数传入另一个函数。
案例
以上高阶函数非常灵活,当不是放大300倍时,只需要修改传入的参数即可,不需要改动funB函数。
原意为映射,即将集合或列表中的每一个元素按照一定规则进行操作,生成一个新的列表或集合。
map函数是系统提供的具有映射功能的函数,返回值是一个迭代对象。
案例
原意是归并,缩减,把一个可迭代对象最后归并为一个结果。
reduce必须导入functools包。
对于作为其参数的函数有以下要求:
案例
过滤函数:对一组数据进行过滤,符合条件的数据会生成一个新的列表并返回。
与map比较:
filter函数怎么写:
案例
把一个序列按照给定算法进行排序。
key:在排序前对每一个元素进行key函数运算,可以理解为按照key函数定义的逻辑进行排序。
python2和python3相差巨大。
函数名可以作为具体的返回值。
案例
【拓展】
闭包(closure)
当一个函数在内部定义函数,并且内部函数应用外部函数的参数或局部变量,且当函数被作为返回值时,相关参数和变量保存在返回的函数中,这种结果叫做闭包。
以上案例中的myF是一个标准的闭包结构。
闭包常见坑案例
造成上述问题的原因:返回函数引用了变量i,i并非立即执行,而是等到三个函数都返回的时候才统一使用,此时i已经变成了3,最终调用的时候,都返回3*3。
此问题描述成:返回闭包时,返回函数不能引用任何循环变量。
解决方案:再创建一个函数,用该函数的参数绑定循环变量的当前值,无论该循环变量以后如何改变,已经绑定的函数参数值不再改变。解决如下:
在不改动函数代码的基础上无限制扩展函数功能的一种机制,装饰器是一个返回函数的高阶函数。
装饰器的好处:一经定义,则可以装饰任意函数;一旦被装饰,则把装饰器的功能直接添加到定义函数的功能上。
使用@语法(此符号是python的语法糖),即在每次要扩展到函数定义前使用@+函数名。
参数固定的函数,相当于一个有特定参数的函数体。
functools.partial的作用是将一个函数的某些参数固定,返回一个新函数。
把两个可迭代内容生成一个可迭代的tuple元素类型组成的内容。
案例
和zip的功能比较像。对可迭代对象中的每一个元素配上一个索引,索引和内容构成tuple元素。
案例
常用:
namedtuple
tuple类型,是一个可命名的tuple。
deque
比较方便地解决了频繁插入删除带来的效率问题。
案例
defaultdict
当直接读取dict不存在的属性时,直接返回默认值。
案例
Counter
统计字符串个数。
案例
长久保存信息的一种数据信息集合。
常用操作:
open函数负责打开文件,带有很多参数。
r:以只读方式打开;
w:以写方式打开,会覆盖以前的内容(文件若不存在会自动创建);
x:以创建方式打开,如文件已经存在,则报错;
a:append方式,以追加的方式对文件内容进行写入;
b:binary方式,二进制方式写入;
t:以文本方式打开;
+:可读写。
案例
with语句使用的技术是一种上下文管理协议技术(ContextManagementProtocal),其会自动判断文件的作用域,自动关闭不再使用的打开的文件句柄。
对文件的操作一般都要求使用with语句。
案例
案例1:按行读取
案例2:全部读取:
案例3:read按字符读取
以上最后一个案例为什么看上去不是每行打印三个字符呢?
原因如下:
我们手动输入的回车换行符在编译时会被替换为\n,即我将如何和你招呼\n以眼泪\n以沉默,而python中的print函数默认每次打印以换行结尾,故每次读取三个字符打印出来的结果为:
我将如
何和你
招呼\n
以眼泪
\n以沉
默
将\n转义一下,就会得到以上截图中的结果了。
移动文件的读取位置,也叫读取指针。
from的取值范围:
移动的单位是字节(byte),注意一个汉字不是一个字节(若干字节)。
返回文件只针对当前位置。
案例
用来显示文件读写指针当前的位置(以字节byte为单位)。
案例
案例
序列化(持久化,落地):把程序运行中的信息保存在磁盘上。
反序列化:序列化的逆过程。
pickle:python提供的序列化模块。
pickle.dump:序列化。
pickle.load:反序列化。
案例1
案例2(结构化数据)
持久化工具,类似字典,用k-v保存数据,存取方式与字典相似。
打开open,关闭close。
shelve特性:
程序:一堆代码以文本形式存入一个文档
进程:程序运行的一个状态,包含地址空间、内存、数据栈等。每个进程有自己完全独立的运行环境,多进程共享数据是一个问题。
线程:一个进程的独立运行片段,一个进程可以有多个线程。可理解为轻量化的进程。一个进程的多个线程共享数据和上下文运行环境。
全局解释器锁(GIL):
Python代码的执行是由Python虚拟机进行控制的,在主循环中只能有一个控制线程执行。
Python包:
案例:多线程-减少程序执行时间
未使用多线程,按顺序执行共执行约6秒(print的时间相对于sleep的时间可以忽略不计):
主线程分配完任务,不等待loop1、loop2子线程执行完就直接报告完成任务:
多线程,传参数:
直接利用threading.Thread生成Thread实例。
案例
守护线程案例
非守护线程(主线程结束,子线程依然执行):
守护线程(子线程和主线程一起死亡):
案例
企业中常用的写法(实用):
import threading
import time
loop = [4,2]
class ThreadFunc:
def __init__(self, name):
self.name = name
def loop(self, nloop, nsec):
'''
:param nloop: loop函数的名称
:param nsec: 系统休眠时间
:return:
'''
print("Start loop ", nloop, 'at ', time.ctime())
time.sleep(nsec)
print("Done loop ", nloop, 'at ', time.ctime())
def main():
print("Starting at ", time.ctime())
t = ThreadFunc("loop")
t1 = threading.Thread(target=t.loop, args=("LOOP1", 4))
t2 = threading.Thread(target=ThreadFunc('loop').loop, args=("LOOP2", 2))
t1.start()
t2.start()
t1.join()
t2.join()
print("All done at", time.ctime())
if __name__ == '__main__':
main()
while True:
time.sleep(10)
共享变量:当多个线程同时访问一个变量时,会产生共享变量问题。
解决变量:锁、信号灯。
锁(Lock):
是一个标志,标志一个线程在占用一些资源。
使用方法:
注意事项:
import threading
sum = 0
loopsum = 1000000
lock = threading.Lock()
def myAdd():
global sum, loopsum
for i in range(1,loopsum):
#上锁、申请锁
lock.acquire()
sum += 1
#释放锁
lock.release()
def myMinu():
global sum, loopsum
for i in range(1,loopsum):
#上锁、申请锁
lock.acquire()
sum -= 1
#释放锁
lock.release()
if __name__ == '__main__':
print("Starting....{}".format(sum))
t1 = threading.Thread(target=myAdd, args=())
t2 = threading.Thread(target=myMinu(), args=())
t1.start()
t2.start()
t1.join()
t2.join()
print("Done....{}".format(sum))
线程安全问题:
如果一个资源/变量,它对于多线程来讲,不用加锁也不会引起任何问题,则成为线程安全。
线程不安全变量类型:
线程安全变量类型:
生产者消费者问题(多线程同步问题经典案例):
一个模型。可以用来搭建消息队列。解耦生产者和消费者。
queue是一个用来存放变量的数据结构,特点是先进先出,内部元素排队,可以理解为一个特殊的List。
import queue
import time
import threading
#模拟生产者
class Producer(threading.Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() < 1000:
for i in range(100):
count += 1
msg = '生成产品' + str(count)
queue.put(msg)
print(msg)
time.sleep(0.5)
#模拟消费者
class Customer(threading.Thread):
def run(self):
global queue
while True:
if queue.qsize() > 100:
for i in range(3):
msg = self.name + "消费了" + queue.get()
print(msg)
time.sleep(1)
if __name__ == '__main__':
queue = queue.Queue()
for i in range(500):
queue.put('初始产品'+str(i))
for i in range(2):
p = Producer()
p.start()
for i in range(5):
c = Customer()
c.start()
死锁问题:
申请和释放的顺序应该是相反的。
产生死锁:
import threading
import time
lock_1 = threading.Lock()
lock_2 = threading.Lock()
def func_1():
print("func_1 Starting......")
lock_1.acquire()
print("func_1 申请了lock_1......")
time.sleep(2)
print("func_1 等待lock_2......")
lock_2.acquire()
print("func_1申请了lock_2......")
lock_2.release()
print("func_1释放了lock_2......")
lock_1.relase()
print("func_1释放了lock_1......")
print("func_1 Done......")
def func_2():
print("func_2 Starting......")
lock_2.acquire()
print("func_2 申请了lock_2......")
time.sleep(4)
print("func_2 等待lock_1......")
lock_1.acquire()
print("func_2申请了lock_1......")
lock_1.release()
print("func_2释放了lock_1......")
lock_2.relase()
print("func_2释放了lock_2......")
print("func_2 Done......")
if __name__ == '__main__':
print("主程序启动......")
t1 = threading.Thread(target=func_1, args=())
t2 = threading.Thread(target=func_2, args=())
t1.start()
t2.start()
t1.join()
t2.join()
print("主程序结束......")
锁的等待时间问题:
func_1申请不到资源后会释放本身持有的资源(解决死锁的一种方法)。
import threading
import time
lock_1 = threading.Lock()
lock_2 = threading.Lock()
def func_1():
print("func_1 Starting......")
lock_1.acquire(timeout=4)#超过4秒就不等了
print("func_1 申请了lock_1......")
time.sleep(2)
print("func_1 等待lock_2......")
rst = lock_2.acquire(timeout=2)
if rst:
print("func_1得到了lock_2......")
lock_2.release()
print("func_1释放了lock_2......")
else:
print("func_1注定申请不到lock_2......")
lock_1.release()
print("func_1释放了lock_1......")
print("func_1 Done......")
def func_2():
print("func_2 Starting......")
lock_2.acquire()
print("func_2 申请了lock_2......")
time.sleep(4)
print("func_2 等待lock_1......")
lock_1.acquire()
print("func_2申请了lock_1......")
lock_1.release()
print("func_2释放了lock_1......")
lock_2.release()
print("func_2释放了lock_2......")
print("func_2 Done......")
if __name__ == '__main__':
print("主程序启动......")
t1 = threading.Thread(target=func_1, args=())
t2 = threading.Thread(target=func_2, args=())
t1.start()
t2.start()
t1.join()
t2.join()
print("主程序结束......")
semaphore:
允许一个资源做多由几个线程同时使用。
import threading
import time
#允许最多三个线程同时使用
semaphore = threading.Semaphore(3)
def func():
if semaphore.acquire():
for i in range(5):
print(threading.currentThread().getName() + ' get semaphore')
time.sleep(15)
semaphore.release()
print(threading.currentThread().getName() + ' release semaphore')
for i in range(8):
t = threading.Thread(target=func)
t.start()
threading.Timer:
在指定的秒数后执行指定的函数。Timer利用多线程,在指定时间后启动一个功能。
可重入锁:
一个锁可以被一个线程多次申请。主要解决递归调用的时候需要申请锁的情况(以下案例中如果不使用可重入锁,将会产生死锁)。
import threading
import time
class MyThread(threading.Thread):
def run(self):
global number
time.sleep(1)
if mutex.acquire(1):
number += 1
msg = self.name + 'set number to ' + str(number)
print(msg)
mutex.acquire()
mutex.release()
mutex.release()
number = 0
mutex = threading.RLock() #可重入锁
def testRL():
for i in range(4):
t = MyThread()
t.start()
if __name__ == "__main__":
testRL()
subprocess
multiprocessing
concurrent.futures
进程间的通讯(InterprocessCommunication,IPC)
进程之间无任何共享状态。
进程的创建:
在os中查看pid、ppid以及它们的关系:
生产者消费者模型:
import multiprocessing
from time import ctime
def customer(input_q):
print("Into customer:", ctime())
while True:
item = input_q.get()
print("pull", item, "out of q")
input_q.task_done() #发出信号通知任务完成
print("Out of consumer:", ctime())
def producer(sequence, output_q):
print("Into producer:", ctime())
for item in sequence:
output_q.put(item)
print("put", item, "into q")
print("Out of producer:", ctime())
if __name__ == "__main__":
q = multiprocessing.JoinableQueue()
cons_p = multiprocessing.Process(target=customer, args=(q, ))
cons_p.daemon = True
cons_p.start()
sequence = [1, 2, 3, 4]
producer(sequence, q)
q.join()
import multiprocessing
from time import ctime
def customer(input_q):
print("Into customer:", ctime())
while True:
item = input_q.get()
if item is None:
break
print("pull", item, "out of q")
print("Out of consumer:", ctime())
def producer(sequence, output_q):
print("Into producer:", ctime())
for item in sequence:
output_q.put(item)
print("put", item, "into q")
print("Out of producer:", ctime())
if __name__ == "__main__":
q = multiprocessing.Queue()
cons_p = multiprocessing.Process(target=customer, args=(q, ))
cons_p.start()
sequence = [1, 2, 3, 4]
producer(sequence, q)
q.put(None)
cons_p.join()
import multiprocessing
from time import ctime
def customer(input_q):
print("Into customer:", ctime())
while True:
item = input_q.get()
if item is None:
break
print("pull", item, "out of q")
print("Out of consumer:", ctime())
def producer(sequence, output_q):
print("Into producer:", ctime())
for item in sequence:
output_q.put(item)
print("put", item, "into q")
print("Out of producer:", ctime())
if __name__ == "__main__":
q = multiprocessing.Queue()
cons_p1 = multiprocessing.Process(target=customer, args=(q, ))
cons_p1.start()
cons_p2 = multiprocessing.Process(target=customer, args=(q,))
cons_p2.start()
sequence = [1, 2, 3, 4]
producer(sequence, q)
q.put(None)
q.put(None)
cons_p1.join()
cons_p2.join()