以守护进程运行python脚本,python test1.py &
1.基础知识
1.0 包package
python package需要有一个名为__init__.py的文件,不然就是普通的package,则无法import package下的模块。可以在__init__.py文件里写入要被使用的模块,这样import package时,系统会直接去__init__.py里面寻找模块或者函数。
- 当导入一个package时,python解释器会首先在内置模块中寻找,若没有则在sys.path列表中寻找。参考
1.1 变量命名规则
python变量名只能包含以下字符:大小写字母、数字、下划线(_),名称不允许以数字开头。并且以下划线开头的名字有特殊含义。
1.2 可变对象与不可变对象
- 可变对象:列表list、字典dict、集合set
- 不可变对象:数值(int,float)、字符串(str)、元组(tuple)
1.3python容器
- 列表
创建列表: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}
集合运算:交集(&),并集(|),差集(-)
1.4 格式化
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 '
>>> "%10d %10f %10s"%(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.5 代码注释
#单行注释1
print(123)#单行注释2
#多行注释1
#ddd
#ddd
#ddd
'''
多行注释2
ddd
'''
1.6 python2 VS python3
1.6.1 print
在python3中,print是函数,使用 print('helloworld')
不换行输出,print("hello",end="")
print("world") 输出:helloworld
在python2中,print是关键字,print "helloworld"
不换行输出,pring "hello",
print "world" 输出:hello world (以空格分割)
1.6.2 input
--------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'>
>>>
1.6.3 整除
-----------python2
>>> print 5/2 #向下取整
2
-----------python3
>>> print (5/2) #默认进行浮点数除法
2.5
>>> print (5//2) #取模
2
1.6.4 range
-------------python2
>>> print range(4) #返回列表
[0, 1, 2, 3]
------------python3
>>> print(range(4)) #返回range对象
range(0, 4)
#循环访问py2和py3基本一样
1.6.5 字符串
python3表示字符串的两种类型:bytes和str,前者的实例包含原始的8位值(一个字节),后者实例包含unicode字符。
python2表示字符串的两种类型:unicode和str,前者包含Unicode字符,后者包含原始的8位值。
二进制转化为Unicode字符,使用decode;Unicode字符转二进制,使用encode。
1.6.6 列表推导产生的变量泄漏问题
- 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.7 项目依赖库安装
- pip freeze > requirements.txt 导出项目的依赖。
- pip install -r requirements.txt 在项目中一次性安装依赖
1.8 用venv 配置不同的开发环境
- 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
1.9.代码风格
- 折叠长行的首选方法是在小括号,中括号,大括号中使用Python隐式换行。长行可以在表达式外面使用小括号来变成多行。连续行使用反斜杠更好。
- 和None比较用is
- 缩进使用4个空格,而不要用tab
- 不要在for和while后面用else
- 为变量赋值时,赋值符号的左右侧应该各自写上一个空格。
- 文件中的函数和类之间应该用两个空行隔开。
- 在同一个类中,各方法之间应该用一个空行隔开。
1.10.新式类和旧式类
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可以序列化所有的数据类型,包括类,函数都可以序列化。
序列化的目的:
- 以某种存储形式使自定义对象持久化。
- 将对象从一个地方传递到另一个地方。
- 使程序更具维护性。
1.11.1 Json序列化
用于字符串 和 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
1.11.2 pickle序列化
用于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)
1.12.猴子补丁(Monkey patch)
在动态语言中,不去改变源码而对功能进行追加和变更,是在程序运行的过程中去修改。 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
1.13.上下文管理器
上下文管理器是一个对象,为操作提供了额外的上下文消息,以一种优雅的方式将额外的处理封装起来。如果一个类实现了
__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搜索模块的目录
1.16. 原地操作
许多运算符都有原地操作,如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']
2.错误解决方法
2.1 ImportError错误
- 普通的
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
语句。 - 在函数内导入模块(即使用到该模块内容的函数内部)