1 当Python解释器读取源代码时,为让它按UTF-8编码读取,通常在文件开头写两行:
# !/user/bin/env python3
# -*- coding:utf-8 -*-
第一行注释是告诉linux/os系统,这是个python可执行程序,windows系统会忽略
第二行注释是告诉python解释器,按照UTF-8编码读源代码,否则中文可能会乱码
2 格式化输出:
‘%d%s%s’%(a,b,c)
{0}{1:.1f}.format(a,b)
3 可通过append追加元素在列表末尾,通过pop弹出最后一个元素,在pop里放数字弹出对应key的数
tuple 对于单个元素的元组,可以通过(1,)来消除歧义
4 条件语句:
if clause:
pass
elif clause:
pass
else:
Pass
5 python内置字典dict在其他语言中成为map,使用key-value存储,极快的查找速度
通过dict提供的get方法,如果key不存在,返回None或者自己指定的值;
删除一个key使用pop(key),对应的value也会被删除
dict 有以下几个特点:
1)查找和插入的速度极快,不会随着key的增加而变慢
2)需要占用大量的内存,内存浪费多
list有以下特点:
1)查找和插入的时间随着元素的增加而增加
2)占用空间小,内存浪费少
set和dict类似,也是一组key集合,但是不存储value,它没有重复的key,通过add(key)方法可以增加元素到
set中,通过remove(key)方法删除元素,set不可以放入可变对象,因为无法判断两个可变对象是否相等
6 空函数
def nop():
pass
函数返回多个值其实是返回一个tuple
位置参数:最普通的参数,
默认参数:a=10,必选参数在前,默认参数在后,否则解释器会报错。当有多个参数时,把变化大的参数放在前面,变化小的参数放在后面,变化小的参数就可以作为默认参数。默认参数降低了函数调用的难度,而需要更复杂的调用时,又可传递更多的参数来实现
可变参数:*args。可以传入0个、一个以上的参数,或者元组和列表
关键字参数:**kargs,可以传入字典,对于关键字参数,可以传入不受限制的数量,到底传入了什么参数就要在函数内部检查了,如果要限制关键字参数的名字,就可以使用命名关键字参数,这种的定义方式如下,在*后面写变量名
def person(name,*,city):
pass
调用方式是person('Jack',city='beijing')
如果函数中已经有一个可变参数,就不需要特殊分割符号*了,比如
def person(name,*args,city)
命名关键字参数具有默认值时,可不传入值,比如:
def person(name,age,*,city='beijing',job):
pass
person('jack',24,job='engineer')
位置参数,默认参数,可变参数,关键字参数和命名关键字参数,这五种组合都可以使用
def func(a,b=0,*args,**kargs):pass
def func(a,b=0,*,c,**kargs):pass
def func(a,b=0,*args,c,**kargs):pass
7 如果一个函数在内部调用自身,则它就是递归函数。优点是逻辑清晰,缺点是占用内存,
要防止栈溢出,解决递归缺点的方法是通过尾递归优化。
尾递归是指函数返回的时候调用自身,并且return语句不能包含表达式,这样解释器就可以把尾递归做优化,使递归本身无论调用多少次,都占用一个栈帧,不会出现栈溢出的情况遗憾的是大多数编程语言没有对尾递归做优化,所以即使写成尾递归形式,也会导致溢出。
8 列表切片操作:
前三个元素:L[0:3]
倒数第一个元素的索引L[-1]
后十个数索引 L[-10:]
前十个数,每两个取一个 l[ :10:2]
所有的数,每5个取一个 l[ ::5]
tuple 也是一种list,唯一区别是tuple不可变,字符串也是一种list,可以切片
9 for in,迭代
for key in dict.keys() 迭代键
for value in dict.values() 迭代值
for k,v in dict.items() 迭代键值
10 列表生成式
list(range(1,11))
[x*x for x in range(1,11)]
[x*x for x in range(1,11) if x%2 ==0] 用if语句筛选
[m+n for m in range(1,11) for n in range(1,11)]
11 生成器
生成器即一边循环一边计算的机制。生成方法有:
1)将列表加()生成,
2)直接在()用列表生成式生成
3)使用yield关键字
12 迭代器
直接作用于for循环的数据类型有以下几种:
1)集合数据类型,如list、tuple、dict、set、str
2)生成器
13 函数式编程
变量可指向函数,函数名也可是变量,函数参数可接收另一函数作参数即成为高阶函数
14 map/reduce
由于map接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到
序列的每一个元素并将结果作为新的Iterator返回。Iterator是惰性序列,因此通过list()函数把整个序列都计算出来并返回一个list
reduce(f,list) 稍微复杂一点,先取够f需要的参数,然后然函数调用的结果作为第一个参数,继续在list中取够它所需要的参数,比如:
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
>>> reduce(fn, [1, 3, 5, 7, 9])
13579
filter(f,list),f作为筛选条件,将list中符合条件的筛选出来 。它也是一个迭代器,
惰性序列,需要list()获得结果
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
sorted() 函数也是高阶函数,它可以接收一个key函数 实现自定义的绝对值大小排序
15 函数作为返回值
在函数A中定义了函数b,且函数b引用了外部函数a的参数和局部变量,当函数a返回函数b时,相关参数和变量都保存在返回的函数中,这种称为闭包
16 匿名函数
只能有一个表达式,不能写return,好处:因为没名字,不用担心命名冲突
17 装饰器
在代码运行期间动态增加功能的方式,本质上是一以函数为参数,并返回函数的高阶函数。如果decorator本身需要传入参数,那就需要写一个返回decorator的高阶函数,写出来更复杂
18 偏函数
使用functools。partial作用就是,把一个函数的某些参数固定住,返回一个新的函数
19 模块
python引入了目录来组织模块,称为package。
自己创建模块时要注意命名,不要和系统的冲突,否则无法导入
作用域
_a表示私有变量实际不是
__a私有变量解释器会改名字使外部不可直接访问
__a__特殊变量
安装第三方模块,pip3,可以使用anaconda它集成了很多第三方包
默认情况下,python解释器会搜索当前目录,所有已安装的内置模块和第三方模块,
搜索路径放在sys模块的path变量中,如果要自己添加自己的搜索目录,有两种方法
一是直接修改sys.path.append(path)添加要搜索的目录,这种方法在运行时修改,运行结束后失效;二是设置环境变量PYTHONPATH,该环境变量的内容被自动添加到模块的搜索路径中,设置方式和path环境变量类似。
20 面向对象编程OOP
实例的访问限制,外部代码可以自由地修改一个实例的变量,如果要让一个内部变量不被外部访问,可以把变量的名称前加上两个下划线__,则变量就成为一个私有变量,只有内部可以访问,然后如果外部代码要获取其变量代表的属性,那么可以给student类增加get_name和get_score方法,如果要允许外部修改score,则可以给类增加set_score方法。 需要注意的是在python中,以双下划线 开始和双下划线结束的是特殊变量,特殊变量时可以直接访问的,
python中__name__,__score__,不是私有变量,所以不要用__name__,__score__这样的变量名来命名私有变量,_name这类变量,意思请把该变量看做私有的,但是它可以在外部访问
获取对象信息
1)使用type(),它返回对应的class类型。判断一个对象是否是函数可以使用types模块中定义的常量
types.FunctionType,types.BuiltinFunctionType,types.LambdaType
types.GeneratorType
2)使用isinstance(),对于class的继承关系来说,使用type就很不方便,所以使用它
3)使用dir()可以获得对象的使用属性和方法
21面向对象高级编程
1)使用__slot__
为了达到限制属性的目的,可以在定义class的时候,定义一个特殊的__slot_-
变量,来限制class实例能添加的属性,则其他的属性定义会报错,但是这种方法对子类是不起作用的
2)使用@property
参看例程
3)多重继承
4)定制类
__str__ 定义打印字符串
__repr__定义显示字符串
__iter__定义使可以使用for in循环,它返回初始值
__next__定义for in循环中的next值
__getitem__定义使对象可以像list那样由下标取元素
__getattr__定义属性相关内容
__call__定义实例调用
5)使用枚举类
from enum import Enum
Month=Enum('Month',('Jan','Feb',...,‘Dec’))
然后可以直接使用Month。Jan来引用一个常量,或枚举它的所有成员
for name,member in Month.__members__.items():pass
另一种方法是可以从enum中派生类,使用装饰器@unique可以保证唯一性
6)使用元类
type既可以返回一个对象的类型又可以创建新的类型,参考例程
创建新类时,type()依次传入3个参数,1 class的名称 2 继承的父类集合,tuple的单元素写法 3 class的方法与函数绑定
7)使用元类metaclass
22错误和调试
1) 错误处理
try:pass
except as e:pass
else:pass
finally:pass
所有的错误继承自BaseException,except不仅捕获该类型的错误,还把其子类错误一网打尽(参例程)
2)记录错误
内置的logging
import logging
except Exception as e:logging.exception(e)
3) 抛出错误
定义一一个错误的class,然后raise
class FooError(valueError):pass
def foo(s):
if n==0:raise FooError('')
4)调试
使用print()
assert
logging.info(),需要在import logging之后添加一行配logging.basicConfig(level=logging.INFO)
pdb启动python解释器的调试器,可以随时查看运行状态
python -m pdb app.py
以参数-m pdb启动后,pdb定位到下一步要执行的代码上,输入命令1来查看代码,输入命令n可以单步执行代码,输入变量名可以查看变量,输入q结束调试
使用pdb.set_trace()可以设置断点,需要import pdb
使用好的IDE,比如Visual Studio Code,PyCharm,Eclipse+pydev插件
5)单元测试
引入python自带的unitest模块
import unitest
class TestDict(unitest.TestCase):pass
6)文档测试
将测试程序写在'''...'''中,然后执行import doctest;doctest.testmod()
23 IO编程
1)IO编程:
读文件:f=open('...','r');f.read();f.close()
关闭文件:f.close(),由于文件读写时可能产生IOError,一旦出错,后面的f.close()
不会调用,所以可以使用try...finally来实现,或者with open () as f:pass
read()会依次读取文件的全部内容,太占内存,所以使用read(size)or readline() ,to get one line one time,readlines() read all content once and return a list.
写文件:f=open('...','w');f.write();f.close()
w会覆盖已经存在的文件,如果要添加内容,以'a'追加模式
二进制文件打开使用f=open('...','rb)
字符编码:读取非UTF-8的文本文件,需要指定编码方式
f=open('...','r',encoding='gbk',errors='ignore')
2)StringIO在内存中读写str
from io import StringIO
f=StringIO()
f.write('...') 返回字符数
getvalue()方法用于获得写入后的str
要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
s = f.readline()
if s == '':
break
print(s.strip())
StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
3)操作文件和目录
os.name,os.environ,os.environ.get('...')获取某个环境变量的值
把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符,同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:
os.path.splitext()可以直接让你得到文件扩展名,很多时候非常方便:
os.rename(),os.remove('...')
幸运的是shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充。
4)序列化
我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,
在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
pickle模块来实现序列化。pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object:
f = open('dump.txt', 'wb')
pickle.dump(d, f)
f.close()
当我们要把对象从磁盘读到内存时,可以先把内容读到一个bytes,然后用pickle.loads()
方法反序列化出对象,也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。我们打开另一个Python命令行来反序列化刚才保存的对象:
24进程和线程
进程
线程
25网络编程
IP IPv4,IPv6
TCP可靠连接,可靠数据流传输,有效流控制,全双工,多路复用,包头大,冗余性不好
UDP不需要建立连接, 不稳定的服务,包头小,开销小
26web开发
web应用中,浏览器和服务器之间的传输协议是http
27异步IO
协程:
asyncio:
async/await
aiohttp
28实战