此内容为之前学习python时做的知识笔记
人生苦短,我用python
以守护进程运行python脚本,python test1.py &
1.基础知识1.0 包packagepython package需要有一个名为init.py的文件,不然就是普通的package,则无法import package下的模块。可以在init.py文件里写入要被使用的模块,这样import package时,系统会直接去init.py里面寻找模块或者函数。
- 当导入一个package时,python解释器会首先在内置模块中寻找,若没有则在sys.path列表中寻找。参考
python变量名只能包含以下字符:大小写字母、数字、下划线(_),名称不允许以数字开头。并且以下划线开头的名字有特殊含义。
1.2 可变对象与不可变对象- 可变对象:列表list、字典dict、集合set
- 不可变对象:数值(int,float)、字符串(str)、元组(tuple)
- 列表
创建列表:a=[],a=list()
赋值:a=[],b=a 此时,a,b共享同一个对象。
复制(新表):a=[],b=a.copy(),c=list(a),d=a[:] 此时b,c,d是新的对象,不共享,和a没有任何关系。属于浅复制;浅复制只复制一层(外层)
- 元组
创建元组:a=(),a=tuple() a=(1,)等价于a=1,
元组元素不可更改
- 字典
创建字典:a={},a=dict()
复制:copy()
赋值:=
- 集合
创建集合:a=set(),a={1}
集合运算:交集(&),并集(|),差集(-)
Python有两种格式化方式,习惯称为旧式和新式;这两种方式在python2和python3中都适用。
- 使用%的旧式格式化
旧式格式化的形式为:string % data,其中string包含的是待插值序列。
>>> '%s'%4.12
'4.12'
>>> '%f'%4.12
'4.120000'
>>> "my name is %s,age is %d "%('ss',14)
'my name is ss,age is 14 '
>>> "d f s"%(12,11,'dad') #设置最小域宽度为10格字符,左侧用空格补充
' 12 11.000000 dad'
>>> "%-10d %-10f %-10s"%(12,11,'dad') #左对齐
'12 11.000000 dad '
>>> '%.4f %.3d'%(12.13131,11) #数据截断,设置最大字符宽度
'12.1313 011'
- 使用{}和format的新式格式化
>>> '{}{}'.format(12,13)
'1213'
>>> '{1}{0}'.format(12,13) #指定插入的顺序,参数从0开始。
'1312'
>>> '{m}{n}'.format(n=12,m=13) #命名变量参数
'1312'
>>> '{1:d} {0:f}'.format(12,13) #使用:实现格式化类型
'13 12.000000'
>>> '{1:<4d} {0:<5f}'.format(12,13) #左对齐<,右对齐>,居中^
'13 12.000000'
>>> '{1:^4d} {0:<5.3f}'.format(12,13) #精度和旧式一样,但也有不同
' 13 12.000'
>>> '{:^4.3}'.format(12) #新格式中无法对整数设定精度
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
#单行注释1
print(123)#单行注释2
#多行注释1
#ddd
#ddd
#ddd
'''
多行注释2
ddd
'''
在python3中,print是函数,使用 print('helloworld')
不换行输出,print("hello",end="")
print("world") 输出:helloworld
在python2中,print是关键字,print "helloworld"
不换行输出,pring "hello",
print "world" 输出:hello world (以空格分割)
--------python2
>>> a=input() #会做计算处理
12
>>> print a,type(a)
12 <type 'int'>
>>> a=raw_input() #对输入都以字符串处理
12
>>> print a,type(a)
12 <type 'str'>
>>>
--------python3
>>> a=input()
12
>>> print(a)
12
>>> print(type(a)) #所有输入都作为字符串处理
<class 'str'>
>>>
-----------python2
>>> print 5/2 #向下取整
2
-----------python3
>>> print (5/2) #默认进行浮点数除法
2.5
>>> print (5//2) #取模
2
-------------python2
>>> print range(4) #返回列表
[0, 1, 2, 3]
------------python3
>>> print(range(4)) #返回range对象
range(0, 4)
#循环访问py2和py3基本一样
python3表示字符串的两种类型:bytes和str,前者的实例包含原始的8位值(一个字节),后者实例包含Unicode字符。
python2表示字符串的两种类型:unicode和str,前者包含Unicode字符,后者包含原始的8位值。
二进制转化为Unicode字符,使用decode;Unicode字符转二进制,使用encode。
- python2
>>> x = 'my precious'
>>> dummy = [x for x in 'ABC']
>>> x
'C'
>>> dummy
['A', 'B', 'C']
- python3
>>> x = 'my precious'
>>> dummy = [x for x in 'ABC']
>>> x
'my precious'
>>> dummy
['A', 'B', 'C']
python2中,在列表推导中同名变量的赋值可能会影响上下文环境;而在python3中,都有自己的局部作用域。使用生成器则不会出现这种变量泄漏的问题。
1.6.7 importpython2默认是按照相对路径导入模块和包,python3默认则是按照绝对路径导入。python2引入一个module时会先在当前目录搜索,然后再去搜索路径(sys.path)搜索;而python3直接在搜索路径搜索,为了导入,使用显式路径导入。
Python2.x 缺省为相对路径导入,Python3.x 缺省为绝对路径导入。绝对导入可以避免导入子包覆盖掉标准库模块(由于名字相同,发生冲突)。如果在 Python2.x 中要默认使用绝对导入,可以在文件开头加入如下语句:
from __future__ import absolute_import
这句 import 并不是指将所有的导入视为绝对导入,而是指禁用 implicit relative import(隐式相对导入), 但并不会禁掉 explicit relative import(显示相对导入)。
from .foo import Foo #python2、3都适用
from .bar import Bar #python2、3都适用
#from mdl.foo import Foo #python2、3都适用
#from mdl.bar import Bar #python2、3都适用
#from foo import Foo #python3不适用
#from bar import Bar #python3不适用
py2 : except exc, varpy3 : except exc as var,使用 as 作为关键词
1.6.9 不等运算符Python 2.x中不等于有两种写法 != 和 <>Python 3.x中去掉了<>, 只有!=一种写法
1.6.10 dict方法py2中dict的keys()、items()、values() 是列表,iteritems()返回迭代器py3中dict的keys()、items()、values() 是类或迭代器,非基础数据类型,执行json的加解密时,需要注意py3中iteritems() 和 viewitems() 这两个方法都已经废除了,而items()得到的结果是和py2里面viewitems()一致的。在py3里用items()替换iteritems() ,可以用于for来循环遍历
1.6.11 数据类型在Python2中long是比int取值范围更大的整数,Python3中取消了long类型,int的取值范围扩大到之前的long类型范围。python3版本中增加了bytes类型
1.6.12 重载当我们想对python中原有的模块进行覆盖,又不希望退出当前的程序,就需要用到重载的概念
# python2 内置函数
reload(module)
# python3
from importlib import reload
reload(module)
- pip freeze > requirements.txt 导出项目的依赖。
- pip install -r requirements.txt 在项目中一次性安装依赖
- pip install virtualenv
- 进入到项目目录,执行virtualenv --no-site-packages venv(虚拟环境到名字) no-site-packages意思是不复制系统到安装包,得到的是纯净的环境
- 激活虚拟环境 source venv/bin/activate。进入了venv环境,pip包时只安装到该环境下,系统python环境不受任何影响(windows系统venv\Scripts\activate),激活后Python 解释器的路径就被添加进PATH 中。
- 退出虚拟环境 deactivate,回到系统python环境
python3内置了用于创建虚拟环境的venv,可直接使用python3 -m venv .venv(Linux下)
py -3 -m venv .venv
virtualenv --python=/usr/local/bin/python3 env3 #创建指定python版本的虚拟环境 --python 指定python解释器
1.9.代码风格- 折叠长行的首选方法是在小括号,中括号,大括号中使用Python隐式换行。长行可以在表达式外面使用小括号来变成多行。连续行使用反斜杠更好。
- 和None比较用is
- 缩进使用4个空格,而不要用tab
- 不要在for和while后面用else
- 为变量赋值时,赋值符号的左右侧应该各自写上一个空格。
- 文件中的函数和类之间应该用两个空行隔开。
- 在同一个类中,各方法之间应该用一个空行隔开。
python2中既有新式类又有旧式类,并且默认为经典类,只有显示继承object才是新式类。
class a(Object):pass #新式类写法
class a():pass #经典类(旧式类)写法
class a:pass #经典类写法
类.mro() #查看解析顺序列表,只有新式类有该属性。
----------------------------------------------------------------------
class a():
pass
c=a()
print dir(c)
---------------------------------out
['__doc__', '__module__']
class a(object):
pass
c=a()
print dir(c)
---------------------------- ---out
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
*:在编写python类时,尽量使用新式类,其包含更多属性。
python3中只有新式类,默认式新式类,不必显式继承object。新式类增加了slots内置属性, 可以把实例属性的种类锁定到slots规定的范围之中。
如果类是经典类,在多继承的情况下,会按照深度优先方式查找;如果类是新式类,在多继承的情况下,会按照广度优先方式查找;
1.11.python序列化什么叫序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。json是可以在不同语言之间交换数据的,而pickle只在python之间使用。json只能序列化最基本的数据类型,而pickle可以序列化所有的数据类型,包括类,函数都可以序列化。
序列化的目的:
- 以某种存储形式使自定义对象持久化。
- 将对象从一个地方传递到另一个地方。
- 使程序更具维护性。
用于字符串 和 python数据类型间进行转换
Python |
JSON |
dict |
object |
list, tuple |
array |
str, unicode |
string |
int, long, float |
number |
True |
true |
False |
false |
None |
null |
JSON |
Python |
object |
dict |
array |
list |
string |
unicode |
number (int) |
int, long |
number (real) |
float |
true |
True |
false |
False |
null |
None |
-----------------------------loads和dumps---------------------------
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json转换完的字符串类型的字典中的字符串是由""表示的
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
-------------------------load和dump----------------------------
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2
用于python特有的类型 和 python的数据类型间进行转换。pickle操作文件时,需要以二进制的方式操作。
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) #一串二进制内容
dic2 = pickle.loads(str_dic)
print(dic2) #字典
import time
struct_time = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f) #f.write(pickle.dumps(struct_time))
f.close()
f = open('pickle_file','rb')
struct_time2 = pickle.load(f) #struct_time2=pickle.loads(f.read())
print(struct_time2.tm_year)
如果目标对象是基本数据类型,则不会执行转换方法
import json
class Info(object):
def __init__(self,name,age):
# super().__init__()
self.name=name
self.age=age
info=Info("selfeasy",12)
#由于json不支持将对象转为为序列化对象,所以需要做转换处理,实现default方法
'''两种转换方式
1. 实现default参数所指定的方法
2. 继承JSONEncoder,并实现default方法
'''
# 1. 实现default方法, 当反序列化时,为了保持原来的目标对象,需要实现object_hook所指向的函数方法
def makeJson(obj):
return dict(name=obj.name,age=obj.age)
def load_Json(obj):
return Info(obj['name'], obj['age'])
a=json.dumps(info, default=makeJson)
print(a)
print(json.loads(a,object_hook=load_Json))
# 2.继承JSONEncoder,实现default方法
class JsonMake(json.JSONEncoder):
def default(self, o):
if isinstance(o,Info):
return dict(name=o.name,age=o.age)
return super().default(o)
a=json.dumps(info, cls=JsonMake)
print(a)
print(json.loads(a,object_hook=load_Json))
在动态语言中,不去改变源码而对功能进行追加和变更,是在程序运行的过程中去修改。1.追加功能 2.功能变更 3.修正程序错误4.增加钩子,在执行某个方法的同时执行一些其他的处理,如打印日志,实现AOP等。
class XiaoMing(object):
def favorite(self):
print "apple"
class God(object):
@classmethod
def new_xiaoming_favorite(cls):
print "banana"
@classmethod
def monkey_patch(cls):
XiaoMing.favorite = cls.new_xiaoming_favorite
God.monkey_patch()
xiaoming = XiaoMing()
xiaoming.favorite()
>> banana
上下文管理器是一个对象,为操作提供了额外的上下文消息,以一种优雅的方式将额外的处理封装起来。如果一个类实现了__enter__和__exit__方法则表明该类的实例是一个上下文管理器。上下文管理器通常和with搭配使用。实现上下文管理器的两种方式:类和装饰器
- 类实现上下文管理器
class context(object):
def __init__(self):
print ('上下文管理器初始化')
def __enter__(self):
print("上下文管理器开始执行")
return self
def __exit__(self,exec_type, exec_value, exec_traceback):
print ("上下文执行结束")
def operator(self):
print (1/2)
with context() as obj:
obj.operator()
--------------------------------out
上下文管理器初始化
上下文管理器开始执行
0.5
上下文执行结束
备注 :当operator改为1/0时,程序执行后抛出异常;但是当在exit方法中返回True时(默认为False),程序不会报错,因为结果返回true就表示告诉python解释器,异常已捕获并解决,不需要往外抛了。
- 装饰器实现上下文管理器可以不用写一个类来实现上下文管理器,类的实现过于繁杂。python提供了一个装饰器,只需按照它的协议来实现函数内容,即可以将该函数对象变成一个上下文管理器。
from contextlib import contextmanager
from traceback import format_exc
@contextmanager
def context(a,b):
print ("上下文管理器开始运行") #enter方法
f=a/b
try:
yield f
except Exception:
print ("处理异常")
finally:
print("finally")
with context(1,2) as f:
print (123)
print(f)
----------------------------------out
上下文管理器开始运行
123
0.5
finally
备注:try之前的代码会在装饰器的__enter__方法中执行;当执行到yield时,它的产出值会作为__enter__的返回值,赋值给as后的变量。当with块的代码执行完成后,上下文管理器会在yield处恢复,继续执行yield后的代码,后面的代码在装饰器的__exit__方法中被调用。当程序发生异常时,后面的代码不会执行(包括finally代码)
上下文管理器类与@contextmanager中最大的区别在于对异常的处理。以类的方式实现的上下文管理器,在引发异常时,exit方法内的代码仍会正常执行;而以生成器函数实现的上下文管理器,在引发异常时,exit方法会将异常传递给生成器,如果生成器无法正确处理异常,则yield之后的代码不会执行。
1.14. 可散列的数据类型如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现 __hash__() 方法。另外可散列对象还要有 __eq__() 方法,这样才能跟其他键做比较。如果两个可散列对象是相等的,那么它们的散列值一定是一样的。原子不可变数据类型(str、bytes 和数值类型)都是可散列类型。
1.15. Python 运行时
python -m xxx #相当于import,当作模块运行,当前脚本路径不会加入到sys.path中。
python xxx.py #直接运行,当前脚本路径会加入到sys.path中。
python -m site #显示sys.path的值内容,即python搜索模块的目录
许多运算符都有原地操作,如add方法对应的原地操作是iadd。python中的运算符和operator模块中的函数是对应的
- 不可变类型的目标
对于不可变的目标如字符串、数字、元组等,当调用一个原地方法是,分两步执行,运算和赋值。当调用原地函数时,只执行运算嘛,不执行赋值操作。如下:
>>> import operator
>>> a="hello"
>>> operator.iadd(a, ' world')#若要更新变量,则需要执行赋值操作,即a=operator.iadd(a, ' world')
'hello world'
>>> a
'hello'
- 可变类型的目标对于可变的目标,如列表、字典,原地方法将执行更新,因此不需要后续赋值操作。如下:
>>> import operator
>>> s = ['h', 'e', 'l', 'l', 'o']
>>> iadd(s, [' ', 'w', 'o', 'r', 'l', 'd'])
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
>>> s
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
0. python xxx.py 直接运行
1. python -m xxx.py当作模块执行,相当于import
2. python -c 当作命令,脚本执行
import sys
from pprint import pprint
pprint(sys.path)
python -c "import sys;print sys.path"
python -m site
python -m pydoc -p 8180 #开启本地http服务
正则表达式re中就用到了转义
当字符串中使用到特殊字符时,有时候我们不想让其发生转义,而想原样式输出,我们可以使用r字符来定义原始字符串。如下:
str = 'Python\nJava'
print(str)
# out
Python
Java
str = r'Python\nJava'
print(str)
# out
Python\nJava
- 普通的package和python packae
错误分析</strong>:from package import xxx 时,package无法被识别为python package
解决办法:在package下新建__init__.py即可,此时package被视为python package
- 循环导入
from a inport b # module a
from b import a # module b
解决办法:
- 在模块的最后使用import语句。
- 在函数内导入模块(即使用到该模块内容的函数内部)