核心知识梳理(五)

Day34:描述器

在python中,实现了__get____set____delete__三个方法中的任意一个都称为描述器;其中仅实现了__get__方法的称为非数据描述器,实现了__get____set__方法的称为数据描述器,我们来看一下这三个方法的语句:

object.__get__(self, instance, owner)
object.__set__(self, instance, value)
object.__delete__(self, instance)
  • 当非数据描述器是实例的变量时,实例访问非数据描述器不会调用__get__方法,只是访问了描述器类的实例;当数据描述器是实例的变量时,实例访问数据描述器会调用描述器的get方法
  • 当存在描述器的时候,一个类实例的查找属性顺序为:先查找类或父类中是否有数据描述器属性,如果有那么,先访问数据描述器,如果没有数据描述器 --> 那么就会查找自己实例的dict属性,如果dict属性里面也没有找到 --> 就会在类或父类的非数据描述器中进行查找

Day35:模块化开发

  • 模块化是代码的组成的一种方式,Python中的每一个文件就是模块,模块化开发能够将不同的功能组装在一起,实现功能的累加,诸多功能组装在一起,最终形成项目
  • 在Python中,文件有三种方式进行组织分别是:Python模块、目录、包;以.py后缀名结尾的文件就是python的一个模块,而包和目录的不同之处在于包内部多一个init.py文件,使得包能够被模块导入,而目录则不能
  • 模块的导入分为绝对导入和相对导入
其中绝对导入是从python的搜索路径中导入对应的包中的模块,格式为:from package import module

相对导入只能在导入包中的模块时才能使用,不能在执行文件中用,
格式为from . import module ,如果是一个点表示当前模块,两个点表示上层模块,三个点表示上上层模块
且相对导入的模块无法直接运行,必须使用python -m package.module这样的方式运行,
或者被__main__模块导入之后使用from . import module运行
  • 在模块导入中,模块中所有的对象都能够被导入,没有私有和保护属性的概念,我们在导入时可以指定允许被导入的对象。但是如果使用from 模块名 import *方式导入时,模块内所有对象都将被导入,此时我们可以使用列表__all__申明允许被导入的对象,如__all__ = ['add', 'a']

  • 在开发中__slots__可以告诉Python不要使用字典,而且只给一个固定集合的属性分配空间,所以我们可以使用__slots__来加快的属性访问速度和减少内存消耗

  • 一个python文件通常有两种使用方法,一种是直接作为脚本直接执行,另一种是导入到其他的 python 脚本中被调用执行,我们可以通过判断语句if __name__ == '__main__'来判断模块是直接执行还是被导入的,当条件为真时就是直接被执行,可以继续执行条件语句后面的代码块,条件为假时(被导入)则不会执行后面的代码块

Day36:异常处理

  • 异常就是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行,一般情况下,在Python无法正常处理程序时就会发生一个异常,当发生异常时我们需要捕获处理它,否则程序会终止执行

  • 异常和错误的区别是异常可以被捕获,而错误有时候无法被捕获,语法错误会被IDE检查到,但是逻辑错误无法被知晓

  • 捕捉异常可以使用try/except语句,包含在try下的所有代码块都会进行异常检测处理 ,如果没有出现异常则正常执行try后面的代码块,如果出现异常通过except来捕获异常信息并处理

try:
  需要被捕获异常的代码块
except 异常类型对象:
  处理捕获到的异常
  • except后面可以指定要捕获的异常类型,如BaseException是所有异常的基类,Exception表示常规错误的异常等,我们可以自定义异常,但是所有的自定义异常类需要继承Exception;可以把多个 except语句连接在一起, 处理一个 try 块中可能发生的多种异常

  • 我们知道只有try语句块中发生了异常,才会执行exceptfinally是不管try中有没有发生异常都会执行的,所以我们可以在finally中关闭文件,或者做一写其他清理工作

  • 处理异常除了使用try/except语句,我们还可以通过raise自己触发异常,语法格式为raise [Exception [, args [, traceback]]],语句中 Exception 是异常的类型(例如,NameError)参数标准异常中任一种,args 是自已提供的异常参数,最后一个参数是可选的,如果存在,是跟踪异常对象;注意一旦执行了raise语句,raise之后的语句将不在执行

Day37:模块打包

  • 模块打包目的是让自己开发的功能能够实现共享,供给他人使用,包管理索引平台是Python Package Index
  • 模块打包有三种格式tar.gz格式、egg格式、whl格式
tar.gz格式是标准压缩格式,里面包含了项目元数据和代码,可以使用Python setup.py sdist命令生成

