建议刚开始学习直接使用ANACONDA
++https://www.anaconda.com/download/++
配置python环境变量 https://docs.python.org/3.6/using/cmdline.html#envvar-PYTHONMALLOC
++==Python PEP8导包顺序==++
- ==Python标准库==
- ==Python第三方模块==
- ==应用程序自定义模块 然后使用一个空行分割这三类模块的导入语句,这将确保模块使用固定的习惯导入, 有助于减少每个模块需要的 import 语句数目。==
- ==python中0,"",None都等于False==
生成随机字符,可用于加密key 密钥
import os,base64
base64.b64encode(os.urandom(20))
# python的包命令
pip install xxx
pip uninstall xxx
pip install upgrade xxx
# anaconda提供包命令
conda install xxx
conda uninstall xxx
conda update xxx
Python头信息
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: YourName
python2设置编码格式
# 设置解释器编码格式
import sys
reload(sys)
sys.setdefaultencoding('utf8')
# python对接oracle时设置系统变量
os.environ["NLS_LANG"]="SIMPLIFIED CHINESE_CHINA.UTF8"
安装python的虚拟环境
安装virtualenvwrapper
使得virtualenv变得更好用,所以我们一起安装了
# 安装:
(sudo) pip install virtualenv virtualenvwrapper
# 修改~/.bash_profile或其它环境变量相关文件(如 .bashrc 或用 ZSH 之后的 .zshrc),添加以下语句
export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/workspace
source /usr/local/bin/virtualenvwrapper.sh
# 修改后使之立即生效(也可以重启终端使之生效):
source ~/.bash_profile
关 | 键 | 字 |
---|---|---|
and | exec | not |
assert | finally | or |
break | for | pass |
class | from | |
continue | global | raise |
def | if | return |
del | import | try |
elif | in | while |
else | is | with |
except | lambda | yield |
pip常用命令
pip freeze or pip list 列出已安装的包
pip freeze > <目录>/requirements.txt 导出requirements.txt
pip install <包名> 或 pip install -r requirements.txt 在线安装
pip install --no-index -f=<目录>/ <包名> 安装本地安装包
pip uninstall <包名> 或 pip uninstall -r requirements.txt 卸载包
pip install -U <包名> 或:pip install <包名> --upgrade 升级包
pip install -U pip 升级pip
pip show -f <包名> 显示包所在的目录
pip search <搜索关键字> 搜索包
pip list -o 查询可升级的包
pip install <包名> -d <目录> 或 pip install -d <目录> -r requirements.txt 下载包而不安装
pip wheel <包名> 打包
更换国内pypi镜像 国内pypi镜像 阿里:https://mirrors.aliyun.com/pypi/simple 豆瓣:http://pypi.douban.com/simple 中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/
指定单次安装源
pip install <包名> -i http://pypi.v2ex.com/simple 指定全局安装源
在unix和macos,配置文件为:$HOME/.pip/pip.conf 在windows上,配置文件为:%HOME%\pip\pip.ini
[global] timeout = 6000 index-url = http://pypi.douban.com/simple
---
### Python核心
> python中的数据类型有:
- Number(数字)
- - int(有符号的整形)
- - float(浮点型)
- - complex(复数)
- Bool(布尔)
- - True
- - Flase
- String(字符串)
- List(列表)
- Tuple(元组)
- Dictionary(字典)
小整数池范围-5~256
> 知道驼峰命名法和关键字命名范围
> 查看关键字可以使用:
```python
import keyword
keyword.kwlist
格式化输出有:
占位符 | 输出值 |
---|---|
%c | 字符 |
%s | 通过str() 字符串转换来格式化 |
%i | 有符号十进制整数 |
%d | 有符号十进制整数 |
%u | 无符号十进制整数 |
%o | 八进制整数 |
%x | 十六进制整数(小写字母) |
%X | 十六进制整数(大写字母) |
%e | 科学计数法(小写'e') |
%E | 科学计数法(大写“E”) |
%f | 浮点数 |
%g | %f和%e 的简写 |
%G | %f和%E的简写 |
> 常用的有%s、%f、%d |
还有一种自动格式化填充format()
print('{}'.format('我们'))
"numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
在Python3中输出是print(),Python2中是print
在Python3中输入使用input(),Python2中使用raw_input()
算数运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 两个对象相加 a + b 输出结果 30 |
- | 减 | 得到负数或是一个数减去另一个数 a - b 输出结果 -10 |
* | 乘 | 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200 |
/ | 除 | b / a 输出结果 2 |
// | 取整除 | 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 |
% | 取余 | 返回除法的余数 b % a 输出结果 0 |
** | 指数 | a**b 为10的20次方, 输出结果 100000000000000000000 |
赋值运算符 | 描述 | 实例 |
---|---|---|
= | 赋值运算符 | 把=号右边的结果给左边的变量 num = 1 + 2 * 3,结果num的值为7 |
复合赋值运算符 | 描述 | 实例 |
---|---|---|
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c *= a 等效于 c = c * a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
常用的数据类型转换
函数 | 说明 |
---|---|
int(x [,base ]) | 将x转换为一个整数 |
float(x ) | 将x转换为一个浮点数 |
complex(real [,imag ]) | 创建一个复数,real为实部,imag为虚部 |
str(x ) | 将对象 x 转换为字符串 |
repr(x ) | 将对象 x 转换为表达式字符串 |
eval(str ) | 用来计算在字符串中的有效Python表达式,并返回一个对象 |
tuple(s ) | 将序列 s 转换为一个元组 |
list(s ) | 将序列 s 转换为一个列表 |
chr(x ) | 将一个整数转换为一个Unicode字符 |
ord(x ) | 将一个字符转换为它的整数值 |
hex(x ) | 将一个整数转换为一个十六进制字符串 |
oct(x ) | 将一个整数转换为一个八进制字符串 |
bin(x ) | 将一个整数转换为一个二进制字符串 |
判断语句
if 条件:
todo
elif 条件:
todo
else:
todo
循环语句
while 条件:
todoing
for i in 可迭代对象:
i
break在循环中满足条件退出循环 continue满足条件跳过这一次循环,继续后面的循环 如果什么都不做可以使用pass来占位
==字符串、元组、列表都可以做切片==; ==字符串、元组、列表、字典都是可迭代对象==
字符串常见操作
string = ' hello world hello everybody '
# find,如果查找的字符串存在返回索引,否则返回-1
string.find(str,start=0,end=len(string)
# index,跟find方法一样如果没找到字符串则会抛出一个异常
string.index(str,start=0,end=len(string)
# count,在start与end之间,str出现的次数
string.count(str,start=0,end=len(string)
# replace,把str1替换成str2,如果指定count,则替换不会超过count次
string.replace(str1,str2,count)
# split,指定分割的符号,如果指定最大分割值,则仅分割最大值个数的字符串(0是不分割,无参数则全分割)
string.split(str='',maxsplit)
# capitalize首字母大写
string.capitalize()
# title,把字符串的每个单词首字母大写
string.title()
# startswith,检查字符串是否是以指定字符串开头, 是则返回 True,否则返回 False
string.startswith(hello)
# endswith,检查字符串是否以指定字符串结束,如果是返回True,否则返回 False
string.endswith(obj)
# lower,转换 mystr 中所有大写字符为小写
string.lower()
# upper,转换 mystr 中的小写字母为大写
string.upper()
# ljust,返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.ljust(width)
# rjust,返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
string.rjust(width)
# center,返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string..center(width)
# lstrip,删除 mystr 左边的空白字符
string.lstrip()
# rstrip,删除 mystr 字符串末尾的空白字符
string.rstrip()
# strip,删除mystr字符串两端的空白字符
string.strip()
# rfind,类似于 find()函数,不过是从右边开始查找
string.rfind(str, start=0,end=len(mystr))
# rindex,类似于 index(),不过是从右边开始.
string.rindex( str, start=0,end=len(mystr))
# partition,把mystr以str分割成三部分,str前,str和str后
string.partition(str)
# rpartition,类似于 partition()函数,不过是从右边开始
string.rpartition(str)
# splitlines,按照行分隔,返回一个包含各行作为元素的列表
string.splitlines()
# isalpha,如果 mystr 所有字符都是字母 则返回 True,否则返回 False
string.isaplha()
# isdigit,如果 mystr 只包含数字则返回 True 否则返回 False
string.isdigit()
# isalnum,如果 mystr 所有字符都是字母或数字则返回 True,否则返回 False
string.isalnum()
# isspace,如果 mystr 中只包含空格,则返回 True,否则返回 False
string.isspace()
# join,mystr 中每个元素后面插入str,构造出一个新的字符串
string.join(str)
列表
list1 = [1,2,3]
list2 = [7,8,9]
# append,向列表追加元素
list1.append(4)
# extend,将另一个集合中的元素逐一添加到列表中
list1.extend(list2)
# insert,(index, object) 在指定位置index前插入元素object
list1.insert(0,1)
# 修改元素可以通过指定下标重新赋值
list1[0]=5
# in, not in:
## in(存在),如果存在那么结果为true,否则为false
## not in(不存在),如果不存在那么结果为true,否则false
2 in list1
1 not in list1
# index, count:用法与字符串相同
list1.index(2)
list1.count(1)
# del, pop, remove:删除元素
## del:根据下标进行删除
## pop:默认弹出最后一个元素,也可以指定下标
## remove:根据元素的值进行删除
del list1[0]
list1.pop()
list1.remove(2)
# sort,排序,可以添加reverse=True参数设置倒序
list1.sort()
# reverse只逆置顺序,不排序
list1.reverse()
# 列表推导式
[i for i in range(30) if i % 3 is 0]
# 生成器
(i for i in range(30) if i % 3 is 0)
元组
# Python的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。
# 访问元素,可以拆包或者取下标
tuple = (1,2,3)
tuple[1]
x,y,z = tuple
# 元组的内置函数count, index
# index和count与字符串和列表中的用法相同
tuple.count(1)
tuple.index(1)
字典
dict = {'id':1,'name':'张三'}
# 修改元素:字典的每个元素中的数据是可以修改的,只要通过key找到,即可修改
dict['name']='李四'
# 添加元素:**访问不存在的元素会抛出异常,如果在使用 变量名['键'] = 数据 时,这个“键”在字典中,不存在,那么就会新增这个元素**
dict['age']=18
# update,添加多个元素
dict.update({'addr':'beijing','sex':'nan'})
# fromkeys,根据传入的列表和值生成多个元素,所有元素的值都一样
b=[1,2,3,4]
a={}
a=a.fromkeys(b,'666')
# setdefault(key,value),如果key存在获取元素,如果不存在则添加元素
dict.setdefault('id')
dict.setdefault('addr','东北')
# get,获取指定key的value,如果key不存在返回None
dict.get('学籍')
# 删除元素:
## del:指定key删除元素
## clear():删除所有元素
del dict['age']
dict.clear()
# 弹出元素:
## pop:指定key弹出元素
## popitem:弹出最后一个元素
dict.pop('id')
dict.popitem()
# len,测量字典中,键值对的个数
len(dict)
# keys,返回一个包含字典所有KEY的列表
dict.keys()
# values,返回一个包含字典所有value的列表
dict.values()
# items,返回一个包含所有(键,值)元祖的列表
dict.items()
# enumerate()枚举,传入字典返回(key,value),传入字典返回(index,value)
# python2:has_key,dict.has_key(key)如果key在字典中,返回True,否则返回False
集合
set={1,2,3}
# add,添加元素
set.add(4)
# update,添加多个元素
set.update({4,5,6})
# pop,弹出第一个元素
set.pop()
# remove,删除指定元素,如果元素不存在抛出异常
set.remove(2)
# discard,删除指定元素,元素不存在返回None
set.discard
---
set1={1,2,3}
set2={2,3,4}
# &,交集
set1 & set2
# |,并集
set1 | set2
# ^,对称差集
set1 ^ set2
# -,差集
set1 - set2
公共方法
运算符 | Python 表达式 | 结果 | 描述 | 支持的数据类型 |
---|---|---|---|---|
+ | [1, 2] + [3, 4] | [1, 2, 3, 4] | 合并 | 字符串、列表、元组 |
* | ['Hi!'] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 复制 | 字符串、列表、元组 |
in | 3 in (1, 2, 3) | True | 元素是否存在 | 字符串、列表、元组、字典 |
not in | 4 not in (1, 2, 3) | True | 元素是否不存在 | 字符串、列表、元组、字典 |
python内置函数
方法 | 描述 |
---|---|
cmp(item1, item2) | python2 中cmp(item1, item2)比较值个大小 item1大返回1,item1小返回-1,相等返回0 |
len(item) | 计算容器中元素个数 |
max(item) | 返回容器中元素最大值 |
min(item) | 返回容器中元素最小值 |
del(item) | 删除变量 |
type(item) | 返回对象类型 |
isinstance(item,type) | 传入对象和类型返回True或False |
reversed(item) | 返回倒置的对象需要转换list或其他 |
enumerate(item) | 返回一个元组 |
zip(list,list) | 返回新的列表,需要传入的列表每个元素一一对应 |
hash(obj) | 返回哈希值 |
dict(item) | 创建字典或转换成字典 |
list(item) | 创建列表或转换成列表 |
tuple(tiem) | 转换成元组 |
dir(obj) | 查看函数有哪些方法 |
divmod(datasize, limte) | 全部数据,每页几条数据。返回元组(总页数, 剩余条数) |
```python | |
# python3中代替cmp的函数 | |
import operator | |
operator.eq(a,b) # 是否相等 | |
operator.lt(a,b) # a 小于 b | |
operator.gt(a,b) # a 大于 b | |
operator.le(a,b) # a 小等于 b | |
operator.ge(a,b) # a 大等于 b | |
``` |
==函数内部定义的变量属于局部变量,在函数外定义的变量属于全局变量,在函数内优先调用局部变量,如果想从函数内部修改全局变量需要使用global关键字声明==
# 递归函数
def func(num):
if num == 1:
return num
return func(num-1) + num
# 匿名函数
(lambda x:x+1)(2)
list1 = [{'a':1},{'a':2},{'a':3}]
list1.sort(key=lamdba x:x['a'])
抽象基类
ABC,Abstract Base Class(抽象基类),主要定义了基本类和最基本的抽象方法,可以为子类定义共有的API,不需要具体实现。相当于是Java中的接口或者是抽象类。 抽象基类可以不实现具体的方法(当然也可以实现,只不过子类如果想调用抽象基类中定义的方法需要使用super())而是将其留给派生类实现。
抽象基类提供了逻辑和实现解耦的能力,即在不同的模块中通过抽象基类来调用,可以用最精简的方式展示出代码之间的逻辑关系,让模块之间的依赖清晰简单。同时,一个抽象类可以有多个实现,让系统的运转更加灵活。而针对抽象类的编程,让每个人可以关注当前抽象类,只关注其方法和描述,而不需要考虑过多的其他逻辑,这对协同开发有很大意义。极简版的抽象类实现,也让代码可读性更高。
抽象基类的使用:
1:直接继承
直接继承抽象基类的子类就没有这么灵活,抽象基类中可以声明”抽象方法“和“抽象属性”,只有完全覆写(实现)了抽象基类中的“抽象”内容后,才能被实例化,而虚拟子类则不受此影响。
2:虚拟子类
将其他的类”注册“到抽象基类下当虚拟子类(调用register方法),虚拟子类的好处是你实现的第三方子类不需要直接继承自基类,可以实现抽象基类中的部分API接口,也可以根本不实现,但是issubclass(), issubinstance()进行判断时仍然返回真值。
Python 对于ABC的支持模块是abc模块,定义了一个特殊的metaclass:ABCMeta 还有一些装饰器:@abstractmethod 和 @abstarctproperty 。abc.ABCMeta 用于在Python程序中创建抽象基类。而抽象基类如果想要声明“抽象方法”,可以使用 @abstractmethod ,如果想声明“抽象属性”,可以使用 @abstractproperty 。
为了解决Python2&3的兼容问题,需要引入six模块,该模块中有一个针对类的装饰器 @six.add_metaclass(MetaClass) 可以为两个版本的Python类方便地添加metaclass
通用做法。
@six.add_metaclass(MetaClass) >的作用是在不同版本的Python之间提供一个优雅的声明类的metaclass的手段,事实上不用它也可以,只是使用了它代码更为整洁明了。
import six
@six.add_metaclass(Meta)
class MyClass(object):
pass
在Python 3 等价于
import six
class MyClass(object, metaclass = Meta):
pass
在Python 2.x (x >= 6)中等价于
import six
class MyClass(object):
__metaclass__ = Meta
pass
或者直接调用装饰器, 这里也能看出来装饰器就是个方法包装而已。
import six
class MyClass(object):
pass
MyClass = six.add_metaclass(Meta)(MyClass)
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class BaseClass(object):
@abc.abstractmethod
def func_a(self, data):
"""
an abstract method need to be implemented
"""
@abc.abstractmethod
def func_b(self, data):
"""
another abstract method need to be implemented
"""
class SubclassImpl(BaseClass):
def func_a(self, data):
print("Overriding func_a, " + str(data))
@staticmethod
def func_d(self, data):
print(type(self) + str(data))
class RegisteredImpl(object):
@staticmethod
def func_c(data):
print("Method in third-party class, " + str(data))
BaseClass.register(RegisteredImpl)
if __name__ == '__main__':
for subclass in BaseClass.__subclasses__():
print("subclass of BaseClass: " + subclass.__name__)
print("subclass do not contains RegisteredImpl")
print("-----------------------------------------------")
print("RegisteredImpl is subclass: " + str(issubclass(RegisteredImpl, BaseClass)))
print("RegisteredImpl object is instance: " + str(isinstance(RegisteredImpl(), BaseClass)))
print("SubclassImpl is subclass: " + str(issubclass(SubclassImpl, BaseClass)))
print("-----------------------------------------------")
obj1 = RegisteredImpl()
obj1.func_c("RegisteredImpl new object OK!")
print("-----------------------------------------------")
obj2 = SubclassImpl() #由于没有实例化所有的方法,所以这里会报错 Can't instantiate abstract class SubclassImpl with abstract methods func_b
obj2.func_a("It's right!")
结果如下:
subclass of BaseClass: SubclassImpl
subclass do not contains RegisteredImpl
-----------------------------------------------
RegisteredImpl is subclass: True
RegisteredImpl object is instance: True
SubclassImpl is subclass: True
-----------------------------------------------
Method in third-party class, RegisteredImpl new object OK!
-----------------------------------------------
Traceback (most recent call last):
File "/Users/wangqi/Git/Python/scrapy_crawler_learn/test/ABCTest.py", line 51, in <module>
obj2 = SubclassImpl() #由于没有实例化所有的方法,所以这里会报错 Can't instantiate abstract class SubclassImpl with abstract methods func_b
TypeError: Can't instantiate abstract class SubclassImpl with abstract methods func_b
三元操作符
x if x < y else y
位运算
按位与( bitwise and of x and y )
- & 举例: 5&3 = 1 解释: 101 11 相同位仅为个位1 ,故结果为 1
按位或( bitwise or of x and y )
- | 举例: 5|3 = 7 解释: 101 11 出现1的位是 1 1 1,故结果为 111
按位异或 ( bitwise exclusive or of x and y )
- ^ 举例: 5^3 = 6 解释: 101 11 对位相加(不进位)是 1 1 0,故结果为 110
按位反转 (the bits of x inverted )
- ~ 举例:
5 = -6 解释: 将二进制数+1之后乘以-1,即x = -(x+1),-(101 + 1) = -110
- ~ 举例:
按位反转 (the bits of x inverted )
- ~ 举例:
5 = -6 解释: 将二进制数+1之后乘以-1,即x = -(x+1),-(101 + 1) = -110
- ~ 举例:
按位左移 ( x shifted left by n bits )
- << 举例: 5<<2 = 20 解释:101 向左移动2位得到 10100 ,即右面多出2位用0补
按位右移 ( x shifted right by n bits )
举例: 5>>2 = 1 解释:101 向右移动2位得到 1,即去掉右面的2位
文件操作
# 创建文件对象open
file = open(name,'w')
# 文件读操作
file.read(num) # 读取所有字节,参数是字节
file.readline(num) # 只读取一行,参数可以指定字节
with open("filename") as fh:
line = fh.readline()
while line:
print(line.strip())
line = fh.readline()
file.readlines() # 读取所有行,返回列表
# 文件写操作
file.write(str) # 传入字符串写入文件
file.writelines(iter) # 传入可迭代对象写入文件
# 关闭文件操作
file.close()
# 文件其他操作
file.fileno() # 文件描述符
file.flush() # 刷新文件的内部缓冲区
file.seek(offset,from)
# 第一个参数,代表需要移动偏移的字节数。
# 第二个参数,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
file.tell() # 查看当前位置
file.closed # 查看文件是否关闭,没关闭返回False
file.encoding # 查看文件编码格式
file.mode # 查看文件操作模式
file.name # 查看文件名
自定义上下文管理器
class Query(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('Begin')
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print('Error')
else:
print('End')
def query(self):
print('Query info about %s...' % self.name)
with Query('Bob') as q:
q.query()
# 还有另一种更简便的方法
from contextlib import contextmanager
class Query(object):
def __init__(self, name):
self.name = name
def query(self):
print('Query info about %s...' % self.name)
@contextmanager
def create_query(name):
print('Begin')
q = Query(name)
yield q
print('End')
@closing
# 如果一个对象没有实现上下文,我们就不能把它用于with语句。这个时候,可以用closing()来把该对象变为上下文对象。例如,用with语句使用urlopen():
from contextlib import closing
from urllib.request import urlopen
with closing(urlopen('https://www.python.org')) as page:
for line in page:
print(line)
# 它的作用就是把任意对象变为上下文对象,并支持with语句。
访问模式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
import os
# os模块提供的一些分隔符
os.linesep
'\r\n'
os.sep
'\\'
os.pathsep
';'
os.curdir
'.'
os.pardir
'..'
常用os模块函数
函数 | 描述 |
---|---|
name | 获取系统类型(如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。) |
environ | 查看操作系统中定义的环境变量 |
environ.get('key') | 获取某个环境变量的值 |
rename(file,newname) | 文件重命名 |
remove(file) | 删除文件 |
mkdir(dir) | 创建文件夹 |
makedirs() | 创建多层目录 |
getcwd() | 获取当前目录 |
chdir("../") | 改变默认目录 |
listdir("./") | 获取目录列表 |
rmdir(dir) | 删除文件夹 |
removedir() | 删除多层目录 |
chmod() | 改变权限 |
access() | 查看权限 |
open() | 打开文件 |
read() | 读 |
write() | 写 |
常用os.path模块函数
函数 | 描述 |
---|---|
abspath('.') | 查看当前目录的绝对路径 |
basename() | 去掉目录路径,返回文件名 |
dirname() | 去掉文件名,返回路径 |
join() | 将分离的各部分组合成一个路径名 |
split() | 将完整的路径名分割成路径和文件名 |
getatime() | 返回最新的访问时间 |
getctime() | 返回文件创建时间 |
getmtime() | 返回文件修改时间 |
getsize() | 返回文件字节大小 |
exists() | 判断文件或目录是否存在 |
isabs() | 判断是否是绝对路径 |
isdir() | 判断是否是目录 |
isfile() | 判断是否是文件 |
splitext() | (返回文件名,文件后缀) |
当无法导入包时使用 os.path.abspath(os.path.join(os.getcwd(),".."))
==python提供了pickle(pickle.dumps(obj)序列化对象成bytes数据、pickle.loads(strobj)将序列化对象转换成python对象)、cpickle和shelve模块可以将python对象以二进制直接保存到文件里,而不需要转换成字符串==
sys常用方法
函数 | 描述 |
---|---|
sys.argv | 命令行参数List,第一个元素是程序本身路径 |
sys.modules.keys() | 返回所有已经导入的模块列表 |
sys.exc_info() | 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息 |
sys.exit(n) | 退出程序,正常退出时exit(0),有错误退出exit(1) |
sys.hexversion | 获取Python解释程序的版本值,16进制格式如:0x020403F0 |
sys.version | 获取Python解释程序的版本信息 |
sys.maxint | 最大的Int值 |
sys.maxunicode | 最大的Unicode值 |
sys.modules | 返回系统导入的模块字段,key是模块名,value是模块 |
sys.path | 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 |
sys.platform | 返回操作系统平台名称 |
sys.stdout | 标准输出 |
sys.stdin | 标准输入 |
sys.stderr | 错误输出 |
sys.exc_clear() | 用来清除当前线程所出现的当前的或最近的错误信息 |
sys.exec_prefix | 返回平台独立的python文件安装的位置 |
sys.byteorder | 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little' |
sys.copyright | 记录python版权相关的东西 |
sys.api_version | 解释器的C的API版本 |
Python读写ini文件的方法
[ZIP]
EngineVersion=0
DATVersion=5127
FileName=dat-5127.zip
FilePath=/pub/antivirus/datfiles/4.x/
FileSize=13481555
Checksum=6037,021E
MD5=aaeb519d3f276b810d46642d782d8921
获取MD5的值
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.readfp(open('update.ini'))
a = config.get("ZIP","MD5")
print a
设置值
import ConfigParser
config = ConfigParser.ConfigParser()
# set a number of parameters
config.add_section("book")
config.set("book", "title", "the python standard library")
config.set("book", "author", "fredrik lundh")
config.add_section("ematter")
config.set("ematter", "pages", 250)
# write to file
config.write(open('1.ini', "w"))
修改(添加)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('1.ini')
a = config.add_section("md5")
config.set("md5", "value", "1234")
config.write(open('1.ini', "r+")) #可以把r+改成其他方式,看看结果:)
修改
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('1.ini')
config.set("md5", "value", "kingsoft") #这样md5就从1234变成kingsoft了
config.write(open('1.ini', "r+"))
shutil标准库
函数名 | 作用 |
---|---|
move(src,dst) | 移动文件,重命名等 |
copytree('src, dst, symlinks=False, ignore=None) | 递归复制 |
rmtree(path, ignore_errors=False, onerror=None) | 递归删除目录树 |
get_archive_formats() | 返回支持的 压缩格式列表, 如 [(name,desc),('tar','uncompressed tar file')] |
make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, dry_run=0, owner=None, group=None, logger=None) | 创建压缩文件(base_name : 压缩包的文件名, 也可以使压缩包的路径. format : 压缩种类,root_dir : 要压缩的文件夹路径, 默认当前目录,owner : 用户, 默认当前用户,group : 组, 默然当前组) |
copy(src, dst) | 复制文件及权限 |
shutil.copyfileobj(fsrc, fdst, length=16384) | 将文件内容拷贝到另一个文件, copy data from file-like object fsrc to file-like object fdst |
copyfile(src, dst) | 拷贝文件, Copy data from src to dst |
copymode(src, dst) | 仅拷贝权限,内容,用户,组不变, Copy mode bits from src to dst |
copystat(src, dst) | 仅拷贝状态信息, Copy all stat info (mode bits, atime, mtime, flags) from src to dst |
copy2('f1.log', 'f2.log') | 拷贝文件和状态信息, Copy data and all stat info |
简单查看系统类型platform
import platform
platform.system()
信号处理模块signal
在signal模块中,主要是使用signal.signal()函数来预设信号处理函数
singnal.signal(signalnum, handler)
其中第一个参数是信号量,第二个参数信号处理函数。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import signal
import time
def signal_handler(signum, frame):
print('Received signal: ', signum)
while True:
signal.signal(signal.SIGHUP, signal_handler) # 1
signal.signal(signal.SIGINT, signal_handler) # 2
signal.signal(signal.SIGQUIT, signal_handler) # 3
signal.signal(signal.SIGALRM, signal_handler) # 14
signal.signal(signal.SIGTERM, signal_handler) # 15
signal.signal(signal.SIGCONT, signal_handler) # 18
while True:
print('waiting')
time.sleep(1)
运行上面的程序
python test.py
然后另外开一个终端,找到对应的进程,并执行下面的kill操作
kill -1 <pid>
kill -2 <pid>
kill -3 <pid>
kill -14 <pid>
kill -15 <pid>
kill -18 <pid>
kill -9 <pid> # 最后杀死进程
此时可以看到test.py的输出,打印的就是具体接收到的信号。
==这里注意一点就是程序中注册了SIGINT信号,所以在运行程序后使用CTRL+C并不能结束进程,而是仍然打印进程接收到的信号。==
signal.alarm()
另外,signal模块提供了一个很有用的函数signal.alarm(),它用于在一定时间后向进程自身发送SIGALRM信号,比如下面的例子设置5秒后向自己发送一个SIGALRM信号。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import signal
import time
def signal_handler(signum, frame):
print('Received signal: ', signum)
while True:
signal.signal(signal.SIGALRM, signal_handler) # 14
signal.alarm(5)
while True:
print('waiting')
time.sleep(1)
关于引用、深浅拷贝
import copy
a = [1, 2, 3, [4, 5]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(7)
a[3].append(6)
print(a)
print(b)
print(c)
print(d)
[1, 2, 3, [4, 5, 6], 7]
[1, 2, 3, [4, 5, 6], 7]
[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5]]
argparse模块
- python标准库模块argparse用于解析命令行参数,编写用户友好的命令行界面,该模块还会自动生成帮助信息,并在所给参数无效时报错。
- https://docs.python.org/3/library/argparse.html
- https://blog.csdn.net/guoyajie1990/article/details/76739977
# 例子
#arg_parse.py
#coding:utf-8
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
将上述代码保存为arg_parse.py,在命令行运行该脚本。使用-h选项可以查看帮助信息
$ python prog.py -h
usage: prog.py [-h] [--sum] N [N ...]
Process some integers.
positional arguments:
N an integer for the accumulator
optional arguments:
-h, --help show this help message and exit
--sum sum the integers (default: find the max)
如果不指定–sum选项,则找出输入参数中的最大值,否则求和。
$ python prog.py 1 2 3 4
4
$ python prog.py 1 2 3 4 --sum
10
logging日志的基本使用
- 日志级别
==级别排序:CRITICAL > ERROR > WARNING > INFO > DEBUG== ==默认级别WARNING==import logging logger = logging.getLogger() ch = logging.StreamHandler() logger.addHandler(ch) logging.debug('debug') logging.info('info') logging.warning('warning') logging.error('error') logging.critical('critical')
- 部分名词解释
- Logging.Formatter:这个类配置了日志的格式,在里面自定义设置日期和时间,输出日志的时候将会按照设置的格式显示内容。
- Logging.Logger:Logger是Logging模块的主体,进行以下三项工作:
- 为程序提供记录日志的接口
- 判断日志所处级别,并判断是否要过滤
- 根据其日志级别将该条日志分发给不同handler
- 常用函数有:
- Logger.setLevel() 设置日志级别
- Logger.addHandler() 和 Logger.removeHandler() 添加和删除一个Handler
- Logger.addFilter() 添加一个Filter,过滤作用
- Logging.Handler:Handler基于日志级别对日志进行分发,如设置为WARNING级别的Handler只会处理WARNING及以上级别的日志。
- 常用函数有:
- setLevel() 设置级别
- setFormatter() 设置Formatter
日志输出-控制台
import logging # 引入logging模块 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') # logging.basicConfig函数对日志的输出格式及方式做相关配置 # 由于日志基本配置中级别设置为DEBUG,所以一下打印信息将会全部显示在控制台上 logging.info('this is a loggging info message') logging.debug('this is a loggging debug message') logging.warning('this is loggging a warning message') logging.error('this is an loggging error message') logging.critical('this is a loggging critical message')
日志输出-文件
import logging # 引入logging模块 import os.path import time # 第一步,创建一个logger logger = logging.getLogger() logger.setLevel(logging.INFO) # Log等级总开关 # 第二步,创建一个handler,用于写入日志文件 rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time())) log_path = os.path.dirname(os.getcwd()) + '/Logs/' log_name = log_path + rq + '.log' logfile = log_name fh = logging.FileHandler(logfile, mode='w') fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关 # 第三步,定义handler的输出格式 formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") fh.setFormatter(formatter) # 第四步,将logger添加到handler里面 logger.addHandler(fh) # 日志 logger.debug('this is a logger debug message') logger.info('this is a logger info message') logger.warning('this is a logger warning message') logger.error('this is a logger error message') logger.critical('this is a logger critical message')
日志输出-控制台和文件
只要在输入到日志中的第二步和第三步插入一个handler输出到控制台: 创建一个handler,用于输出到控制台 ch = logging.StreamHandler() ch.setLevel(logging.WARNING) # 输出到console的log等级的开关 第四步和第五步分别加入以下代码即可 ch.setFormatter(formatter) logger.addHandler(ch)
- format常用格式说明
- %(levelno)s: 打印日志级别的数值
- %(levelname)s: 打印日志级别名称
- %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
- %(filename)s: 打印当前执行程序名
- %(funcName)s: 打印日志的当前函数
- %(lineno)d: 打印日志的当前行号
- %(asctime)s: 打印日志的时间
- %(thread)d: 打印线程ID
- %(threadName)s: 打印线程名称
- %(process)d: 打印进程ID
- %(message)s: 打印日志信息
import logging.config
conf = {'version': 1,
'disable_existing_loggers': True,
'incremental': False,
'formatters': {'myformat1': {'class': 'logging.Formatter',
'format': '|%(asctime)s|%(name)s|%(filename)s|%(lineno)d|%(levelname)s|%(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'}
},
'filters': {'filter_by_name': {'class': 'logging.Filter',
'name': 'logger_for_filter_name'},
'filter_single_level_pass':{'()': 'mylogger.SingleLevelFilter',
'pass_level': logging.WARN}
},
'handlers': {'console': {'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'myformat1',
'filters': ['filter_single_level_pass', ]},
'screen': {'()': 'mylogger.ScreenHandler',
'level': logging.INFO,
'formatter': 'myformat1',
'filters': ['filter_by_name', ]}
},
'loggers': {'logger_for_filter_name': {'handlers': ['console', 'screen'],
'filters': ['filter_by_name', ],
'level': 'INFO'},
'logger_for_all': {'handlers': ['console', ],
'filters': ['filter_single_level_pass',],
'level': 'INFO',
'propagate': False}
}
}
logging.config.dictConfig(conf)
logging.getLogger('logger_for_all')
import logging.config
import os
import platform
__PREFIX = 'D:\\tyxb_tiantong_logs' if platform.system() == 'Windows' else '%s/%s/%s' % (
log_path.rstrip('/'), app_name.strip('/'), os.getpid())
# 根据系统修改文件生成路径
__LOG_PATH_DEBUG = r'%s\debug.log' % __PREFIX if platform.system() == 'Windows' else '%s/debug.log' % __PREFIX
__LOG_PATH_INFO = r'%s\info.log' % __PREFIX if platform.system() == 'Windows' else '%s/info.log' % __PREFIX
__LOG_PATH_WARN = r'%s\warn.log' % __PREFIX if platform.system() == 'Windows' else '%s/warn.log' % __PREFIX
__LOG_PATH_ERROR = r'%s\error.log' % __PREFIX if platform.system() == 'Windows' else '%s/error.log' % __PREFIX
# 判断目录是否存在
if not os.path.exists(__PREFIX):
os.makedirs(__PREFIX)
# 鏃ュ織閰嶇疆
__LOGGING_CONFIG = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'standard': {
'format': '[%(asctime)s] %(levelname)s::(%(process)d %(thread)d)::%(module)s(%(funcName)s:%(lineno)d): %(message)s'
},
},
'handlers': {
'error': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'level': 'ERROR',
'formatter': 'standard',
'filename': __LOG_PATH_ERROR + '_file',
'when': 'H',
'interval': 1
},
'warn': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'level': 'WARN',
'formatter': 'standard',
'filename': __LOG_PATH_WARN + '_file',
'when': 'H',
'interval': 1
},
'info': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'level': 'INFO',
'formatter': 'standard',
'filename': __LOG_PATH_INFO + '_file',
'when': 'H',
'interval': 1
},
'debug': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'level': 'DEBUG',
'formatter': 'standard',
'filename': __LOG_PATH_DEBUG + '_file',
'when': 'H',
'interval': 1
}
},
'loggers': {
'default': {
'handlers': ['debug', 'info', 'warn', 'error'],
'level': 'INFO',
'propagate': True
},
'enable_debug': {
'handlers': ['debug', 'info', 'warn', 'error'],
'level': 'DEBUG',
'propagate': True
}
}
}
logging.config.dictConfig(__LOGGING_CONFIG)
if debug:
return logging.getLogger('enable_debug')
else:
return logging.getLogger('default')
重写日志对象
import logging
import getpass
import sys
class L(logging.Logger):
def debug(self, msg, *args, **kwargs):
if self.isEnabledFor(logging.DEBUG):
self._log(logging.DEBUG, msg, args, extra={"真的": "可以"}, **kwargs)
logger = L("new") # logging.getLogger("new")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("[%(asctime)s] %(levelname)s::(%(process)d %(thread)d)::%(module)s(%(funcName)s:%(lineno)d): %(message)s")
ll = logging.StreamHandler()
ll.setFormatter(formatter)
logger.addHandler(ll)
logger.debug("ok")
其他相关资料 https://www.cnblogs.com/CJOKER/p/8295272.html
相关模块
模块 | 内容 |
---|---|
base64 | 提供二进制字符串和文本字符串的编码/解码 |
binascli | 提供二进制和ASCII编码的二进制字符串间的编码/解码 |
bz2 | 访问BZ2格式的压缩文件 |
csv | 访问csv文件 |
json | 访问json文件 |
filecmp | 用于比较目录和文件 |
fileinput | 提供多个文本文件的行迭代器 |
gzip/zlib | 读写GNU zip(gzip)文件/压缩文件 |
c/String() | 对字符串对象提供文件接口 |
zipfile | 用于读取zip归档文件工具 |
tarfile | 读取tar归档文件 |
常用第三方库
chardet检测编码格式
>>> chardet.detect(b'Hello, world!')
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
>>> data = '离离原上草,一岁一枯荣'.encode('utf-8')
>>> chardet.detect(data)
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
IPy
校验ip是否合法
https://pypi.org/project/IPy/
from IPy import IP
>>> print(IP(0x7f000001))
127.0.0.1
>>> print(IP('0x7f000001'))
127.0.0.1
>>> print(IP(' 127.0.0.1'))
127.0.0.1
>>> print(IP('10'))
10.0.0.0
# 如果不合法抛出异常
pillow图像处理库
from PIL import Image
# 打开一个jpg图像文件,注意是当前路径:
im = Image.open('test.jpg')
# 获得图像尺寸:
w, h = im.size
print('Original image size: %sx%s' % (w, h))
# 缩放到50%:
im.thumbnail((w//2, h//2))
print('Resize image to: %sx%s' % (w//2, h//2))
# 把缩放后的图像用jpeg格式保存:
im.save('thumbnail.jpg', 'jpeg')
from PIL import Image, ImageFilter
# 打开一个jpg图像文件,注意是当前路径:
im = Image.open('test.jpg')
# 应用模糊滤镜:
im2 = im.filter(ImageFilter.BLUR)
im2.save('blur.jpg', 'jpeg')
tqdm(iterator)进度条
from tqdm import tqdm
for i in tqdm(range(10)):
pass
psutil监控系统运行状态
https://github.com/giampaolo/psutil https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001511052957192bb91a56a2339485c8a8c79812b400d49000
# 获取CPU的信息:
>>> import psutil
>>> psutil.cpu_count() # CPU逻辑数量
4
>>> psutil.cpu_count(logical=False) # CPU物理核心
2
# 统计CPU的用户/系统/空闲时间:
>>> psutil.cpu_times()
scputimes(user=10963.31, nice=0.0, system=5138.67, idle=356102.45)
six一种版本兼容模块
import six
# 判断是否是python2
six.PY2
# 判断是否是python3
six.PY3
# 兼容py2和py3的队列
from six.moves.queue import Queue
w3lib对url、html、http做处理
http://w3lib.readthedocs.io/en/latest/w3lib.html
import w3lib.url
# 对url进行排序
w3lib.url.canonicalize_url(url, keep_blank_values=True, keep_fragments=False, encoding=None)
suds调用webservice接口
引用初始化
>>> from suds.client import Client
>>> url = 'http://www.gpsso.com/webservice/kuaidi/kuaidi.asmx?wsdl'
>>> client = Client(url)
>>> print client
Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913
Service ( Kuaidi ) tns="http://gpsso.com/"
Prefixes (1)
ns0 = "http://gpsso.com/"
Ports (2):
(KuaidiSoap)
Methods (1):
KuaidiQuery(xs:string Compay, xs:string OrderNo, )
Types (1):
ApiSoapHeader
(KuaidiSoap12)
Methods (1):
KuaidiQuery(xs:string Compay, xs:string OrderNo, )
Types (1):
ApiSoapHeader
>>>
对url做一下说明,一般要确认给的wsdl地址是正常模式,地址打开一般为xml格式而有些服务是做成了html模式,这个会导致实例化或者调用方法的时候出现xml解析异常。
方法调用
2中的client打印出来就可以知道,该webserviece服务定义了什么方法,方法需要什么参数,声明了什么信息等(如头信息,ApiSoapHeader),方法可以通过client.serviece直接调用
>>> client.service.KuaidiQuery(Company='EMS', OrderNo='1111')
(KuaidiQueryResult){
API =
(API){
RESULTS = "0"
MESSAGE = "接口查询成功"
}
}
>>>
而声明的头信息,则可以用factory的方式去实例化
>>> header = client.factory.create('ApiSoapHeader')
>>> print header
(ApiSoapHeader){
APICode = None
APIKey = None
}
>>> header.APICode = '123'
>>> header.APIKey = 'key123'
>>> print header
(ApiSoapHeader){
APICode = "123"
APIKey = "key123"
}
>>>
头信息需要用set_options方法设置
>>>
>>> client.set_options(soapheaders=[header,])
>>>
内建模块
collections集合模块
# namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2
# deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])
# defaultdict
# 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回默认值
'N/A'
# 注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入。
# 除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。
# OrderedDict
# 使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
# 果要保持Key的顺序,可以用OrderedDict:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序
# Counter是一个简单的计数器,例如,统计字符出现的个数:
>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
... c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
# Counter实际上也是dict的一个子类,上面的结果可以看出,字符'g'、'm'、'r'各出现了两次,其他字符各出现了一次。
常见做法:
sum(c.values()) # 继承自字典的.values()方法返回values的列表,再求和
c.clear() # 继承自字典的.clear()方法,清空counter
list(c) # 返回key组成的list
set(c) # 返回key组成的set
dict(c) # 转化成字典
c.items() # 转化成(元素,计数值)组成的列表
Counter(dict(list_of_pairs)) # 从(元素,计数值)组成的列表转化成Counter
c.most_common()[:-n-1:-1] # 最小n个计数的(元素,计数值)组成的列表
c += Counter() # 利用counter的相加来去除负值和0的值
from collections import ChainMap
# 连接操作,如果有相同键只会取第一个元素
dict1={"a":"bobby1", "b":"bobby2"}
dict2={"c":"bobby2", "d":"bobby3"}
new_dict=ChainMap(user_dict1, user_dict2)
for key, value in new_dict.items():
print(key, value)
print(new_dict.maps)
from collections import Iterator, Iterable # 判断类型
时间日期处理
董小旭提供 http://www.wklken.me/posts/2015/03/03/python-base-datetime.html
1. datetime
>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2015, 1, 12, 23, 9, 12, 946118)
>>> type(now)
<type 'datetime.datetime'>
2. timestamp
>>> import time
>>> time.time()
1421075455.568243
3. time tuple
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=12, tm_hour=23, tm_min=10, tm_sec=30, tm_wday=0, tm_yday=12, tm_isdst=0)
4. string
>>> import datetime
>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2015-01-12 23:13:08'
5. date
>>> import datetime
>>> datetime.datetime.now().date()
datetime.date(2015, 1, 12)
datetime基本操作
1. 获取当前datetime
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 12, 23, 26, 24, 475680)
2. 获取当天date
>>> datetime.date.today()
datetime.date(2015, 1, 12)
3. 获取明天/前N天
明天
>>> datetime.date.today() + datetime.timedelta(days=1)
datetime.date(2015, 1, 13)
三天前
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 12, 23, 38, 55, 492226)
>>> datetime.datetime.now() - datetime.timedelta(days=3)
datetime.datetime(2015, 1, 9, 23, 38, 57, 59363)
4. 获取当天开始和结束时间(00:00:00 23:59:59)
>>> datetime.datetime.combine(datetime.date.today(), datetime.time.min)
datetime.datetime(2015, 1, 12, 0, 0)
>>> datetime.datetime.combine(datetime.date.today(), datetime.time.max)
datetime.datetime(2015, 1, 12, 23, 59, 59, 999999)
5. 获取两个datetime的时间差
>>> (datetime.datetime(2015,1,13,12,0,0) - datetime.datetime.now()).total_seconds()
44747.768075
6. 获取本周/本月/上月最后一天
本周
>>> today = datetime.date.today()
>>> today
datetime.date(2015, 1, 12)
>>> sunday = today + datetime.timedelta(6 - today.weekday())
>>> sunday
datetime.date(2015, 1, 18)
本月
>>> import calendar
>>> today = datetime.date.today()
>>> _, last_day_num = calendar.monthrange(today.year, today.month)
>>> last_day = datetime.date(today.year, today.month, last_day_num)
>>> last_day
datetime.date(2015, 1, 31)
获取上个月的最后一天(可能跨年)
>>> import datetime
>>> today = datetime.date.today()
>>> first = datetime.date(day=1, month=today.month, year=today.year)
>>> lastMonth = first - datetime.timedelta(days=1)
关系转换
几个关系之间的转化
Datetime Object / String / timestamp / time tuple
关系转换例子
datetime <=> string
datetime -> string
>>> import datetime
>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2015-01-12 23:13:08'
string -> datetime
>>> import datetime
>>> datetime.datetime.strptime("2014-12-31 18:20:10", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2014, 12, 31, 18, 20, 10)
datetime -> timetuple
>>> import datetime
>>> datetime.datetime.now().timetuple()
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=12, tm_hour=23, tm_min=17, tm_sec=59, tm_wday=0, tm_yday=12, tm_isdst=-1)
timetuple -> datetime
timetuple => timestamp => datetime [看后面datetime<=>timestamp]
datetime <=> date
datetime -> date
>>> import datetime
>>> datetime.datetime.now().date()
datetime.date(2015, 1, 12)
date -> datetime
>>> datetime.date.today()
datetime.date(2015, 1, 12)
>>> today = datetime.date.today()
>>> datetime.datetime.combine(today, datetime.time())
datetime.datetime(2015, 1, 12, 0, 0)
>>> datetime.datetime.combine(today, datetime.time.min)
datetime.datetime(2015, 1, 12, 0, 0)
datetime <=> timestamp
datetime -> timestamp
>>> now = datetime.datetime.now()
>>> timestamp = time.mktime(now.timetuple())
>>> timestamp
1421077403.0
timestamp -> datetime
>>> datetime.datetime.fromtimestamp(1421077403.0)
datetime.datetime(2015, 1, 12, 23, 43, 23)
加锁——fcntl模块
import fcntl
打开一个文件
f = open('./test') ##当前目录下test文件要先存在,如果不存在会报错。
对该文件加密:
fcntl.flock(f,fcntl.LOCK_EX)
这样就对文件test加锁了,如果有其他进程对test文件加锁,则不能成功,会被阻塞,但不会退出程序。
解锁:fcntl.flock(f,fcntl.LOCK_UN)
cntl模块:
flock() : flock(f, operation)
operation : 包括:
fcntl.LOCK_UN 解锁
fcntl.LOCK_EX 排他锁
fcntl.LOCK_SH 共享锁
fcntl.LOCK_NB 非阻塞锁
LOCK_SH 共享锁:所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限。
LOCK_EX 排他锁:除加锁进程外其他进程没有对已加锁文件读写访问权限。
LOCK_NB 非阻塞锁:
如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_NB进行按位或(|)运算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)
例子:
import os
import sys
import time
import fcntl #导入模块
class FLOCK(ojbect):
def __init__(self,name):
"""
:param name: 文件名
"""
self.fobj = open(name,'w')
self.fd = self.fobj.fileno()
def lock(self):
try:
fcntl.lockf(sefl.fd,fcntl.LOCK_EX|fcntl.LOCK_NB) #给文件加锁,使用了fcntl.LOCK_NB
print '给文件加锁,稍等 ... ...'
time.sleep(20)
return True
except:
print '文件加锁,无法执行,请稍后运行。'
retrun False
def unlock(self):
self.fobj.close()
print '已解锁'
if __name__ == "__main__":
print sys.argv[1]
locker = FLOCK(sys.argv[1])
a = locker.lock()
if a:
print '文件已加锁'
else:
print '无法执行,程序已锁定,请稍等'
decimal快速入门
https://docs.python.org/2/library/decimal.html#quick-start-tutorial
十进制模块具有用户可更改的精度(默认为28个位置),对于给定的问题,该精度可以与需要的一样大:
>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal(1) / Decimal(7)
Decimal('0.142857')
>>> getcontext().prec = 28
>>> Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')
通常开始使用小数将导入模块,查看当前上下文,getcontext()并在必要时为精度,舍入或启用的陷阱设置新值:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # Set a new precision
十进制实例可以用整数,字符串,浮点数或元组构造。从整数或浮点构造执行该整数或浮点的值的精确转换。十进制数字包括特殊值,例如 NaN,表示“不是数字”,正数和负数 Infinity,以及-0。
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.41421356237')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
新Decimal的意义仅由输入的位数决定。上下文精度和舍入仅在算术运算中发挥作用。
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
小数与Python的其余部分很好地交互。这里有一个小小数浮点飞行马戏团:
>>> data = map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split())
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1) # round() first converts to binary floating point
1.3
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
还有一些数学函数也可用于Decimal:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
该quantize()方法将数字四舍五入为固定的指数。这种方法对于货币应用程序非常有用,这些应用程序通常会将结果转换为固定数量的地方
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
如上所示,该getcontext()功能访问当前上下文并允许更改设置。这种方法可以满足大多数应用的需求。
对于更高级的工作,使用Context()构造函数创建备用上下文可能很有用。要使备用激活,请使用该setcontext() 功能。
根据该标准,该decimal模块提供了两个准备使用的标准上下文,BasicContext并且ExtendedContext。前者对于调试特别有用,因为许多陷阱都已启用:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
上下文还有信号标志用于监控计算过程中遇到的异常情况。这些标志保持设置直到明确清除,所以最好在每一组监控计算之前使用该clear_flags()方法清除标志。
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, flags=[Rounded, Inexact], traps=[])
该标志条目显示合理的近似Pi四舍五入(数字超出范围内精度被扔掉了),而且结果不准确(有些丢弃数字为非零)。
单个陷阱是使用traps上下文字段中的字典设置的:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
大多数程序只在程序开始时调整当前上下文一次。而且,在许多应用程序中,数据会Decimal在循环内转换为单个数据。通过创建上下文集和小数点,程序的大部分操作数据的方式与其他Python数字类型无异。
class decimal.Decimal([ value [,context ] ] ) Decimal基于价值构建一个新的对象。
值可以是整数,字符串,元组float或其他Decimal 对象。如果没有给出价值,则返回Decimal('0')。如果value是一个字符串,则在删除前导和尾随空白字符后,它应该符合十进制数字字符串语法:
sign ::= '+' | '-'
digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator ::= 'e' | 'E'
digits ::= digit [digit]...
decimal-part ::= digits '.' [digits] | ['.'] digits
exponent-part ::= indicator [sign] digits
infinity ::= 'Infinity' | 'Inf'
nan ::= 'NaN' [digits] | 'sNaN' [digits]
numeric-value ::= decimal-part [exponent-part] | infinity
numeric-string ::= [sign] numeric-value | [sign] nan
操作说明
adjusted()
移出系数最右边的数字后,返回调整后的指数,直到只剩下前导数字: Decimal('321e+5').adjusted()返回7。用于确定最重要数字相对于小数点的位置。
as_tuple()
返回数字的命名元组表示形式: 。DecimalTuple(sign, digits, exponent)
在版本2.6中更改:使用命名的元组。
canonical()
返回参数的规范编码。目前,一个Decimal实例的编码总是规范的,所以这个操作返回它的参数不变。
2.6版本中的新功能。
compare(其他[,上下文] )
比较两个Decimal实例的值。此操作的行为与通常的比较方法相同__cmp__(),只是 compare()返回Decimal实例而不是整数,并且如果任一操作数是NaN,则结果是NaN:
a or b is a NaN ==> Decimal('NaN')
a < b ==> Decimal('-1')
a == b ==> Decimal('0')
a > b ==> Decimal('1')
compare_signal(其他[,上下文] )
compare()除了所有的NaNs信号之外,该操作与该方法相同。也就是说,如果两个操作数都不是一个NaN信号,那么任何安静的NaN操作数都被视为一个信号NaN。
compare_total(其他)
使用它们的抽象表示比较两个操作数,而不是它们的数值。与该compare()方法类似,但结果给出了Decimal实例的总排序。Decimal具有相同数值但不同表示的两个 实例在此顺序中比较不等:
>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')
安全和信令NaNs也包括在总的顺序中。这个函数的结果是,Decimal('0')如果两个操作数具有相同的表示形式,Decimal('-1')如果第一个操作数在总顺序中低于第二个,并且Decimal('1')第一个操作数在总顺序中高于第二个操作数。有关总订单的详细信息,请参阅规格。
2.6版本中的新功能。
compare_total_mag(其他)
比较两个操作数使用它们的抽象表示而不是它们的值compare_total(),但忽略每个操作数的符号。 x.compare_total_mag(y)相当于 x.copy_abs().compare_total(y.copy_abs())。
2.6版本中的新功能。
conjugate()
只是返回自我,这种方法只符合十进制规范。
2.6版本中的新功能。
copy_abs()
返回参数的绝对值。此操作不受上下文影响,并且很安静:没有标志被更改,也没有执行舍入。
2.6版本中的新功能。
copy_negate()
返回参数的否定。此操作不受上下文影响,并且很安静:没有标志被更改,也没有执行舍入。
2.6版本中的新功能。
copy_sign(其他)
返回第一个操作数的副本,并将符号设置为与第二个操作数的符号相同。例如:
>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')
此操作不受上下文影响,并且很安静:没有标志被更改,也没有执行舍入。
2.6版本中的新功能。
exp([ context ] )
返回e**x给定数字处的(自然)指数函数的值。结果使用ROUND_HALF_EVEN舍入模式正确舍 入。
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
2.6版本中的新功能。
from_float(f )
精确地将float转换为十进制数的Classmethod。
注意Decimal.from_float(0.1)与Decimal('0.1')不同。由于0.1在二进制浮点中不能完全表示,因此该值存储为最接近的可表示值,即 0x1.999999999999ap-4。该十进制等效值是 0.1000000000000000055511151231257827021181583404541015625。
注意 从Python 2.7开始,一个Decimal实例也可以直接从a构建float。
>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')
2.7版本的新功能。
fma(other,third [,context ] )
融合乘加。返回自己*其他+第三没有舍去中间产品自己*其他。
>>> Decimal(2).fma(3, 5)
Decimal('11')
2.6版本中的新功能。
is_canonical()
True如果参数是规范的,False 否则返回。目前,一个Decimal实例总是规范的,所以这个操作总是返回True。
2.6版本中的新功能。
is_finite()
返回True如果参数是一个有限数量,以及 False如果参数为无穷大或为NaN。
2.6版本中的新功能。
is_infinite()
返回True如果参数为正或负无穷大,False否则。
2.6版本中的新功能。
is_nan()
返回True如果参数是(安静或信令)的NaN和 False其它。
2.6版本中的新功能。
is_normal()
True如果参数是一个调整指数大于或等于Emin的正常有限非零数字,则返回。返回如果参数为0,低于正常,无穷大或NaN的。请注意,术语“ 法线”在此处与用于创建典型值的方法在不同的意义上使用。Falsenormalize()
2.6版本中的新功能。
is_qnan()
True如果参数是安静的NaN,则返回, False否则返回。
2.6版本中的新功能。
is_signed()
True如果参数有负号False则返回, 否则返回。请注意,零和NaN都可以携带符号。
2.6版本中的新功能。
is_snan()
返回True如果参数信令楠False 否则。
2.6版本中的新功能。
is_subnormal()
True如果参数是低于正常的,则返回,False 否则返回。如果数字非零,有限且调整指数小于Emin,则数字为低于正常值。
2.6版本中的新功能。
is_zero()
返回True如果参数为一(正或负)和零 False否则。
2.6版本中的新功能。
ln([ context ] )
返回操作数的自然对数(基数e)。结果使用ROUND_HALF_EVEN舍入模式正确舍入。
2.6版本中的新功能。
log10([ context ] )
返回操作数的十进制对数。结果使用ROUND_HALF_EVEN舍入模式正确舍入。
2.6版本中的新功能。
logb([ context ] )
对于非零数字,返回其操作数的调整指数作为 Decimal实例。如果操作数为零,则 Decimal('-Infinity')返回该DivisionByZero标志并引发该标志。如果操作数是无穷大,则Decimal('Infinity')返回。
2.6版本中的新功能。
logical_and(其他[,上下文] )
logical_and()是一个逻辑操作,它需要两个逻辑操作数(请参阅逻辑操作数)。结果是and两个操作数的数字方式。
2.6版本中的新功能。
logical_invert([ context ] )
logical_invert()是一种逻辑运算。结果是操作数的数字反转。
2.6版本中的新功能。
logical_or(其他[,上下文] )
logical_or()是一个逻辑操作,它需要两个逻辑操作数(请参阅逻辑操作数)。结果是or两个操作数的数字方式。
2.6版本中的新功能。
logical_xor(其他[,上下文] )
logical_xor()是一个逻辑操作,它需要两个逻辑操作数(请参阅逻辑操作数)。结果是数字独占或两个操作数。
2.6版本中的新功能。
max(其他[,上下文] )
像不同的是在返回之前和施加的上下文舍入规则值用信号通知或忽略(取决于上下文以及它们是否信令或安静)。max(self, other)NaN
max_mag(其他[,上下文] )
与该max()方法类似,但使用操作数的绝对值进行比较。
2.6版本中的新功能。
min(其他[,上下文] )
像不同的是在返回之前和施加的上下文舍入规则值用信号通知或忽略(取决于上下文以及它们是否信令或安静)。min(self, other)NaN
min_mag(其他[,上下文] )
与该min()方法类似,但使用操作数的绝对值进行比较。
2.6版本中的新功能。
next_minus([ context ] )
返回给定上下文中的最大数字(或者在当前线程的上下文中,如果没有给出上下文),该数字小于给定的操作数。
2.6版本中的新功能。
next_plus([ context ] )
返回大于给定操作数的给定上下文(或者在当前线程的上下文中,如果没有给出上下文)中可表示的最小数字。
2.6版本中的新功能。
next_toward(其他[,上下文] )
如果两个操作数不相等,则在第二个操作数的方向上返回最接近第一个操作数的数字。如果两个操作数在数值上相等,则返回第一个操作数的副本,并将符号设置为与第二个操作数的符号相同。
2.6版本中的新功能。
normalize([ context ] )
通过汽提最右边的尾随零和转换等于任何结果归一化数Decimal('0')到 Decimal('0e0')。用于为等价类的属性生成规范值。例如,Decimal('32.100')与 Decimal('0.321000e+2')两个正常化为等效值 Decimal('32.1')。
number_class([ context ] )
返回描述操作数类的字符串。返回的值是以下十个字符串之一。
"-Infinity",表明操作数是负无穷大。
"-Normal",表明该操作数是一个负的正常数。
"-Subnormal"表明操作数是负数和低于正常的。
"-Zero",表明操作数是负零。
"+Zero",表明操作数是一个正的零。
"+Subnormal",表明操作数是正的和低于正常的。
"+Normal",表示操作数是正数。
"+Infinity",表明操作数是正无穷。
"NaN",表明操作数是一个安静的NaN(不是数字)。
"sNaN",表明操作数是一个信号NaN。
2.6版本中的新功能。
quantize(exp [,rounding [,context [,watchexp ] ] ] )
在舍入后返回一个等于第一个操作数并具有第二个操作数的指数的值。
>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')
与其他操作不同,如果量化操作之后的系数长度大于精度,则会InvalidOperation发出an 信号。这保证了,除非有错误条件,否则量化指数总是等于右侧操作数的指数。
与其他操作不同,即使结果是次正常且不精确,量化也不会发出下溢信号。
如果第二个操作数的指数大于第一个操作数的指数,则可能需要舍入。在这种情况下,舍入模式由rounding参数确定,如果给出,则由给定 context参数确定; 如果没有给出参数,则使用当前线程上下文的舍入模式。
如果watchexp被设置(默认),那么只要结果指数大于Emax或小于, 就会返回一个错误Etiny。
radix()
返回Decimal(10),Decimal 类中所有算术的基数(基数)。包括与规范的兼容性。
2.6版本中的新功能。
remainder_near(其他[,上下文] )
从分返回,其余自通过其他。这不同于 其余部分的符号被选择为使其绝对值最小化。更确切地说,返回值是 其中最接近的精确值的整数,如果两个整数都同样接近,则即使一个选择。self % otherself - n * othernself / other
如果结果为零,那么它的符号将是自我的标志。
>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(其他[,上下文] )
将第一个操作数的数字旋转一个由第二个操作数指定的量的结果。第二个操作数必须是精度范围-precision中的整数。第二个操作数的绝对值给出了要旋转的地方的数量。如果第二个操作数是正的,那么旋转是在左边; 否则旋转是正确的。如有必要,第一个操作数的系数在左侧填充为零以达到长度精度。第一个操作数的符号和指数保持不变。
2.6版本中的新功能。
same_quantum(其他[,上下文] )
测试自我和其他人是否有相同的指数或两者是否都是 NaN。
scaleb(其他[,上下文] )
返回第一个操作数,指数由第二个调整。等价地,返回第一个操作数乘以10**other。第二个操作数必须是整数。
2.6版本中的新功能。
shift(其他[,上下文] )
返回将第一个操作数的数位移位第二个操作数指定的数值的结果。第二个操作数必须是精度范围-precision中的整数。第二个操作数的绝对值给出了要移位的位数。如果第二个操作数是正的,那么这个移位是在左边; 否则这个转变是在右边。移入系数的数字是零。第一个操作数的符号和指数保持不变。
2.6版本中的新功能。
sqrt([ context ] )
将参数的平方根返回到完全精度。
to_eng_string([ context ] )
如果需要指数,则转换为字符串,使用工程符号。
工程符号的指数是3的倍数。这可以在小数点左边留下最多3位数字,并且可能需要添加一个或两个尾随零。
例如,这转换Decimal('123E+1')为Decimal('1.23E+3')。
to_integral([ rounding [,context ] ] )
与该to_integral_value()方法相同。该to_integral 名称一直保持与旧版本的兼容性。
to_integral_exact([ rounding [,context ] ] )
四舍五入到最接近的整数,发信号Inexact或 Rounded酌情发生舍入。舍入模式由rounding给定的参数确定,否则由给定的参数 确定context。如果没有给出参数,则使用当前上下文的舍入模式。
2.6版本中的新功能。
to_integral_value([ rounding [,context ] ] )
四舍五入到最接近的整数,无需信号Inexact或 Rounded。如果给出,则适用四舍五入 ; 否则,在提供的上下文或当前上下文中使用舍入方法。
在版本2.6中更改:从重命名to_integral为to_integral_value。旧名称对于兼容性仍然有效。
subprocess模块
https://docs.python.org/2/library/subprocess.html
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
运行args描述的命令。等待命令完成,然后返回returncode属性。
上面显示的参数仅仅是最常用的参数,在下面的常用参数中进行了描述(因此缩写签名中的略带奇数的记号)。完整的函数签名与Popen构造函数的签名相同- 该函数将所有提供的参数直接传递到该接口。 例子:
>>> subprocess.call(["ls", "-l"])
0
>>> subprocess.call("exit 1", shell=True)
1
==警告:使用shell=True可能是安全隐患。执行包含来自不可信源的未经处理的输入的shell命令会使程序容易受到shell注入的攻击,这是一个严重的安全漏洞,可导致任意命令执行。在使用时shell=True,pipes.quote()可用于正确地转义要用于构造shell命令的字符串中的空白和shell元字符。==
==注意:不要使用stdout=PIPE或stderr=PIPE使用此功能,因为它可能会基于子进程输出量导致死锁。在需要管道时使用Popen该communicate()方法。==
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
带参数运行命令。等待命令完成。如果返回码为零,则返回,否则提升CalledProcessError。该 CalledProcessError对象将在returncode属性中具有返回码 。
例子:
>>> subprocess.check_call(["ls", "-l"])
0
>>> subprocess.check_call("exit 1", shell=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
使用参数运行命令并将其输出作为字节字符串返回。
如果返回代码不为零,则会引发一次CalledProcessError。该 CalledProcessError对象将在returncode属性中具有返回码,并在 属性中包含任何输出 output。
例子:
>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'
>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
要在结果中捕获标准错误,请使用 stderr=subprocess.STDOUT:
>>> subprocess.check_output(
... "ls non_existent_file; exit 0",
... stderr=subprocess.STDOUT,
... shell=True)
'ls: non_existent_file: No such file or directory\n'
subprocess.PIPE 特殊值,可用作标准输入,标准输出或标准错误参数,Popen并指示应打开标准流的管道。
subprocess.STDOUT 可以用作stderr参数的特殊值,Popen并指示标准错误应该与标准输出进入相同的句柄。
exception subprocess.CalledProcessError 当进程运行check_call()或 check_output()返回非零退出状态时引发异常。
returncode 退出子进程的状态。
cmd 用于产生子进程的命令。
output 子进程的输出,如果这个异常被引发 check_output()。否则,None。
commands的使用
# 如果需求返回结果该模块提供了很好的方法
>>> import commands
>>> commands.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> commands.getstatusoutput('cat /bin/junk')
(256, 'cat: /bin/junk: No such file or directory')
>>> commands.getstatusoutput('/bin/junk')
(256, 'sh: /bin/junk: not found')
>>> commands.getoutput('ls /bin/ls')
'/bin/ls'
>>> commands.getstatus('/bin/ls')
'-rwxr-xr-x 1 root 13352 Oct 14 1994 /bin/ls'
traceback模块
import traceback
try:
1/0
except Exception,e:
traceback.print_exc()
输出结果是
Traceback (most recent call last):
File "test_traceback.py", line 3, in <module>
1/0
ZeroDivisionError: integer division or modulo by zero
这样非常直观有利于调试。
traceback.print_exc()跟traceback.format_exc()有什么区别呢?
format_exc()返回字符串,print_exc()则直接给打印出来。
即traceback.print_exc()与print traceback.format_exc()效果是一样的。
print_exc()还可以接受file参数直接写入到一个文件。比如
traceback.print_exc(file=open('tb.txt','w+'))
写入到tb.txt文件去。
hashlib提供常见的摘要算法
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
import hashlib
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())
# 对象 = hashlib.加密算法('字符串')也可以这样用
types判断python对象类型
import types
In [3]: types.GeneratorType
Out[3]: generator
ctype的使用
官方网址 https://docs.python.org/2/library/ctypes.html
其他 https://www.cnblogs.com/rainduck/archive/2011/09/02/2163230.html
以下是Windows的一些示例。请注意,msvcrtMS标准C库包含大多数标准C函数,并使用cdecl调用约定:
>>> from ctypes import *
>>> print windll.kernel32
<WinDLL 'kernel32', handle ... at ...>
>>> print cdll.msvcrt
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt
>>>
Windows会.dll自动附加通常的文件后缀。
在Linux上,需要指定包含加载库的扩展名的文件名,因此不能使用属性访问来加载库。要么使用LoadLibrary()dll加载器的方法,要么 通过调用构造函数创建CDLL实例来加载库:
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")
>>> libc
<CDLL 'libc.so.6', handle ... at ...>
>>>
ctypes类型 | c类型 | python类型 |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character string |
c_wchar | wchar_t | 1-character unicode string |
c_byte | char | int/long |
c_ubyte | unsigned char | int/long |
c_short | short | int/long |
c_ushort | unsigned short | int/long |
c_int | int | int/long |
c_uint | unsigned int | int/long |
c_long | long int/long | |
c_ulong | unsigned long | int/long |
c_longlong | __int64 or long long | int/long |
c_ulonglong | unsigned __int64 or unsigned long long | int/long |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char * (NUL terminated) | string or None |
c_wchar_p | wchar_t * (NUL terminated) | unicode or None |
c_void_p | void * | int/long or None |
from ctypes import *
a=c_int * 10
print(a(1,2,3,4,5,6,7,8,9,10))
for i in a(1,2,3,4,5,6,7,8,9,10):
print(i)
<__main__.c_long_Array_10 object at 0x0000000004AF5148>
1
2
3
4
5
6
7
8
9
10
struct模块中的函数及用法
函数 | return | explain |
---|---|---|
pack(fmt,v1,v2…) | string | 按照给定的格式(fmt),把数据转换成字符串(字节流),并将该字符串返回. |
pack_into(fmt,buffer,offset,v1,v2…) | None | 按照给定的格式(fmt),将数据转换成字符串(字节流),并将字节流写入以offset开始的buffer中.(buffer为可写的缓冲区,可用array模块) |
unpack(fmt,v1,v2…..) | tuple | 按照给定的格式(fmt)解析字节流,并返回解析结果 |
pack_from(fmt,buffer,offset) | tuple | 按照给定的格式(fmt)解析以offset开始的缓冲区,并返回解析结果 |
calcsize(fmt) | size of fmt | 计算给定的格式(fmt)占用多少字节的内存,注意对齐方式 |
struct对齐方式
为了同c中的结构体交换数据,还要考虑c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下 Character | Byte order | Size | Alignment ---|---|---|--- @(默认) | 本机 | 本机 | 本机,凑够4字节 = | 本机 | 标准 | none,按原字节数 < | 小端 | 标准 | none,按原字节数
| 大端 | 标准 | none,按原字节数 ! | network(大端) | 标准 | none,按原字节数
struct格式符
格式符 | C语言类型 | Python类型 | Standard size |
---|---|---|---|
x | pad byte(填充字节) no value | ||
c | char | string of length 1 | 1 |
b | signed char | integer | 1 |
B | unsigned char | integer | 1 |
? | _Bool | bool | 1 |
h | short | integer | 2 |
H | unsigned short | integer | 2 |
i | int | integer | 4 |
I(大写的i) | unsigned int | integer | 4 |
l(小写的L) | long | integer | 4 |
L | unsigned long | long | 4 |
q | long long | long | 8 |
Q | unsigned long long | long | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | string | |
p | char[] | string | |
P | void * | long |
简单使用
import struct
a = 20
b = 400
str = struct.pack("ii", a, b)
#转换后的str虽然是字符串类型,但相当于其他语言中的字节流(字节数组),可以在网络上传输
print 'length:', len(str)
print str
print repr(str)
#---- result
#length: 8
# ----这里是乱码
#'/x14/x00/x00/x00/x90/x01/x00/x00'
str = struct.pack("ii", 20, 400)
a1, a2 = struct.unpack("ii", str)
print 'a1:', a1
print 'a2:', a2
#---- result:
#a1: 20
#a2: 400
struct.calcsize
import struct
from ctypes import create_string_buffer
buf = create_string_buffer(12)
print repr(buf.raw)
struct.pack_into("iii", buf, 0, 1, 2, -1)
print repr(buf.raw)
print struct.unpack_from('iii', buf, 0)
#---- result
#'/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00'
#'/x01/x00/x00/x00/x02/x00/x00/x00/xff/xff/xff/xff'
#(1, 2, -1)
# 有符号转无符号
e=-641881654
a=struct.pack('i',e)
struct.unpack('I',a)
迭代器
- 通过可迭代对象的iter() 返回的
- 有next() next
- StopIteration
class Iterable: def __iter__(self): return self def __init__(self): self.start=-1 def __next__(self): self.start +=2 if self.start >10: raise StopIteration return self.start
py3
[1,2,3,4].iter().next()
py2
[1,2,3,4].iter().next()
#### 生成器
1. 生成器(generator)是特殊的迭代器,函数中有yield关键字就是生成器
2. 创建方法:函数、生成器表达式
3. 原生的数据结构:列表、字符串、元组、字典,range、xrange
==(py3的range=py2的xrange)==
```python
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
异常 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError Python | 语法错误 |
IndentationError | 缩进错误 |
TabError Tab | 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError Unicode | 相关的错误 |
UnicodeDecodeError Unicode | 解码时的错误 |
UnicodeEncodeError Unicode | 编码时错误 |
UnicodeTranslateError Unicode | 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
检测和处理异常
# 在python中使用try捕获异常,except处理异常.
# 捕获异常和处理异常通常同时使用
try:
需要监控的代码块
except Exception as e:
print(e)
# 也可以多个except,处理指定异常
try:
需要监控的代码块
except ValueError:
pass
except TypeError:
pass
# 当条件不满足时可以执行else,无论之前的条件满不满足都会执行finally
try:
需要监控的代码块
except:
pass
else:
pass
finally:
pass
自定义异常
class 自定义异常(Exception):
'''只需要重写父类的init方法就可以'''
def __init__(self,err='erro'):
Exception.__init__(self,err)
def test():
'''手动抛出异常'''
raise 自定义异常
try:
test()
except 自定义异常 as e:
print(e)
断言
- assert语句用来声明某个条件是真的。
- 如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。
- 当assert语句失败的时候,会引发AssertionError异常。
assert 表达式 [, 参数]
def foo(s): n = int(s) assert n != 0, 'n is zero!' return 10 / n
def main(): foo('0')
$ python err.py Traceback (most recent call last): ... AssertionError: n is zero!
#### 打断点
```python
启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。我们先准备好程序:
# err.py
s = '0'
n = int(s)
print(10 / n)
然后启动:
$ python -m pdb err.py
> /Users/michael/Github/learn-python3/samples/debug/err.py(2)<module>()
-> s = '0'
# 这种通过pdb在命令行调试的方法理论上是万能的,但实在是太麻烦了,如果有一千行代码,要运行到第999行得敲多少命令啊。还好,我们还有另一种调试方法。
pdb.set_trace()
这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点:
# err.py
import pdb
s = '0'
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print(10 / n)
单元测试
import unittest
class TestDict(unittest.TestCase):
def setUp(self):
'''构造函数'''
print('setUp...')
def test_func(self):
pass
def tearDown(self):
'''析构函数'''
print('tearDown...')
if __name__ == '__main__':
unittest.main()
# 编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。
# 以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
# 对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual():
self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
# 另一种重要的断言就是期待抛出指定类型的Error,比如通过d['empty']访问不存在的key时,断言会抛出KeyError:
with self.assertRaises(KeyError):
value = d['empty']
#而通过d.empty访问不存在的key时,我们期待抛出AttributeError:
with self.assertRaises(AttributeError):
value = d.empty
函数
- 函数式编程
- 位置参数、关键字参数、默认参数、非关键字可变长参数(元组)args、关键字变量参数(字典)*kwargs、全局变量global关键字、内嵌函数
- 闭包,访问闭包外层的变量使用nonlocal关键字
- 内层函数引用外层函数的变量(参数也算变量),然后返回内层函数的情况称为闭包
def func(): def func2(): return return func
- 内层函数引用外层函数的变量(参数也算变量),然后返回内层函数的情况称为闭包
- 装饰器,访问外层的变量使用nonlocal关键字
# import functools def wapper(func): # @functools.wraps(func)#修饰内层函数,以防止当前装饰器去修改被装饰函数的__name__属性 def inner(): return func(*args,**kwargs) return inner
@wapper def func(): return
#### 高阶函数
[廖雪峰的网站](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317852443934a86aa5bb5ea47fbbd5f35282b331335000)
> map():函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
```python
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce:把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
from functools import reduce
def add(x, y):
return x + y
reduce(add, [1, 3, 5, 7, 9])
25
filter():也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
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函数来实现自定义的排序
sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
偏函数
# 简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
# 自己写一个偏函数
class partial:
def __new__(cls, func, *args, **kwargs):
if not callable(func):
raise TypeError("the first argument must be callable")
self = super().__new__(cls)
self.func = func
self.args = args
self.kwargs = kwargs
return self
def __call__(self, *args, **kwargs):
newkeywords = self.kwargs.copy()
newkeywords.update(kwargs)
return self.func(*self.args, *args, **newkeywords)
# 使用:
def add(x, y):
return x + y
inc = partial(add, y=1)
print(inc(41)) # 42
StringIO与BytesIO
>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> print(f.getvalue())
hello world!
# getvalue()方法用于获得写入后的str。
# 要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:
>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
... s = f.readline()
... if s == '':
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!
# StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
# BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
# 请注意,写入的不是str,而是经过UTF-8编码的bytes。
# 和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:
>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
==import和import(str)调用模块不同==
globals()和locals()查看全局和局部命名空间 reload(model)重新导入已经导入的模块
面向对象编程
==在python中类是用来创建对象的==
- 私有的属性,不能通过对象直接访问,但是可以通过方法访问
- 私有的方法,不能通过对象直接访问
- 私有的属性、方法,不会被子类继承,也不能被访问
- 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
- 父类中的 私有方法、属性,不会被子类继承
- 可以通过调用继承的父类的共有方法,间接的访问父类的私有方法、属性
class Myobj(object):
'''定义类,所有私有属性和方法都不会被继承,私有属性不能直接被实例对象调用'''
__私有类属性 = None
类属性 = None
country = 'china'
def __init__(self,*args,**kwargs):
'''定义构造方法,初始化实例属性'''
self.name = None
self._受保护的属性= None
self.__私有属性= None
def __str__(self):
"""返回一个对象的描述信息"""
return '输出%s'%self.name
def method(self):
print('我的方法')
def __私有方法(self):
return
def __del__(self):
'''析构方法,当对象被删除时自动调用'''
print('end')
@classmethod
def getCountry(cls):
'''类方法'''
return cls.country
@staticmethod
def getCountry():
'''静态方法'''
return People.country
class 子类(Myobj):
'''子类可以继承一个或多个父类,相同属性会优先调用第一个父类,如果子类创建了和父类一样方法和属性会重写父类的该方法或属性'''
pass
# 类访问类方法
Myobj().getCountry
# 类访问实例方法
Myobj().method()
# 实例化对象
obj=Myobj()
# 实例对象访问实例属性
obj.method()
# 写入属性
obj.__setattr__('mv',2)
# 获取属性
print(obj.__getattribute__('mv'))
# python还提供了一种为了达到限制的目的,允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
# 定制类
# __len__()方法我们也知道是为了能让class作用于len()函数。
# 两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。
# 通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法:
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
# 要表现得像list那样按照下标取出元素,需要实现__getitem__()方法:
class Fib(object):
def __getitem__(self, n):
if isinstance(n, int): # n是索引
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
>>> f = Fib()
>>> f[0:5]
[1, 1, 2, 3, 5]
>>> f[:10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# 枚举类
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
# @unique装饰器可以帮助我们检查保证没有重复值。
工厂模式
class Person:
# 工厂模式父类只定义属性和基本方法
def __init__(self):
self.name = None
self.gender = None
def getName(self):
return self.name
def getGender(self):
return self.gender
class Male(Person):
def __init__(self, name):
print "Hello Mr." + name
class Female(Person):
def __init__(self, name):
print "Hello Miss." + name
class Factory:
# 实际最后执行的都是子类
def getPerson(self, name, gender):
if gender == ‘M':
return Male(name)
if gender == 'F':
return Female(name)
if __name__ == '__main__':
factory = Factory()
person = factory.getPerson("Chetan", "M")
单例模式
class Singleton(object):
def __init__(self,*args,**kwargs):
pass
@classmethod
def get_instance(cls, *args, **kwargs):
# 利用反射,看看这个类有没有_instance属性
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
# 使用装饰器创建单例
def singleton(cls):
instance = {}
def _singleton(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return _singleton
==如果一个文件中有all变量,那么也就意味着这个变量中的元素,不会被from xxx import *时导入==
__all__ = ['类名','函数名']
元类
# 我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
# metaclass是创建类,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list):
__metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类
网络编程
udp协议
from socket import socket
# 创建套接字
udp_socket=socket(AF_INET,SOCK_DGRAM)
# 绑定端口
udp_socket.bind(('',port))
# 设置广播
udp_socket.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
# 发送消息
udp_socket.sendto('消息'.encode('gbk'),('目标ip',端口))
# 接收消息
接收的数据,地址=udp_socket.recvfrom(字节数)
接收的数据.decode('gbk')
tcp协议
# tcp客户端
from socket import socket
# 创建套接字
tcp_client=socket(AF_INET,SOCK_STREAM)
# 连接服务器
tcp_client.connect(('服务器ip',服务器port))
# 发送数据
tcp_client.send('消息'.encode('gbk'))
# 关闭连接
tcp_client.close()
# tcp服务端
from socket import socket
# 创建套接字
tcp_server=socket(AF_INET,SOCK_STREAM)
# 地址重用
tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
# 绑定地址
tcp_server.bind(('',7788))
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcp_server.listen(128)
# 接收连接
客户连接,客户地址=tcp_server.accept()
# 接收数据
数据=客户连接,recv(字节)
# 发送数据
客户连接.send('数据'.encode('gbk'))
# 关闭连接
客户连接.close()
Socket内建方法
函数 | 描述 |
---|---|
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 |
s.recvfrom() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值。 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值。 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。 |
s.fileno() | 返回套接字的文件描述符。 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关连的文件 |
setsockopt(level,optname,value)
选项 | 意义 | 期望值 |
---|---|---|
SO_BINDTODEVICE | 可以使socket只在某个特殊的网络接口(网卡)有效。也许不能是移动便携设备 | 一个字符串给出设备的名称或者一个空字符串返回默认值 |
SO_BROADCAST | 允许广播地址发送和接收信息包。只对UDP有效。如何发送和接收广播信息包 | 布尔型整数 |
SO_DONTROUTE | 禁止通过路由器和网关往外发送信息包。这主要是为了安全而用在以太网上UDP通信的一种方法。不管目的地址使用什么IP地址,都可以防止数据离开本地网络 | 布尔型整数 |
SO_KEEPALIVE | 可以使TCP通信的信息包保持连续性。这些信息包可以在没有信息传输的时候,使通信的双方确定连接是保持的 | 布尔型整数 |
SO_OOBINLINE | 可以把收到的不正常数据看成是正常的数据,也就是说会通过一个标准的对recv()的调用来接收这些数据 | 布尔型整数 |
SO_REUSEADDR | 当socket关闭后,本地端用于该socket的端口号立刻就可以被重用。通常来说,只有经过系统定义一段时间后,才能被重用。 | 布尔型整数 |
三次握手
- 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
四次挥手
- 第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
- 第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
- 第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
- 第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。
标志 | 中文名 | 描述 |
---|---|---|
URG | 紧急标志 | 紧急(The urgent pointer) 标志有效。紧急标志置位 |
ACK | 确认标志 | 确认编号(Acknowledgement Number)栏有效。大多数情况下该标志位是置位的. TCP报头内的确认编号栏内包含的确认编号(w+1,Figure:1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。 |
PSH | 推标志 | 该标志置位时,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。 |
RST | 复位标志 | 复位标志有效。用于复位相应的TCP连接。 |
SYN | 同步标志 | 同步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。 |
FIN | 结束标志 | 带有该标志置位的数据包用来结束一个TCP回话,但对应端口仍处于开放状态,准备接收后续数据。 服务端处于监听状态,客户端用于建立连接请求的数据包(IP packet)按照TCP/IP协议堆栈组合成为TCP处理的分段(segment)。 |
高级I / O复用selectors
https://docs.python.org/3/library/selectors.html
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock, mask):
conn, addr = sock.accept() # Should be ready
print('accepted', conn, 'from', addr)
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)
def read(conn, mask):
data = conn.recv(1000) # Should be ready
if data:
print('echoing', repr(data), 'to', conn)
conn.send(data) # Hope it won't block
else:
print('closing', conn)
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
多任务
threading模块
threading模块对象 | 描述 |
---|---|
Thread | 表示一个线程的执行的对象 |
Lock | 锁原语对象(跟thread模块里的锁对象相同) |
RLock | 可重入锁对象。使单线程可以再次获得已经获得了的锁(递归锁定) |
Condition | 条件变量对象能让一个线程停下来,等待其他线程满足了某个“条件”。如状态的改变或值的改变 |
Event | 通用的条件变量。多个线程可以等待某个时间的发生,在事件发生后,所有的线程都被激活 |
Semaphore | 为等待锁的线程提供一个类似“等候室”的结构 |
BoundedSemaphore | 与Semaphore类似,只是它不允许超过初始值 |
Timer | 与thread类似,只是它要等待一段时间后才开始运行 |
start() | 开始线程的执行 |
run() | 定义线程的功能的函数(一般会被子类重写) |
join(timeout=None) | 程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout秒 |
getName() | 返回线程的名字 |
setName(name) | 设置线程的名字 |
isAlive() | 布尔标志,表示这个线程是否还在运行中 |
isDaemon() | 返回线程的daemon标志 |
setDaemon(daemonic) | 把线程的daemon标志设为daemonic(一定要在调用start()函数前调用) |
currentThread() | 返回当前的线程变量 |
enumerate() | 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程 |
activeCount() | 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果 |
线程
# 线程是进程中执行的最小单位
import threading
import time
def saySorry():
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=saySorry)
t.start() #启动线程,即让线程开始执行
重写run方法和线程锁
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 释放锁
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
threads = []
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t in threads:
t.join()
print "Exiting Main Thread"
多进程
# 进程是系统分配资源的最小单位
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print 'Run child process %s (%s)...' % (name, os.getpid())
if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
p = Process(target=run_proc, args=('test',))
print 'Process will start.'
p.start()
# 主进程等待子进程
p.join()
# 守护进程
# p.daemon=True
print 'Process end.'
进程池
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print 'Run task %s (%s)...' % (name, os.getpid())
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print 'Task %s runs %0.2f seconds.' % (name, (end - start))
if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
p = Pool()
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print 'Waiting for all subprocesses done...'
p.close()
p.join()
print 'All subprocesses done.'
各种池
进程
import logging
from multiprocessing import Pool
from multiprocessing import Process,Manager
class Test():
def __init__(self):
self.pool = Pool()
def task(self):
print('func')
def _err(self, ex):
try:
raise ex
except:
logging.exception(ex)
def main(self):
self.pool.apply_async(self.task, error_callback=self._err)
# self.pool.apply_async(self.task)
# self.pool.apply_async(self.task)
# self.pool.apply_async(self.task)
self.pool.close()
self.pool.join()
t = Test()
t.main()
线程
import logging
import time
import threading
from multiprocessing.dummy import Pool # 线程池
# from multiprocessing import Pool # 进程池
def func():
print(threading.current_thread().name)
time.sleep(0.5)
print('func')
# raise Exception('123')
return 'ok'
def func2():
time.sleep(0.3)
print('func2')
def func3():
time.sleep(0.1)
print('func3')
def func4():
time.sleep(0)
print('func4')
p = Pool(5)
# 同步执行
# p.apply(func)
# p.apply(func2)
# p.apply(func3)
# p.apply(func4)
# p.close()
# p.join()
def callback(temp):
print(threading.current_thread().name)
print(temp)
def error_callback(temp):
print(threading.current_thread().name)
try:
raise temp
except:
logging.exception(temp)
print(threading.current_thread().name)
# 异步执行
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)
# p.apply_async(func2)
# p.apply_async(func3)
# p.apply_async(func4)
while True:
time.sleep(0.0001)
p.close()
p.join()
协程
from gevent.pool import Pool
def func():
print('func')
raise Exception('ok')
class Gpool(Pool):
def apply_async(self, func, args=None, kwds=None, callback=None, error_callback=None):
super().apply_async(func, args=None, kwds=None, callback=None)
def cloase(self):
pass
p = Gpool()
p.apply_async(func, error_callback='asdasd')
p.apply_async(func)
p.apply_async(func)
p.apply_async(func)
p.apply_async(func)
p.join()
进程间通信
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print 'Put %s to queue...' % value
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
value = q.get(True)
print 'Get %s from queue.' % value
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
进程池通信
from multiprocessing import Manager,Pool
import os,time,random
def reader(q):
print("reader启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in range(q.qsize()):
print("reader从Queue获取到消息:%s" % q.get(True))
def writer(q):
print("writer启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in "itcast":
q.put(i)
if __name__=="__main__":
print("(%s) start" % os.getpid())
q = Manager().Queue() # 使用Manager中的Queue
po = Pool()
po.apply_async(writer, (q,))
time.sleep(1) # 先让上面的任务向Queue存入数据,然后再让下面的任务开始从中取数据
po.apply_async(reader, (q,))
po.close()
po.join()
print("(%s) End" % os.getpid())
或者from queue import Queue创建队列
另一种多线程
from multiprocessing.dummy import Pool as ThreadPool #线程池
# 开4个 worker,没有参数时默认是 cpu 的核心数
pool = ThreadPool(4)
# 在线程中执行 urllib2.urlopen(url) 并返回执行结果
results2 = pool.map(urllib2.urlopen, urls)
# 打印线程名
print(threading.current_thread().name)
pool.close()
pool.join()
from multiprocessing.dummy import Pool
p=Pool()
# 同步执行
p.apply(func)
# 异步执行
p.apply_async(func,callback=callback ,error_callback=callback_func) # 回调函数不能有耗时操作否则会阻塞
p.close()
p.join()
安全的多线程
import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
# 一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。
# ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。
协程
协程又称微线程,是手动控制的线程
- 协程yield
import time
def work1(): while True: print("----work1---") yield time.sleep(0.5)
def work2(): while True: print("----work2---") yield time.sleep(0.5)
def main(): w1 = work1() w2 = work2() while True: next(w1) next(w2)
if name == "main": main()
- 协程greenlet
```python
from greenlet import greenlet
import time
def test1():
while True:
print "---A--"
gr2.switch()
time.sleep(0.5)
def test2():
while True:
print "---B--"
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
#切换到gr1中运行
gr1.switch()
- 协程gevent
from gevent import monkey import gevent import random import time
有耗时操作时需要
monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
def coroutine_work(coroutine_name): for i in range(10): print(coroutine_name, i) time.sleep(random.random())
gevent.joinall([ gevent.spawn(coroutine_work, "work1"), gevent.spawn(coroutine_work, "work2") ])
- 协程池
import gevent from gevent import monkey monkey.patch_all()
from gevent.pool import Pool as BasePool
class Pool(BasePool):
def apply_async(self, func, args=None, kwds=None, callback=None, error_callback=None):
super().apply_async(func, args=args, kwds=kwds, callback=callback)
def close(self):
pass
def sleep(self, n):
gevent.sleep(n)
---
#### 正则
匹配单个 | 功能
---|---
. | 匹配任意1个字符(除了\n)
[ ] | 匹配[ ]中列举的字符
\d | 匹配数字,即0-9
\D | 匹配非数字,即不是数字
\s | 匹配空白,即 空格,tab键
\S | 匹配非空白
\w | 匹配单词字符,即a-z、A-Z、0-9、_
\W | 匹配非单词字符
匹配多个 | 功能
---|---
* | 匹配前一个字符出现0次或者无限次,即可有可无
+ | 匹配前一个字符出现1次或者无限次,即至少有1次
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} | 匹配前一个字符出现m次
{m,n} | 匹配前一个字符出现从m到n次
开头结尾 | 功能
---|---
^ |匹配字符串开头
$ | 匹配字符串结尾
分组 | 功能
---|---
\| | 匹配左右任意一个表达式
(ab) | 将括号中字符作为一个分组
\num | 引用分组num匹配到的字符串
(?P<name>) | 分组起别名
(?P=name) | 引用别名为name分组匹配到的字符串
标志位 | 描述
---|---
re.I | 使匹配对大小写不敏感
re.L | 做本地化识别(locale-aware)匹配
re.M | 多行匹配,影响 ^ 和 $
re.S | 使 . 匹配包括换行在内的所有字符
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
##### 正则函数
函数名 | 描述
---|---
re.match(pattern, string, flags=0) | 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.search(pattern, string, flags=0) | 扫描整个字符串并返回第一个成功的匹配。
re.sub(pattern, repl, string, count=0, flags=0) | 用于替换字符串中的匹配项。
re.findall(pattern,string[, pos[, endpos]]) | 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
re.finditer(pattern, string, flags=0) | 和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
re.split(pattern, string[, maxsplit=0, flags=0]) | split 方法按照能够匹配的子串将字符串分割后返回列表
group(num=0)/groups | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。/返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
re.compile(pattern[, flags]) | 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象。
==参数说明==
参数 | 描述
---|---
pattern | 匹配的正则表达式
string | 要匹配的字符串。
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志
repl | 替换的字符串,也可为一个函数。
count | 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
pos | 可选参数,指定字符串的起始位置,默认为 0。
endpos | 可选参数,指定字符串的结束位置,默认为字符串的长度。
maxsplit | 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
正则分组替换
re.sub(r'(?P<p>[\s=]).*',r'\g<p>'+'127.0.0.1',' 128')
如果没有数字
re.sub(r'([\s=]).*',r'\1asd',' 128')
---
## 生成验证码
def verifycode(request): # 引入绘图模块 from PIL import Image, ImageDraw, ImageFont # 引入随机函数模块 import random # 定义变量,用于画面的背景色、宽、高 bgcolor = (random.randrange(20, 100), random.randrange( 20, 100), 255) width = 100 height = 25 # 创建画面对象 im = Image.new('RGB', (width, height), bgcolor) # 创建画笔对象 draw = ImageDraw.Draw(im) # 调用画笔的point()函数绘制噪点 for i in range(0, 100): xy = (random.randrange(0, width), random.randrange(0, height)) fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) draw.point(xy, fill=fill) # 定义验证码的备选值 str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' # 随机选取4个值作为验证码 rand_str = '' for i in range(0, 4): rand_str += str1[random.randrange(0, len(str1))] # 构造字体对象 font = ImageFont.truetype('Monaco.ttf', 18) # 构造字体颜色 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) # 绘制4个字 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) # 释放画笔 del draw # 存入session,用于做进一步验证 # request.session['verifycode'] = rand_str # 内存文件操作 import io buf = io.StringIO() # 将图片保存在内存中,文件类型为png im.save(buf, 'png') # 将内存中的图片数据返回给客户端,MIME类型为图片png return HttpResponse(buf.getvalue(), 'image/png')
---
## python的内存管理机制
先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲
(1)垃圾回收
(2)引用计数
(3)内存池机制
一、垃圾回收:
python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。
二、引用计数:
Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。
三、内存池机制
Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作,
第0层是C中的malloc,free等内存分配和释放函数进行操作;
第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;
第3层是最上层,也就是我们对Python对象的直接操作;
在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片. Python 在这里主要干的工作有:
如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.
这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.
经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free 释放掉.以便下次使用.对于简单的Python对象,例如数值、字符串,元组(tuple不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同
---
#### python包自己安装
必须有__init__文件
setup.py
from os.path import dirname, join from pip.req import parse_requirements
包管理工具
from setuptools import ( find_packages, setup )
with open(join(dirname(file), './VERSION.txt'), 'rb') as f: version = f.read().decode('ascii').strip() ''' 作为一个合格的模块,应该有版本号 '''
setup( name='mini_scrapy', # 模块名 version=version, # 版本号 description='A mini spider frameword, like scrapy', # 描述 packages=find_packages(exclude=[]), # 包含目录中所有包,exclude=['哪些文件除外'] author='WangJY', # 作者 author_email='wangjunyan456@gmail.com', # 作者邮箱 license='Apache License v2', package_data={'': ['.']}, # {'包名': ['正则']} url='#', install_requires=[str(ir.req) for ir in parse_requirements("requirements.txt",session=False)], # 所需的运行环境 zip_safe=False, classifiers=[ 'Programming Language :: Python', 'Operating System :: Microsoft :: Windows', 'Operating System :: Unix', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', ], )
requirements.txt
requests>=2.18.4 six>=1.11.0 w3lib>=1.18.0 redis>=2.10.6 gevent>=1.2.2
VERSION.txt
1.0
---
使用ipython保存到文件
%hist -f 'filename.py'
import time import datetime
#计算两个日期相差天数,自定义函数名,和两个日期的变量名。 def Caltime(date1,date2): #%Y-%m-%d为日期格式,其中的-可以用其他代替或者不写,但是要统一,同理后面的时分秒也一样;可以只计算日期,不计算时间。 #date1=time.strptime(date1,"%Y-%m-%d %H:%M:%S") #date2=time.strptime(date2,"%Y-%m-%d %H:%M:%S") date1=time.strptime(date1,"%Y-%m-%d") date2=time.strptime(date2,"%Y-%m-%d") #根据上面需要计算日期还是日期时间,来确定需要几个数组段。下标0表示年,小标1表示月,依次类推... #date1=datetime.datetime(date1[0],date1[1],date1[2],date1[3],date1[4],date1[5]) #date2=datetime.datetime(date2[0],date2[1],date2[2],date2[3],date2[4],date2[5]) date1=datetime.datetime(date1[0],date1[1],date1[2]) date2=datetime.datetime(date2[0],date2[1],date2[2]) #返回两个变量相差的值,就是相差天数 return date2-date1
## 描述符
任何实现了__get__(), __set__(), 或者 __delete__()方法的对象就是描述符。一个class的属性是一个描述符的时候,对这个属性的访问会触发特定的绑定行为。一般的我们使用a.b的方式访问,修改和删除属性,它通过查找class的字典来访问属性b,当时如果b是一个描述符,那么get,set和delete相关的描述符方法会被调用。理解描述符是深入理解python的关键,因为描述符是很多特性实现的基础,比如:方法,函数,属性,类方法,静态方法还有对父类方法的引用。详细的说明请看描述符的实现。
描述符协议:
get(self, instance, owner) --> return value set(self, instance, value) delete(self, instance)
- 实现 get 和 set 方法,称为 data descriptor。
- 仅有 get 方法的,称为 non-data descriptor。
- get 对 owner_class、owner_instance 访问有效。
- set、delete 仅对 owner_instance 访问有效。
class Typed: def init(self, key, expected_type): self.key = key self.expected_type = expected_type
def __get__(self, instance, owner):
print('get方法')
# print('instance参数【%s】' %instance)
# print('owner参数【%s】' %owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
# print('instance参数【%s】' % instance)
# print('value参数【%s】' % value)
# print('====>',self)
if not isinstance(value, self.expected_type):
# print('你传入的类型不是字符串,错误')
# return
raise TypeError('%s 传入的类型不是%s' % (self.key, self.expected_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('delete方法')
# print('instance参数【%s】' % instance)
instance.__dict__.pop(self.key)
class People: name = Typed('name', str) # t1.set() self.set() # 类的属性被代理 age=Typed('age',int) #t1.set() self.set()
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
###### 解决粘包
Server端
from socketserver import ThreadingTCPServer, StreamRequestHandler import struct import subprocess
class MyRequestHandler(StreamRequestHandler):
def handle(self):
while True:
print("connect from:", self.client_address)
cmd = bytes.decode(self.request.recv(1024))
if not cmd: break res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() if err: back_msg = err else: back_msg = res.stdout.read()
self.request.send(struct.pack("i", len(back_msg)))
self.request.send(back_msg)
if name == 'main':
tcp_Server = ThreadingTCPServer(("127.0.0.1", 8081), MyRequestHandler)
tcp_Server.allow_reuse_address = True
tcp_Server.serve_forever()
#Client端
import socket import struct
host = "127.0.0.1" port = 8081
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port))
while True: cmd = input(">>>>").strip() if not cmd: continue s.send(cmd.encode("utf-8"))
package_len = s.recv(4)
package_size = struct.unpack("i",package_len)[0]
recv_size = 0
recv_bytes = b""
while recv_size < package_size:
res = s.recv(1024)
recv_bytes += res
recv_size += len(res)
print(recv_bytes.decode("utf-8"))
s.close()
### python3.6 新特性
https://docs.python.org/3.6/whatsnew/3.6.html#pep-498-formatted-string-literals
#### 格式化字符串文字
格式化的字符串文字以前缀'f'为的格式字符串为前缀,并且与之接受的格式字符串类似str.format()。它们包含由花括号包围的替换字段。替换字段是表达式,在运行时进行评估,然后使用format()协议进行格式化 :
name = "Fred" f"He said his name is {name}." 'He said his name is Fred.' width = 10 precision = 4 value = decimal.Decimal("12.34567") f"result: {value:{width}.{precision}}" # nested fields 'result: 12.35'
#### 变量注释的语法
PEP 484引入了函数参数类型注释的标准,即类型提示。此PEP为Python添加语法以注释变量类型,包括类变量和实例变量:
primes: List[int] = []
captain: str # Note: no initial value!
class Starship: stats: Dict[str, int] = {}
与函数注释一样,Python解释器不会将任何特定含义附加到变量注释,只将它们存储在__annotations__类或模块的 属性中。
与静态类型语言中的变量声明相比,注释语法的目标是提供一种通过抽象语法树和__annotations__属性为第三方工具和库指定结构化类型元数据的简便方法。
#### 数字文字中的下划线
PEP 515增加了在数字文字中使用下划线的能力,以提高可读性。例如:
1_000_000_000_000_000 1000000000000000 0x_FF_FF_FF_FF 4294967295
#### 异步发生器
PEP 492引入了 对Python 3.5的本机协同程序和async/await语法的支持。Python的3.5实现的一个显着的限制是,它是不可能使用await,并yield在同一个函数体。在Python 3.6中,这个限制已被解除,从而可以定义异步生成器:
async def ticker(delay, to): """Yield numbers from 0 to to every delay seconds.""" for i in range(to): yield i await asyncio.sleep(delay)
#### 异步理解
PEP 530增加了对list,set,dict comprehensions和generator表达式中使用的支持:async for
result = [i async for i in aiter() if i % 2]
此外,await各种理解都支持表达式:
result = [await fun() for fun in funcs if await condition()]
#### 更简单的类创建自定义
现在可以在不使用元类的情况下自定义子类创建。__init_subclass__每当创建新的子类时,都会在基类上调用新的classmethod:
class PluginBase: subclasses = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.subclasses.append(cls)
class Plugin1(PluginBase): pass
class Plugin2(PluginBase): pass
为了允许零参数super()调用从__init_subclass__()实现中正确工作 ,自定义元类必须确保将新的__classcell__命名空间条目传播到 type.__new__(如创建类对象中所述)。
#### 描述符协议增强
PEP 487扩展了描述符协议以包括新的可选 __set_name__()方法。每当定义新类时,将在定义中包含的所有描述符上调用新方法,为它们提供对所定义的类的引用以及在类命名空间中给予描述符的名称。换句话说,描述符的实例现在可以知道所有者类中描述符的属性名称:
class IntField: def get(self, instance, owner): return instance.dict[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError(f'expecting integer in {self.name}')
instance.__dict__[self.name] = value
# this is the new initializer:
def __set_name__(self, owner, name):
self.name = name
class Model: int_field = IntField()
#### 添加文件系统路径协议
文件系统路径历来被表示为str 或bytes对象。这导致编写在文件系统路径上运行的代码的人认为这些对象只是这两种类型中的一种(int表示文件描述符不计算为不是文件路径)。不幸的是,这种假设阻止了文件系统路径的替代对象表示,例如pathlib使用预先存在的代码,包括Python的标准库。
为了解决这种情况,os.PathLike已经定义了一个新的接口 。通过实现该 __fspath__()方法,对象表示它表示路径。然后对象可以提供一个文件系统路径的低级表示作为一个str或 bytes对象。这意味着一个对象被认为是 路径样如果它实现 os.PathLike或者是str或bytes对象,表示一个文件系统路径。代码可以使用os.fspath(),, os.fsdecode()或os.fsencode()显式获取路径类对象的 str和/或bytes表示。
内置open()函数已更新为接受 os.PathLike对象,os与os.path模块中的所有相关函数 以及标准库中的大多数其他函数和类一样。本os.DirEntry类和相关类pathlib也进行了更新来实现os.PathLike。
希望更新用于在文件系统路径上操作的基本功能将导致第三方代码隐式支持所有类似路径的对象而不需要任何代码更改,或者至少是非常小的os.fspath()代码(例如,在操作之前调用 代码的开头)在路径上的对象)。
以下是一些示例,说明新接口如何 pathlib.Path使用预先存在的代码更轻松,更透明地使用:
import pathlib with open(pathlib.Path("README")) as f: ... contents = f.read() ... import os.path os.path.splitext(pathlib.Path("some_file.txt")) ('some_file', '.txt') os.path.join("/a/b", pathlib.Path("c")) '/a/b/c' import os os.fspath(pathlib.Path("some_file.txt")) 'some_file.txt'
#### 当地时间消歧
在大多数世界地区,曾经并且有时会将本地时钟移回。在这些时间,引入间隔,其中本地时钟在同一天显示两次相同的时间。在这些情况下,本地时钟上显示的信息(或存储在Python日期时间实例中)不足以识别特定时刻。
PEP 495将新的 fold属性添加到实例 datetime.datetime和datetime.time类中,以区分当地时间相同的两个时刻:
u0 = datetime(2016, 11, 6, 4, tzinfo=timezone.utc) for i in range(4): ... u = u0 + i*HOUR ... t = u.astimezone(Eastern) ... print(u.time(), 'UTC =', t.time(), t.tzname(), t.fold) ... 04:00:00 UTC = 00:00:00 EDT 0 05:00:00 UTC = 01:00:00 EDT 0 06:00:00 UTC = 01:00:00 EST 1 07:00:00 UTC = 02:00:00 EST 0
#### concurrent.futures- 启动并行任务
https://docs.python.org/3.6/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor
类concurrent.futures.Executor
一个抽象类,提供异步执行调用的方法。它不应该直接使用,而是通过其具体的子类。
submit(fn,* args,** kwargs ) 将可调用的fn调度为执行, 并返回表示可调用执行的对象。fn(args *kwargs)Future
with ThreadPoolExecutor(max_workers=1) as executor: future = executor.submit(pow, 323, 1235) print(future.result())
map(func,* iterables,timeout = None,chunksize = 1 )
与以下类似:map(func, *iterables)
- 在iterables收集立即而不是懒洋洋地;
- func以异步方式执行,并且可以同时对func进行多次调用 。
返回的迭代器引发一个concurrent.futures.TimeoutError if __next__()被调用,结果在从原始调用到超时秒后不可用Executor.map()。 timeout可以是int或float。如果未指定 超时None,则等待时间没有限制。
如果func调用引发异常,那么当从迭代器中检索其值时,将引发该异常。
在使用时ProcessPoolExecutor,此方法将可迭代组件 切换为多个块,并将其作为单独的任务提交到池中。可以通过将chunksize设置为正整数来指定这些块的(近似)大小。对于很长的iterables,采用大值CHUNKSIZE可以显著改善性能相比的1.默认大小 ThreadPoolExecutor,CHUNKSIZE没有效果。
shutdown(wait = True )
向执行者发出信号,表示当目前待处理的期货执行完毕时,它应该释放它正在使用的任何资源。关机后拨打电话Executor.submit()并拨打电话 。Executor.map()RuntimeError
如果等待,True那么在所有待处理的期货完成执行并且与执行程序关联的资源已被释放之前,此方法将不会返回。如果等待,False则此方法将立即返回,并且当执行所有待处理的期货时,将释放与执行程序关联的资源。无论wait的值如何,整个Python程序都不会退出,直到所有待处理的期货都执行完毕。
如果使用with语句,则可以避免必须显式调用此方法 ,该语句将关闭Executor (等待,就像Executor.shutdown()使用wait set 调用一样True):
import shutil with ThreadPoolExecutor(max_workers=4) as e: e.submit(shutil.copy, 'src1.txt', 'dest1.txt') e.submit(shutil.copy, 'src2.txt', 'dest2.txt') e.submit(shutil.copy, 'src3.txt', 'dest3.txt') e.submit(shutil.copy, 'src4.txt', 'dest4.txt')
ThreadPoolExecutor是一个Executor子类,它使用一个线程池来异步执行调用。
当与a关联的callable Future等待另一个的结果时,可能会发生死锁Future。例如:
import time def wait_on_b(): time.sleep(5) print(b.result()) # b will never complete because it is waiting on a. return 5
def wait_on_a(): time.sleep(5) print(a.result()) # a will never complete because it is waiting on b. return 6
executor = ThreadPoolExecutor(max_workers=2) a = executor.submit(wait_on_b) b = executor.submit(wait_on_a)
和
def wait_on_future(): f = executor.submit(pow, 5, 2) # This will never complete because there is only one worker thread and # it is executing this function. print(f.result())
executor = ThreadPoolExecutor(max_workers=1) executor.submit(wait_on_future)
class concurrent.futures.ThreadPoolExecutor(max_workers = None,thread_name_prefix ='' )
Executor使用最多max_workers 线程池的子类,以异步方式执行调用。
initializer是一个可选的callable,在每个工作线程的开头调用; initargs是传递给初始化器的参数元组。如果初始化程序引发异常,则所有当前挂起的作业都将引发BrokenThreadPool,以及向池中提交更多作业的任何尝试。
改变在3.5版本中:如果max_workers是None或者没有给出,将默认为机器上的处理器,乘以数量5,假设ThreadPoolExecutor经常使用重叠的I / O,而不是CPU的工作,工人的数量应比工人数量ProcessPoolExecutor。
在3.6版本的新功能:该thread_name_prefix加入参数,允许用户控制threading.Thread由池更容易调试创建工作线程的名字。
##### ThreadPoolExecutor示例
import concurrent.futures import urllib.request
URLS = ['http://www.foxnews.com/', 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', 'http://some-made-up-domain.com/']
Retrieve a single page and report the URL and contents
def load_url(url, timeout): with urllib.request.urlopen(url, timeout=timeout) as conn: return conn.read()
We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # Start the load operations and mark each future with its URL future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: data = future.result() except Exception as exc: print('%r generated an exception: %s' % (url, exc)) else: print('%r page is %d bytes' % (url, len(data)))
##### ProcessPoolExecutor
本ProcessPoolExecutor类是Executor使用的过程池异步执行调用子类。 ProcessPoolExecutor使用该multiprocessing模块,它允许它侧向全局解释器锁定,但也意味着只能执行和返回可选对象。
该__main__模块必须可由工作程序子进程导入。这意味着ProcessPoolExecutor在交互式解释器中不起作用。
从提交给a的可调用调用Executor或Future方法ProcessPoolExecutor将导致死锁。
class concurrent.futures.ProcessPoolExecutor(max_workers = None )
Executor使用最多max_workers进程池异步执行调用的子类。如果max_workers是None或者没有给出,将默认为机器上的处理器数量。如果max_workers低于或等于0,则将ValueError 引发a。
版本3.3中更改:当其中一个工作进程突然终止时, BrokenProcessPool现在会引发错误。以前,行为未定义,但执行者或其未来的操作通常会冻结或死锁。
##### ProcessPoolExecutor示例
import concurrent.futures import math
PRIMES = [ 112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419]
def is_prime(n): if n % 2 == 0: return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
def main(): with concurrent.futures.ProcessPoolExecutor() as executor: for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)): print('%d is prime: %s' % (number, prime))
if name == 'main': main() ```