摘要
本文部分内容来源于网络,个人收集整理,请勿传播
python能做什么
- web开发
1 | django |
- 网络编程
1 | twisted |
- 科学计算
1 | numpy |
- gui图形开发
1 | wxpython |
- 运维自动化
1 | openstack |
其他
- 枚举 enumerate
- 元组是只读列表
- 字符串不能修改,只能给变量重新赋值
- eval(),字符串转字典
- functools.wraps使装饰器不会对原本的函数造成影响
- 高阶函数:传入参数有函数,返回的时候用到这个传入的函数参数
Python基础
解释器
执行 python /home/dev/hello.py
时,明确的指出 hello.py 脚本由 python 解释器来执行。
如果想要类似于执行shell脚本一样执行python脚本,例: ./hello.py
,那么就需要在 hello.py
文件的头部指定解释器,如下:
1 | #!/usr/bin/env python |
如此一来,执行: ./hello.py
即可。
ps:执行前需给予 hello.py
执行权限,chmod 755 hello.py
内容编码
python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill)
ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,其最多只能用 8 位来表示(一个字节),即:2**8 = 256
,所以,ASCII码最多只能表示 256 个符号。
显然ASCII码无法将世界上的各种文字和符号全部表示,所以,就需要新出一种可以代表所有字符和符号的编码,即:Unicode
Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,规定虽有的字符和符号最少由 16 位来表示(2个字节),即:2 **16 = 65536,
注:此处说的的是最少2个字节,可能更多
UTF-8,是对Unicode编码的压缩和优化,他不再使用最少使用2个字节,而是将所有的字符和符号进行分类:ascii码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存…
所以,python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill),如果是如下代码的话:
报错:ascii码无法表示中文
1 | #!/usr/bin/env python |
改正:应该显示的告诉python解释器,用什么编码来执行源代码,即:
1 | #!/usr/bin/env python |
字符编码
python2
- py2里默认编码是ascii
- 文件开头那个编码声明是告诉解释这个代码的程序 以什么编码格式 把这段代码读入到内存,因为到了内存里,这段代码其实是以bytes二进制格式存的,不过即使是2进制流,也可以按不同的编码格式转成2进制流,你懂么?
- 如果在文件头声明了
#_*_coding:utf-8_*_
就可以写中文了, 不声明的话,python在处理这段代码时按ascii,显然会出错, 加了这个声明后,里面的代码就全是utf-8格式了 - 在有
#_*_coding:utf-8_*_
的情况下,你在声明变量如果写成name=u”大保健”,那这个字符就是unicode格式,不加这个u,那你声明的字符串就是utf-8格式 utf-8 to gbk
怎么转,utf8先decode成unicode,再encode成gbk
python3
- py3里默认文件编码就是utf-8,所以可以直接写中文,也不需要文件头声明编码了,干的漂亮
- 你声明的变量默认是unicode编码,不是utf-8, 因为默认即是unicode了(不像在py2里,你想直接声明成unicode还得在变量前加个u), 此时你想转成gbk的话,直接your_str.encode(“gbk”)即可以
- 但py3里,你在your_str.encode(“gbk”)时,感觉好像还加了一个动作,就是就是encode的数据变成了bytes里,我擦,这是怎么个情况,因为在py3里,str and bytes做了明确的区分,你可以理解为bytes就是2进制流,你会说,我看到的不是010101这样的2进制呀, 那是因为python为了让你能对数据进行操作而在内存级别又帮你做了一层封装,否则让你直接看到一堆2进制,你能看出哪个字符对应哪段2进制么?什么?自己换算,得了吧,你连超过2位数的数字加减运算都费劲,还还是省省心吧。
- 那你说,在py2里好像也有bytes呀,是的,不过py2里的bytes只是对str做了个别名(python2里的str就是bytes, py3里的str是unicode),没有像py3一样给你显示的多出来一层封装,但其实其内部还是封装了的。 这么讲吧, 无论是2还是三, 从硬盘到内存,数据格式都是 010101二进制到–>b’\xe4\xbd\xa0\xe5\xa5\xbd’ bytes类型-->按照指定编码转成你能看懂的文字
编码应用比较多的场景应该是爬虫了,互联网上很多网站用的编码格式很杂,虽然整体趋向都变成utf-8,但现在还是很杂,所以爬网页时就需要你进行各种编码的转换,不过生活正在变美好,期待一个不需要转码的世界。
注释
- 当行注视:# 被注释内容
- 多行注释:””” 被注释内容 “””
执行脚本传入参数
Python有大量的模块,从而使得开发Python程序非常简洁。类库有包括三中:
- Python内部提供的模块
- 业内开源的模块
- 程序员自己开发的模块
Python内部提供一个 sys 的模块,其中的 sys.argv 用来捕获执行执行python脚本时传入的参数
pyc 文件
执行Python代码时,如果导入了其他的 .py 文件,那么,执行过程中会自动生成一个与其同名的 .pyc 文件,该文件就是Python解释器编译之后产生的字节码。
ps:代码经过编译可以产生字节码;字节码通过反编译也可以得到代码。
变量
声明变量
1 | #!/usr/bin/env python |
变量的作用
昵称,其代指内存里某个地址中保存的内容
变量定义的规则
- 变量名只能是 字母、数字或下划线的任意组合
- 变量名的第一个字符不能是数字
- 以下关键字不能声明为变量名
1 | ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield'] |
作用域
对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用。
1 | if 1==1: |
下面的结论对吗?
- 外层变量,可以被内层变量使用
- 内层变量,无法被外层变量使用
三元运算
1 | result = 值1 if 条件 else 值2 |
- 如果条件为真:result = 值1
- 如果条件为假:result = 值2
进制
- 二进制,01
- 八进制,01234567
- 十进制,0123456789
- 十六进制,0123456789ABCDEF
数据类型
数字
1 | 2 是一个整数的例子。 |
int(整型)
- 在32位机器上,整数的位数为32位,取值范围为-231~231-1,即-2147483648~2147483647
- 在64位系统上,整数的位数为64位,取值范围为-263~263-1,即-9223372036854775808~9223372036854775807
long(长整型)
跟C语言不同,Python的长整数没有指定位宽,即:Python没有限制长整数数值的大小,但实际上由于机器内存有限,我们使用的长整数数值不可能无限大。
注意,自从Python2.2起,如果整数发生溢出,Python会自动将整数数据转换为长整数,所以如今在长整数数据后面不加字母L也不会导致严重后果了。
float(浮点型)
浮点数用来处理实数,即带有小数的数字。类似于C语言中的double类型,占8个字节(64位),其中52位表示底,11位表示指数,剩下的一位表示符号。
complex(复数)
复数由实数部分和虚数部分组成,一般形式为x+yj,其中的x是复数的实数部分,y是复数的虚数部分,这里的x和y都是实数。
注:Python中存在小数字池:-5 ~ 257
布尔值
- 真或假
- 1 或 0
字符串
“hello world”
1 | name.capitalize() 首字母大写 |
万恶的字符串拼接:
python中的字符串在C语言中体现为是一个字符数组,每次创建字符串时候需要在内存中开辟一块连续的空,并且一旦需要修改字符串的话,就需要再次开辟空间,万恶的+号每出现一次就会在内从中重新开辟一块空间。
列表
创建列表:
1 | name_list = ['alex', 'seven', 'eric'] |
基本操作:
- 索引
- 切片
- 追加
- 删除
- 长度
- 切片
- 循环
- 包含
元祖
创建元祖:
1 | ages = (11, 22, 33, 44, 55) |
基本操作:
- 索引
- 切片
- 循环
- 长度
- 包含
字典(无序)
创建字典:
1 | person = {"name": "mr.wu", 'age': 18} |
常用操作:
- 索引
- 新增
- 删除
- 键、值、键值对
- 循环
- 长度
PS:循环,range,continue 和 break
运算
http://www.runoob.com/python/python-operators.html
集合
- 去重
- 关系测试(交集、差集、并集)
- 无序
关系测试
1 | set(list_1) |
collection
计数器(counter)
Counter是对字典类型的补充,用于追踪值的出现次数。
ps:具备字典的所有功能 + 自己的功能
1 | c = Counter('abcdeabcdabcaba') |
- sum(c.values()) # 所有计数的总数
- c.clear() # 重置Counter对象,注意不是删除
- list(c) # 将c中的键转为列表
- set(c) # 将c中的键转为set
- dict(c) # 将c中的键值对转为字典
- c.items() # 转为(elem, cnt)格式的列表
- Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
- c.most_common()[:-n:-1] # 取出计数最少的n-1个元素
- c += Counter() # 移除0和负值
有序字典(orderedDict )
orderdDict是对字典类型的补充,他记住了字典元素添加的顺序
默认字典(defaultdict)
可以设置一个key的默认值,能够在字典第一次对某个不存在key操作时给这个key赋予一个空的默认值然后再操作。
defaultdict是对字典的类型的补充,他默认给字典的值设置了一个类型。
可命名元组(namedtuple)
根据nametuple可以创建一个包含tuple所有功能以及其他功能的类型。
1 | import collections |
双向队列(deque)
一个线程安全的双向队列
既然有双向队列,也有单项队列(先进先出 FIFO )(Queue)
文件操作
1 | # 打印指针位置 |
操作文件时,一般需要经历如下步骤:
- 打开文件
- 操作文件
打开文件
文件句柄 = file(‘文件路径’, ‘模式’)
注:python中打开文件有两种方式,即:open(…) 和 file(…) ,本质上前者在内部会调用后者来进行文件操作,推荐使用 open。
打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。
打开文件的模式有:
- r,只读模式(默认)。
- w,只写模式。【不可读;不存在则创建;存在则删除内容;】
- a,追加模式。【可读; 不存在则创建;存在则只追加内容;】
- “+” 表示可以同时读写某个文件
- r+,可读写文件。【可读;可写;可追加】
- w+,写读
- a+,同a
- “U”表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
- rU
- r+U
- “b”表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
- rb
- wb
- ab
with
为了避免打开文件后忘记关闭,可以通过管理上下文,即:
1 | with open('log','r') as f: |
如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源。
在Python 2.7 后,with又支持同时对多个文件的上下文进行管理,即:
1 | with open('log1') as obj1, open('log2') as obj2: |
函数
- 面向过程
- 面向函数
- 函数式编程
- 面向对象
递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
- 在过程或函数里调用自身
- 一定要有明确的结束条件,称为递归出口
- 每深入一层,处理的数据规模要比上次有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
1 | def calc(n): |
二分查找
1 | data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] |
lambda匿名函数
匿名函数就是不需要显式的指定函数
对于简单的函数,也存在一种简便的表示方式,即:lambda表达式
高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
闭包
- 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包
- 内函数引用了外函数的局部变量,所以外函数的局部变量没有及时释放,消耗内存
1 | def outer(a): |
- 装饰器
- 面向对象:闭包也是实现面向对象的方法之一
- 实现单利模式
装饰器
- 本质是函数
- 装饰其他函数、给函数添加功能,使用装饰器可以在函数执行前和执行后添加相应操作
- 函数即变量
- 不改变原函数代码,不改变原函数调用方式,不改变原函数执行结果
- 高阶函数
- 把一个函数名当做实参传给另一个函数
- 返回值中包含函数名
- 嵌套函数
- 语法糖
- 三层装饰器
1 | def login(auth_type): #把要执行的模块从这里传进来 |
高阶函数
1 | def add(x,y,f): |
迭代器、生成器
生成器generator
定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器
生成器内部基于yield创建,即:对于生成器只有使用时才创建,从而不避免内存浪费
一边循环一边计算的机制,称为生成器:generator
- 列表生成式
- [ i*2 for i in range(10) ]
- [i for i in range(10) if i==9]
- 生成器 generator
- ( i*2 for i in range(10) )
- 只有在调用时才会生成相应的数据
- 只记录当前位置
- 只有一个next()方法,next() #2.7
- yeild StopIteration
- (生产者,消费者)单线程下的并行效果–协程
- 生成器是迭代器的一种
- range不是生成器 和 xrange 是生成器
- readlines不是生成器 和 xreadlines 是生成器
1 | def con(name): |
斐波拉契数列
1 | def fib(max): |
迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
便于循环比较大的数据集合,节省内存
容器(container)
- assert
- 可迭代对象(iterable)
- 可以直接作用于for循环的对象
- list、tuple、dict、set、str(不是Iterator,不过可以通过iter()函数获得一个Iterator对象)
- generator,包括生成器和带yield的generator function
- from collections import Iterable;isinstance([],Iterable)
- 生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
- 迭代器(iterator)
- 可以被next()函数调用并不断返回下一个值的对象
- from collections import Iterator;isinstance([], Iterator)
- 把list、dict、str等Iterable变成Iterator可以使用iter()函数:
生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
1 | # 生成无限序列: |
Fib既是一个可迭代对象(因为它实现了iter方法),又是一个迭代器(因为实现了next方法)。实例变量prev和curr用户维护迭代器内部的状态。每次调用next()方法的时候做两件事:
为下一次调用next()方法修改状态
- 为当前这次调用生成返回结果
- 迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。
深浅拷贝
为什么要拷贝?
1 | 当进行修改时,想要保留原来的数据和修改后的数据 |
数字字符串 和 集合 在修改时的差异? (深浅拷贝不同的终极原因)
1 | 在修改数据时: |
对于集合,如何保留其修改前和修改后的数据?
1 | 在内存中拷贝一份 |
对于集合,如何拷贝其n层元素同时拷贝?
1 | 深拷贝 |
内置函数
- all() 全部为真才为真
- any() 有真就为真
- bin() 转二进制 hex() 16进制 oct() 8进制
- bool()
- chr(98) ord(‘c’)
- classmethod() 类方法
- compile() 编译代码
- dir()
- divmod() 地板除
- enumerate()
- eval()
- exec()
- filter() filter(lambda a:a==9,[i for i in range(10)]) 对于序列中的元素进行筛选,最终获取符合条件的序列
1 | li = [11, 22, 33] |
- map() 遍历序列,对序列中每个元素进行操作,最终获取新的序列。
1 | li = [11, 22, 33] |
- reduce() functools.reduce() 函数会对参数序列中元素进行累积
1 | li = [11, 22, 33] |
- format() 格式化字符串
- globals() 当前所有全局变量 locals() 局部变量
- hash()
- help()
- max() min() sum()
- next()
- round() 保留小数
- slice() 切片
- sorted() 排序
- type()
- vars()
- zip()
- import()
模块、包
定义
- 本质就是一个.py的python文件
- 用来从逻辑上组织python代码
- 变量、函数、类、逻辑
- 实现一个功能
- 包:用来从逻辑上组织模块,本质就是一个目录(init.py)
导入方法
- import module_name
- import module_name1,module_name2
- from module_name import *
- from module_name import func,func1
- from module_name import func as func_module
import本质
- 导入模块的本质就是把python文件解释一次
- 导入包的本质就是执行包下的init.py文件
- 路径搜索(sys.path)
- 搜索路径
如果sys.path路径列表没有你想要的路径,可以通过 sys.path.append(‘路径’) 添加。
1 | import sys |
导入优化
- from module_name import func,func1
模块的分类
- 标准库
- 开源模块–第三方模块