高级特性:
迭代:
只要是可迭代对象,都可以使用for循环进行迭代
python中使用for 。。。in
迭代多个值,如
d = {‘a’:1,‘b’:2}
for k,v in d.items
要对list实现类似java下标循环可以使用enumerate函数
切片:
去list或者tuple部分元素,python提供了比较好的切片工具
创建0-99的数列
L = list(range(100)) 这个是列表生成式
L[:10]表示取前10个数0-9
L[:10:2]表示取前10个数,每个数步长为2,就是0,2,4,6,8
循环的语句比较繁琐,列表生成式可以一行语句就解决
如:[x*x for x in range(1,11)]
多个变量取值
if …else生成式的原则是:如果if在for前面,后面一定要加else,如果在for后面,不允许带else,因为跟在for后面是一个筛选条件
生成器:
generator创建有很多方法,需要把[]改成()
如
g = (x *x for x in range(10))
可以通过next()函数获得生成器的下个返回值
,生成器保存的是算法,每次调用next(),如果没有更多元素,会抛出StopIteration错误
因为生成器也是可迭代对象,所以也可以使用for
生成器使用多的打印可以用yield
迭代器:
使用for循环的数据类型有:
集合数据类型,如list,tuple等
生成对象,包括生成器和带yield的一般方法
直接作用于for循环的对象我们成为可迭代对象,Iterable
判断一个对象是否是可迭代对象 isinstance()
迭代器:是可以被next()函数调用并返回下一个值得对象Iterator
同样可以用isinstance()判断是否是迭代器对象
生成器都是Iterator对象,但是list,dict虽然可迭代,但不是迭代器
可以使用iter()把他们变成迭代器
这里理解下Python的Iterator对象表示的是一个数据流,可以被next()函数调用,直到没有数据抛出StopIteration错误
函数式编程
高阶函数
map/reduce
map()接收两个参数,一个是函数,一个Iterable,返回的结果是Iterator
如 f(x) = x*x
reduce是把一个函数作用在一个序列上,这个函数必须接受两个参数,reduce的任务就是把结果和序列的下一个元素做累计计算,
如
map返回的是是Iterator,而reduce第二个参数就是需要一个可迭代对象
外加lambda函数进一步简化
filter函数,用于过滤序列,实现筛选
与map接收参数一样,区别在于函数会作用每个元素,根据返回值保留元素
如,一个list值要奇数
比如用filter求素数
思路:
使用埃式筛法
这里补充一点yeild的功能,它的出现就代表着生成器,类似于return
https://blog.csdn.net/mieleizhi0522/article/details/82142856?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159880396919725219961679%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159880396919725219961679&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-2-82142856.first_rank_ecpm_v3_pc_rank_v4&utm_term=yeild&spm=1018.2118.3001.4187
再回到这个问题
sorted
排序算法也是程序中经常碰到的算法,排序的核心是比较两个元素的大小,数字可以直接比较,字符串和dict比较需要通过函数抽象出来
对list进行排序
sorted函数还可以加key函数实现自定义排序
按照不考虑大小写,进行翻转排序
返回函数
有时候我们不需要立马得到运算结果,可以将其整体构造函数,返回函数值即可
上面例子就是返回sum值,详细的内容在里面写
只有当初始化函数的时候才会打印出最后的求和结果
匿名函数
有时候我们不需要显示地定义函数,直接传入匿名函数比较方便,世界上lambda就是匿名函数的关键字
如上面提到的求平方
用lambda表示就是list(map(lambda x:x*x,[1,3,5,7,9]))
lambda那块实际上就是循环的语句
也可把匿名函数当做返回值返回
def build(x,y):
return lambda:xx+yy
装饰器
将函数当做一个对象,而函数对象也可以赋值给变量,通过变量同样可以调用函数
装饰器的功能就是不改变原有的代码,在此基础上新加的功能。
这种动态增加功能的方式,称为装饰器(decorator)
调用装饰器的时候只需要@+函数名
偏函数
目的是转换成自己想要的进制
作用域
模块中定义的函数和变量有些是希望给别人用的,有些事仅仅内部模块使用,通过_前缀实现
类似 _abc,private的函数和变量不应该被直接引用,可以作为代码封装和抽象
第三方模块
使用pip,这种方法呢速度比较慢,通常我们使用
anaconda自带的模块,直接导入即可,如import sys
面向对象编程
类和实例
python中一切皆对象,对象最重要的概念就是类和实例
object是所有类都会继承的类
class +类名(object):
实例化类:类名+()即可
在定义一个类时,可以把必须绑定的属性强制填写进去,使用__init__方法
上面就实现了name,score属性绑定
self就指向创建的实例本身,实例化的时候self不需要传
在类中定义函数可以实现封装,在实例化的时候只需要调用类名,不需要知道内部怎么实现的
访问限制
有时候我们不希望外部能够修改内部的属性值,所以在属性的名称前加__,变成私有变量
但是如果需要获取属性怎么办 呢
可以添加get,set方法,通过这种方法可以避免传入无效的参数
继承和多态
继承就是在把类名放到()中
其实当我们定义了一个类时,就是将数据类型定义了
判断某个变量是否是某个类型时用isinstance()方法
多态就是当我们新增子类的时候,只需要接受父类型就可以了,可以使用父类的方法
如何获得对象的信息
比如现在我们拿到一个对象的引用,如何知道它是什么类型、有哪些方法呢
使用type()函数,
获取一个对象的所有属性和方法,使用dir()函数
实例属性和类属性
所以实例属性和类属性的名称尽量不要一样
面向对象高级编程
使用__slots__
当我们只允许某个实例添加属性,就可以在定义类的时候添加__slots__变量
该变量只对当前类实例起作用,对继承的子类是不起作用的
使用@property
这种方式略显复杂,设置实例的范围
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
装饰器就可以给函数动态加上功能,@property就是如此
多重继承
当分类的方法增加时,类的数量定义就会呈指数增长,这样设计不行的,正确做法是多重继承
就是把所有功能的类定义好,最后多继承一个类
这种设计被称为Mixln
定制类
带有__的变量或者函数,这在python中有特殊用途
slots 限定属性或者方法
len 能让class作用于len()
str 返回一个好看的字符串
iter 一个类想被用于for 。。。in循环,就必须实现__iter__()方法,该方法返回的是一个迭代对象,
getitem ,for循环中,能够像list那样按照下标取出元素,
getattr 有时候调用不存在的属性时会报错,这个时候除了加上一个属性外,还可以使用__getattr__()方法,动态返回一个属性
call 一个对象实例可以有自己的属性和方法,直接实现调用
枚举类
当我们定义常量时,一个办法就是大写变量通过整数定义
好的方法是定义个class类型,然后每个常量都是class的一个唯一实例
使用Enum类实现
使用元类
动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。
这里需要以下type,object,class的区别
先定义metaclass,就可以创建类,最后创建实例
比较难的一个类
错误处理
程序编写有问题,称为bug
用户自身造成的,用户输入的格式不正确
异常现象,比如网络突然中断
open()打开文件的函数
错误处理机制
try… except…finally
抛出错误,首先定义一个错误的class,然后选择好继承关系,然后使用raise语句抛出一个错误的实例
这个方式就是讲错误交给最后能解决的那个对象
调试
调试的目的就是需要知道到底出错在哪里,从而来解决bug
第一种调试方式就是 通过print()把可能有问题的变量打印出来
第二种方法是通过断言来替代,这样可以变后面删除大量的print
启动python解释器时可以用-O 参数来关闭assert
第三种就是使用logging,它不会抛出错误,而且可以输出到文件
logging.info()
import logging
logging.basicConfig(level = logging.INFO)
s = ‘0’
n = int(s)
logging.info(‘n = %d’ %n)
print(10/n)
这就是logging的好处,它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。
logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。
第四种调试就是使用python的调试器pdb,程序单步方式运行
第五种就是IDE了,也是我们比较常用的工具
Pycharm和Visual Studio Code(需要安装python插件)
Eclipse加上pydev插件也可以调试python程序
logging才是终极武器。
单元测试
单元测试就是对一个模块、一个函数或者一个类来进行正确性检验的测试工作
比如abs(),我们需要编写几个测试用例
这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。
当你在单元测试中启动一个数据库时,最好的方法就是从公共方法中连接,这样就不需要每个测试方法都重复相同的代码
class TestDict(unittest.TestCase):
def setUp(self):
pass
def tearDump(self):
pass
文档测试,是为了方便调用者理解函数的输入和输出
IO编程
即所谓的input/output,程序和运行时数据都是在内存中驻留,数据交换的方法通常是磁盘、网络、所以需要IO接口
接收数据叫input,外发数据叫output
从磁盘读取文件到内存,只有input操作,相反,把数据写到磁盘,就只有output
整个操作的对象是Stream
流相当于水管,数据类似水,只能单向流动
由于CPU、内存、外设的数据传输速度不一样,就存在传输不匹配
有两种方法解决这个问题
第一、同步IO,即等数据完全写入磁盘,在交给cpu去处理
第二、异步IO,CPU不等待,磁盘的传输不影响程序的执行
同步异步区别:
是否等待IO执行的结果,同步就是需要等待执行的结果
文件读写
读写文件的功能都是由操作系统提供,所以,读写文件就是请求操作系统打开一个文件对象。然后通过操作系统提供的接口从这个文件对象中读取数据,或者把数据写入这个文件对象(写文件)
读文件:open()
f = open(‘/users/michael/test.txt’,‘r’)
如果文件不存在,是会抛出IOError的,有时候我们需要处理这个异常
打开文件后使用read()方法可以一次读取文件的全部内容,python读到的内容是用str对象表示
f.read()
最后是调用close()方法关闭文件
不关闭会占用系统资源
f.close()
结合上面的思路,正常读文件的代码
try:
f = open(‘/path/usr/tex.txt’,‘r’)
print(f.read())
finally:
if f:
f.close()
这样写也比较繁琐,python提供了with()方法,这个方法就是对资源的配置
with open(‘/path/usr/tex.txt’,‘r’) as f:
print(f.read())
其中read()、read(size)、readlines()是有区别的
上面这种读取的对象在python中统称为file-like Object
StringIO就是在内存中创建的file-like Object,常用作临时缓冲
二进制文件(图片、视频)
读取文件,后面的模式用rb,还可以传入encoding参数
如
f = open(‘/Users/michael/test.jpg’, ‘rb’)
f.read()
b’\xff\xd8\xff\xe1\x00\x18Exif\x00\x00…’ # 十六进制表示的字节
有时候文件夹杂着些非法编码字符,可以设置参数errors,最直接的处理方式是忽略
写文件
同样是调用open,唯一区别是传入的模式不同,读文件是r或者rb,而写则是w或者wb或者a
然后调用的是write()方法
还是使用with是最保险的
with open(‘user/a/r.txt’,‘w’,errors=‘ignore’)as f:
f.write(‘abc’)
StringIO和BytestIO
第一个就是在内存中读取str
把str写入StringIO,需先创建一个StringIO,然后像文件一样写入即可
第二个方法是操作二进制数据的
操作文件和目录
python使用OS模块
需要导入os模块
os.environ 查看环境变量
os.name 查看操作系统类型
os.uname 查看系统详细信息
os.environ.get(‘key’)获得某个环境变量的值
操作文件和目录的函数一部分在os模块,一部分在os.path模块
os.path.abspath(‘.’) 查看当前目录绝对路径
os.mkdir(‘/user/a/b’) 创建一个目录
os.rmdir(’user/a/b‘)删除一个目录
合并两个路径,不要直接拼接字符串,使用函数
os.path.join()函数
这样可以正确处理不同操作系统的路径分隔符
如os.path.join(‘user/a’,‘testdir’)
拆分路径的话,使用os.path.split()函数
os.path.splitext()可以直接得到文件扩展名
复制文件不是操作系统提供,需要使用shutil模块提供的copyfile()函数
最后看看如何使用python的这些特性来过滤文件
实例1,列出当前目录下的所有目录
[x for x in os.listdir(‘,’ if os.path.isdir(x)]
实例2,列出所有.py文件
[x for x in os.listdir(‘.’) if os.path.isfile(x)and os.path.splitext(x)[1]==‘.py’]
序列化
把变量从内存中变成可存储或传输的过程称之为序列化,在python叫picking,其他语言也被称为serialization,flattening等
序列化之后就可以把内容写入磁盘,或者传输到别的机器上
反过来我们把序列化的对象重新读到内存里称为反序列化,即unpicking
python中pickle模块是来实现序列化
pickle.dumps(d)将对象d序列化成一个bytes
pickle.dump(d,f)将对象d序列化后写入一个file-like object
pickle.loads()反序列化出对象
也可直接pickle.load()从一个file-like object直接反序列化出对象
不同编程语言之间对象传递,最好是序列化为JSON或者xml
JSON表示的对象就是标准的JavaScript语言的对象
python有内置的json模块,可以实现python对象到json的转换
python的os模块封装了常见的系统调用,包括fork
fork在Windows无法调用,可以使用multiprocessing模块替代
Process类代表一个进程对象
正则表达式:
用描述性的语言定义一个规则,凡是符合规则的字符串就是匹配的
\d 匹配一个数字
\w匹配一个字母或数字
.匹配任意字符
*匹配任一个字符
+表示至少一个字符
?表示0或1个字符
{n}表示n个字符
{n,m}表示n-m个字符
\s匹配一个空格(也包括tab等空白符)
特殊字符需要用转义’\‘
比如- 就可以表示成-
更精确的匹配,可以使用[]表示范围
[0-9a-zA-Z_]可以匹配一个数字、字母或者下划线
^表示行的开头 ^\d表示必须以数字开头
KaTeX parse error: Undefined control sequence: \d at position 8: 表示行的结束 \̲d̲表示必须以数字结束
()表示提取的分组,通常作为提取子串
python中提供了re模块,包含所有正则表达式功能
内建模块
datetime库:
datetime.now()当前时间
d.timestamp()时间转换成时间戳形式
datetime.fromtimestamp(t) 时间戳t转换成datetime
时间戳也可以直接转换成utc时间
datetime.utcfromtimestamp(t)
datetime.strtime(‘2015-6-1 18:19:59’,‘%Y-%m-%d %H:%M:%S’)
str 转换成datetime,后面的字符串规定了日期和时间部分的格式
d.strftime() datetime转换成str
datetime加减,但是需要导入timedelta这个类
本地时间转utc
from datetime import datetime,timedelta,timezone
tz_utc_8 = timezone(timedelta(hours = 8))
时区转换
先拿到当前的UTC时间,在转化
utc_dt = datetime.utcnow().replace(tzinfo = timezone.utc)
#表示拿到utc时间,并强制设置时区为utc+0:00
bj_dt = utc_dt.astimezone(timezone(timedelta(hours = 8)))
#转换成北京时间
collections库
namedtuple 创建一个自定义tuple对象,
Circle = namedtuple(‘Circle’,[‘x’,‘y’,‘r’])
deque 是为了高效实现插入和删除操作的双向列表
支持append,pop,appendleft,popleft