egg格式也是压缩文件,只是扩展名换了,里面包含了项目元数据以及源代码,
这个格式由setuptools项目引入, 可以通过命令Python setup.py bdist_egg命令生成

whl格式是Wheel包,也是一个压缩文件,只是扩展名换了,里面包含了项目元数据和代码,还支持免安装直接运行,
whl分发包内的元数据和egg包是有些不同的,可以通过命令Python setup.py bdist_wheel生成; 
  • 怎么打包
我们可以创建需要打包的模块,然后使用命令行将模块打包:python setup.py bdist_wheel;
还需要在PYPI平台注册账号,在邮箱中认证连接
接着在用户的家目录下创建~/.pypirc文件,将文件配置好
然后安装twine的命令行为:pip install twine;
最后可以将打包好的模块发送到PYPI平台:twine upload dist/*;

Day38:插件化开发与GUI开发

  • 插件化开发是一种思想,考虑到程序功能的加载时机,用到的时候再加载
  • 插件化开发依赖的技术点有:
反射:判断对象是否存在某种功能
动态import:运行时候,根据用户需求(提供字符串),找到模块的资源动态加载起来
多线程:使用线程完成对应的任务
  • 插件化开发的好处:可以开启一个线程,等待用户输入,从而加载指定名称的模块

  • 在插件化开发中,我们可以使用importlib模块动态导入,它的语法格式为

importlib.import_module(name, package=None),name为模块名称字符串,package当相对导入的时候需要传递的包名字符串

  • Python拥有大量可用的GUI 工具包,而Tkinter模块是 Python 的标准 GUI 开发库,可以快速的创建 GUI 应用程序,因为Tkinter是内置到 python 的安装包中,所以只要安装好 Python 之后就能直接导入使用import tkinter

Day39:线程(略难可选)

  • 线程有时被称为轻量进程,是程序执行流的最小单元,在Python中,使用threading库来创建线程,创建进程的语法:threading.Thread(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None),它的一些参数:
    group:为线程组,但是Python中没有线程组,所以这是保留参数;
    target:为可调用对象,也就是任务, 可以是函数,如果是实例,那么实例的类必须实现__call__方法;
    name:指定线程的名称;
    args、kwargs:给线程任务传递参数、关键字参数;
    daemon:指定子线程是否需要主线程等待,主线程是non-daemon线程;

  • Python中的线程没有优先级、线程组、停止、挂起、销毁、恢复的概念;线程退出的方式有两种:
    一种是线程任务执行完毕还有一种是线程内部抛出异常,使用线程之前需要先导入threading,语法为import threading

  • 线程的threading模块中的函数threading.active_count()表示依然存活的线程数,包括主线程、threading.current_thread()表示返回当前线程实例对象、threading.enumerate()表示返回当前存活的线程对象列表(包括主线程,但是不包括终止线程和未启动线程)、threading.main_thread()表示返回主线程实例对象、threading.get_ident()表示返回当前线程的ID

  • 线程的thread_obj有两个方法,分别是run方法start方法,其中start方法会在内存中启动一个新的线程运行任务,而 run方法不会启动新的线程,只是在主线程中执行任务

  • 一般在使用多线程的时候,如果需要打印线程的信息,不会使用print函数打印,而是使用logging日志模块打印,因为考虑到print函数在打印过程中可能出现线程的切换,为了确保线程安全通常使用logging模块,把线程的信息通过日志的形式打印出来

  • 线程中有父子的概念,如果在主线程中启动了一个线程,那么主线程就是父线程,启动的这个工作线程就是子线程&

主线程是non-daemon线程,也就是daemon=False, 如果子线程的daemon=False,
那么主线程会等待子线程执行完毕,主线程才会终止,如果 为True,
那么主线程将不会等待子线程,而是主线程执行完毕后,子线程就会终止运行;

daemon选项必须在启动线程之前设定;
  • 线程中的join方法的语法为:join(self, timeout=None),在当前线程中调用另一个线程的join方法,当前线程会在此处被阻塞,直到被调用的线程结束运行或终止,timeout指定被阻塞的时长,如果没有指定 ,那么就一直阻塞直到调用线程终止;

  • Timer是Thread的一个派生类,用于在指定时间后调用一个方法,如果想实现每隔一段时间就调用一个函数的话,就要在Timer调用的函数中,再次设置Timer;
    创建一个定时任务:threading.Timer(self, interval, function, args=None, kwargs=None)

Day40:线程同步与并发(略难可选)

  • 线程之间有很多种通信方式,例如Event(事件)、Critical Section(临界区,一般是通过加锁实现)、Semaphone(信号量)等

  • Event是事件处理的机制,全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True, 那么event.wait 方法时便不再阻塞

  • event实例对象的对象方法有一下几种:

wait(self, timeout=None):其中timeout为设置等待的时长,如果超过时长(返回值为False)则不再等待,直接向下执行,如果timeout没有指定则一 直等待,等待的时候是阻塞的没有返回值

set():如果执行event.set(),将会设置flag为True,那么wait等待的线程就可以向下执行

clear():如果执行event.clear(),将会设置flag标记为Flase, 那么wait等待的线程将再次等待(阻塞);

is_set():判断event的flag是否为True,如果为True的话wait等待的线程将向下执行

  • 锁是解决临界区资源的问题,保证每一个线程访问临界资源的时候有全部的权利,一旦某个线程获得锁, 其它试图获取锁的线程将被阻塞

加锁:acquire(blocking=True,timeout=-1),False为不阻塞,timeout为设置时长

释放锁:释放锁的方法为release(),在完成任务的时候释放锁,让其他的线程获取到临界资源,通过上下文管理器的方式with lock可以默认释放锁,不需要再写release()方法

  • pool实例对象有两个非常实用的方法,一个是submit(self, fn, *args, **kwargs)用于提交单个任务,还有一个是map(self, fn, *iterables, timeout=None, chunksize=1)类似高阶函数map,可以提交任务,且传递一个可迭代对象,返回任务处理迭代对象的结果

  • 尽管Python完全支持多线程编程, 但是解释器的C语言实现部分在完全并行执行时并不是线程安全的,
    实际上,解释器被一个全局解释器锁保护着 ,它确保任何时候都只有一个Python线程执行;

GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势,
就是因为GIL的存在,使得一个进程的多个线程在执行任务的时候,
一个CPU时 间片内,只有一个线程能够调度到CPU上运行

因此CPU密集型的程序一般不会使用Python实现,可以选择Java,GO等语言;

但是对于非CPU密集型程序,例如IO密集型程序,多数时间都是对网络IO的等待,
因此Python的多线程完全可以胜任
  • 对于全局解释器锁的解决方案有两个,一个是使用multiprocessing创建进程池对象,实现多进程并发,这样就能够使用多CPU计算资源,还可以使用C语言扩展,将计算密集型任务转移给C语言实现去处理,在C代码实现部分可以释放GIL

  • 如果想要同时使用多线程和多进程,最好在程序启动时,创建任何线程之前,先创建一个单例的进程池, 然后线程使用同样的进程池来进行它们的计 算密集型工作,这样类似于线程调用了进程,完成了CPU密集型任务,进程也利用了多CPU的优势

Day41:进程和并发(略难可选)

  • python中提供multiprocess模块实现多进程并发,multiprocessing支持子进程通信和共享数据执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件
可以通过multiprocessing.Process对象来创建一个进程,该进程可以运行在Python程序内部编写的函数

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建,它有start(), run(), join()的方法
  • concurrent模块能够提供一个future的实例对象,实例对象提供了线程的执行器和进程的执行器

  • pool的对象方法有三个:submit()map()shutdown(),其中submit()方法的返回值future对象的方法有如下方法:

submit():返回一个Future对象;
result():查看调用的返回结果;
done():如果任务成功执行或任务取消返回True;
cancel():取消任务;
running():如果任务正在执行返回True;
exception(): 获取执行抛出的异常;
  • 在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期 性的执行某种任务或等待处理某些发生的事件

  • 由于在linux中,每个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终 端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭

  • 但是守护进程却能突破这种限制,它脱离于终端并且在后台运行,并且它脱离终端的目的是为了避免进程在运 行的过程中的信息在任何终端中显示并且进程也不会被任何终端所产生的终端信息所打断,它从被执行的时候 开始运转,直到整个系统关闭才退出

守护进程实现的步骤如下:

父进程fork出子进程并exit退出
子进程调用setsid创建新会话
子进程调用系统函数chdir将根目录"/"成为子进程的工作目录
子进程调用系统函数umask将该进程的umask设置为0
子进程关闭从父进程继承的所有不需要的文件描述符
  • os.fork()返回两个值,一个是在当前父进程返回的,一个是在子进程中返回的,子进程返回的是0,父进程返回的是子进程的pid
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,746评论 0 10
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,764评论 0 8
  • 一. 操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式: 向下管理硬件,向上提供接口.操作系统进行...
    月亮是我踢弯得阅读 5,971评论 3 28
  • 线程 操作系统线程理论 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有...
    go以恒阅读 1,645评论 0 6
  • 今天在这个群里,看到一个同学写到越来越糊弄自己,写作业糊弄自己,但可能这个问题,我觉得我可能也有这个意思,当然...
    名扬天下99阅读 262评论 0 1