Python涉及的细节知识点比较多,在学习的过程中,这些关键的知识点需要牢记,笔记如下。
基础概念
包的导入
一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__
属性来使该程序块仅在该模块自身运行时执行。
if__name__=='__main__':
print('程序自身在运行')
else:
print('我来自另一模块')
import语法会首先把item当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,一个exc:ImportError
异常被抛出了。
反之,如果使用形如import item.subitem.subsubitem
这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。
如果包定义文件__init__.py存在一个叫做__all__的列表变量,那么在使用from package import*的时候就把这个列表中的所有名字作为包内容导入。作为包的作者,可别忘了在更新包之后保证__all__也更新了。如下代码:
代码语言:python代码运行次数:0复制__all__=["echo","surround","reverse"]
字符串
如果你希望将输出的值转成字符串,可以使用repr()或str()函数来实现。
str()函数返回一个用户易读的表达形式。
repr()产生一个解释器易读的表达形式。
例如
代码语言:python代码运行次数:0复制>>>s='Hello,world.'
>>>str(s)
'Hello,world.'
>>>repr(s)
"'Hello,world.'"
str.format()的基本使用
print('Wearethe{}whosay"{}!"'.format('knights','Ni'))
括号及其里面的字符(称作格式化字段)将会被format()中的参数替换,在括号中的数字用于指向传入对象在format()中的位置,如下所示:
print('{0}and{1}'.format('spam','eggs'))
如果在format()中使用了关键字参数,那么它们的值会指向使用该名字的参数。位置及关键字参数可以任意的结合。
print('Thestoryof{0},{1},and{other}.'.format('Bill','Manfred',other='Georg'))
'!a'(使用ascii()),'!s'(使用str())和'!r'(使用repr())可以用于在格式化某个值之前对其进行转化:
代码语言:txt复制importmath
代码语言:txt复制print('ThevalueofPIisapproximately{!r}.'.format(math.pi))
可选项':'和格式标识符可以跟着字段名。这就允许对值进行更好的格式化。下面的例子将Pi保留到小数点后三位:
代码语言:txt复制print('ThevalueofPIisapproximately{0:.3f}.'.format(math.pi))
在':'后传入一个整数,可以保证该域至少有这么多的宽度。用于美化表格时很有用。
如果你有一个很长的格式化字符串,而你不想将它们分开,那么在格式化时通过变量名而非位置会是很好的事情。最简单的就是传入一个字典,然后使用方括号'[]'来访问键值:
代码语言:txt复制table={'Sjoerd':4127,'Jack':4098,'Dcab':8637678}
代码语言:txt复制print('Jack:{0[Jack]:d};Sjoerd:{0[Sjoerd]:d};Dcab:{0[Dcab]:d}'.format(table))
输出:
Jack:4098;Sjoerd:4127;Dcab:8637678
%操作符也可以实现字符串格式化。它将左边的参数作为类似sprintf()式的格式化字符串,而将右边的代入,然后返回格式化后的字符串.例如:
代码语言:txt复制print('ThevalueofPIisapproximately%5.3f.'%math.pi)
因为str.format()比较新的函数,大多数的Python代码仍然使用%操作符。但是因为这种旧式的格式化最终会从该语言中移除,应该更多的使用str.format().
pickle序列化模块
pickle模块实现了基本的数据序列和反序列化。
- 通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
- 通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。
基本接口:
代码语言:txt复制pickle.dump(obj,file,[,protocol])
有了pickle这个对象,就能对file以读取的形式打开:
代码语言:txt复制x=pickle.load(file)
注解:从file中读取一个字符串,并将它重构为原来的python对象。file:类文件对象,有read()和readline()接口。
实例1:使用pickle模块将数据对象保存到文件
代码语言:txt复制importpickle
代码语言:txt复制data1={
代码语言:txt复制'a':[1,2.0,3,4 6j],
代码语言:txt复制'b':('string',u'Unicodestring'),
代码语言:txt复制'c':None}
代码语言:txt复制selfref_list=[1,2,3]
代码语言:txt复制selfref_list.append(selfref_list)
代码语言:txt复制output=open('data.pkl','wb')
代码语言:txt复制#Pickled ictionary using protocol.
代码语言:txt复制pickle.dump(data1,output)
代码语言:txt复制#Picklethelistusingthehighestprotocolavailable.
代码语言:txt复制pickle.dump(selfref_list,output,-1)
代码语言:txt复制output.close()
实例2:使用pickle模块从文件中重构python对象
代码语言:txt复制import pprint,pickle
代码语言:txt复制pkl_file=open('data.pkl','rb')
代码语言:txt复制data1=pickle.load(pkl_file)
代码语言:txt复制pprint.pprint(data1)
代码语言:txt复制data2=pickle.load(pkl_file)
代码语言:txt复制pprint.pprint(data2)
代码语言:txt复制pkl_file.close()
异常
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:
代码语言:txt复制except(RuntimeError,TypeError,NameError):
代码语言:txt复制 pass
一个except子句可以忽略异常的名称,它将被当作通配符使用。你可以使用这种方法打印一个错误信息,然后再次把异常抛出。
代码语言:txt复制try:
代码语言:txt复制 f=open('myfile.txt')
代码语言:txt复制 s=f.readline()
代码语言:txt复制 i=int(s.strip())
代码语言:txt复制except OSErroraserr:
代码语言:txt复制 print("OSerror:{0}".format(err))
代码语言:txt复制exceptValueError:
代码语言:txt复制 print("Couldnotconvertdatatoaninteger.")
代码语言:txt复制except:
代码语言:txt复制 print("Unexpectederror:",sys.exc_info()[0])
代码语言:txt复制 raise
try except语句还有一个可选的else子句,如果使用这个子句,那么必须放在所有的except子句之后。这个子句将在try子句没有发生任何异常的时候执行。例如:
代码语言:txt复制for arg in sys.argv[1:]:
代码语言:txt复制try:
代码语言:txt复制 f=open(arg,'r')
代码语言:txt复制except IOError:
代码语言:txt复制 print('cannotopen',arg)
代码语言:txt复制else:
代码语言:txt复制 print(arg,'has',len(f.readlines()),'lines')
代码语言:txt复制 f.close()
使用else子句比把所有的语句都放在try子句里面要好,这样可以避免一些意想不到的、而except又没有捕获的异常。
Python使用raise语句抛出一个指定的异常。raise唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是Exception的子类)。
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的raise语句就可以再次把它抛出。
代码语言:txt复制try:
代码语言:txt复制 raiseNameError('HiThere')
代码语言:txt复制except NameError:
代码语言:txt复制 print('Anexceptionflewby!')
代码语言:txt复制 raise
输出异常信息如下:
代码语言:txt复制Anexceptionflewby!
代码语言:txt复制Traceback(mostrecentcalllast):
代码语言:txt复制File"<stdin>",line2,in?
代码语言:txt复制NameError:HiThere
如果一个异常在try子句里(或者在except和else子句里)被抛出,而又没有任何的except把它截住,那么这个异常会在finally子句执行后再次被抛出。
with关键字
关键词with语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:
代码语言:txt复制with open("myfile.txt") as f:
代码语言:txt复制 for line in f:
代码语言:txt复制 print(line, end="")
多继承
Python同样有限的支持多继承形式。多继承的类定义形如下例:
代码语言:txt复制class DerivedClassName(Base1,Base2,Base3):
- 类的私有属性 __private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs。
- 类的方法 在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数
- 类的私有方法 __private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用slef.__private_methods。
- 类的专有方法:
<!---->
代码语言:txt复制__init__:构造函数,在生成对象时调用
代码语言:txt复制__del__:析构函数,释放对象时使用
代码语言:txt复制__repr__:打印,转换
代码语言:txt复制__setitem__:按照索引赋值
代码语言:txt复制__getitem__:按照索引获取值
代码语言:txt复制__len__:获得长度
代码语言:txt复制__cmp__:比较运算
代码语言:txt复制__call__:函数调用
代码语言:txt复制__add__:加运算
代码语言:txt复制__sub__:减运算
代码语言:txt复制__mul__:乘运算
代码语言:txt复制__div__:除运算
代码语言:txt复制__mod__:求余运算
代码语言:txt复制__pow__:乘方
- 运算符重载 Python同样支持运算符重载,我么可以对类的专有方法进行重载,即重新实现即可。
正则表达式
Python的re模块提供了re.sub用于替换字符串中的匹配项。
代码语言:txt复制re.sub(pattern,repl,string,max=0)
返回的字符串是在字符串中用RE最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回。
可选参数count是模式匹配后替换的最大次数;count必须是非负整数。缺省值是0表示替换所有的匹配。
实例:
代码语言:txt复制import re
代码语言:txt复制phone="2004-959-559#这是一个电话号码"
代码语言:txt复制#删除注释
代码语言:txt复制num=re.sub(r'#.*$',"",phone)
代码语言:txt复制print("电话号码:",num)
代码语言:txt复制#移除非数字的内容
代码语言:txt复制num=re.sub(r'D',"",phone)
代码语言:txt复制print("电话号码:",num)
以上实例执行结果如下:
电话号码:2004-959-559
电话号码:2004959559
正则表达式修饰符-可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位OR(|)它们来指定。如re.I|re.M被设置成I和M标志:
修饰符描述
re.I使匹配对大小写不敏感
re.L做本地化识别(locale-aware)匹配
re.M多行匹配,影响^和$
re.S使.匹配包括换行在内的所有字符
re.U根据Unicode字符集解析字符。这个标志影响w,W,b,B.
re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
文件操作
f.seek()
如果要改变文件当前的位置,可以使用f.seek(offset,from_what)函数。
from_what的值,如果是0表示开头,如果是1表示当前位置,2表示文件的结尾,例如:
- seek(x,0):从起始位置即文件首行首字符开始移动x个字符
- seek(x,1):表示从当前位置往后移动x个字符
- seek(-x,2):表示从文件的结尾往前移动x个字符 from_what值为默认为0,即文件开头。
Python依赖默认下载路径
Python会将下载的内容保存到/root/.cache目录下,是因为它使用了缓存机制来提高下载效率和减少网络流量。当你使用pip下载和安装Python包时,它会将包和依赖项保存到缓存目录中,以便下次使用时可以直接从缓存中获取,而不需要重新下载。
如果你想更改Python缓存目录的位置,可以设置环境变量XDG_CACHE_HOME来指定新的缓存目录。XDG_CACHE_HOME是一个标准的环境变量,用于指定用户的缓存目录。
以下是一个示例命令,用于将Python的缓存目录更改为/path/to/new/directory:
代码语言:shell复制export XDG_CACHE_HOME=/path/to/new/directory
这个命令将会将XDG_CACHE_HOME环境变量设置为/path/to/new/directory。当你使用Python下载和安装包时,它将会将包和依赖项保存到这个目录下。
需要注意的是,修改缓存目录可能会影响到其他Python项目和用户。因此,在修改缓存目录时,你需要仔细考虑它的影响,并确保它不会影响到其他进程和用户。
Python 列表是引用传递
在Python中,如果将一个列表作为参数传递给函数,并在函数内部修改该列表,会影响函数外部的列表。这是因为在Python中,列表是可变对象,传递给函数的是列表对象的引用,而不是列表对象的副本。因此,对列表对象的任何修改都会影响到原始列表对象。
以下是一个示例代码,演示了在函数内部删除列表元素会影响函数外部的列表:
代码语言:python代码运行次数:0复制def remove_element(my_list, element):
my_list.remove(element)
# del my_list[2]
my_list = [1, 2, 3, 4, 5]
print("Before:", my_list)
remove_element(my_list, 3)
print("After:", my_list)
如果不想在函数内部修改原始列表对象,可以在函数内部创建一个新的列表对象,并将原始列表对象的内容复制到新列表对象中。例如,可以使用以下代码来创建一个新的列表对象:
代码语言:python代码运行次数:0复制new_list = my_list.copy()
然后,在函数内部修改新列表对象,而不是原始列表对象。这样就不会影响函数外部的列表对象了。
可变参数*args和**kwargs
可变参数*args 和 **kwargs定义函数时候,参数args在前,kwargs在后,*args和kwargs组合起来可以传入任意的参数。
*args参数:可接受任意个位置参数,当函数调用时,所有未使用(未匹配)的位置参数会在函数内自动组装进一个tuple对象中,此tuple对象会赋值给变量名args。
**kwargs参数:可接受任意个关键字参数,当函数调用时,所有未使用(未匹配)的关键字参数会在函数内组装进一个dict对象中,此dict对象会赋值给变量名kwargs。
同时使用*args和**kwargs时,*args参数列必须要在**kwargs前,要是像foo(1,a=1,b=2,c=3,2,3)这样调用的话,则会提示语法错误“SyntaxError: non-keyword arg after keyword arg”。
代码语言:python代码运行次数:0复制def foo(*args,**kwargs):
print 'args=',args,"len:",len(args)
print 'kwargs=',kwargs,"len:",len(kwargs)
print '**********************'
if __name__=='__main__':
foo(1,2,3)
foo(a=1,b=2,c=3)
foo(1,2,3,a=1,b=2,c=3)
foo(1,'b','c',a=1,b='b',c='c')
执行结果如下:
代码语言:txt复制args= (1, 2, 3)
代码语言:txt复制kwargs= {}
代码语言:txt复制**********************
代码语言:txt复制args= ()
代码语言:txt复制kwargs= {'a': 1, 'c': 3, 'b': 2}
代码语言:txt复制**********************
代码语言:txt复制args= (1, 2, 3)
代码语言:txt复制kwargs= {'a': 1, 'c': 3, 'b': 2}
代码语言:txt复制**********************
代码语言:txt复制args= (1, 'b', 'c')
代码语言:txt复制kwargs= {'a': 1, 'c': 'c', 'b': 'b'}
For循环遍历
在序列中遍历时,索引位置和对应值可以使用enumerate()函数同时得到:
代码语言:python代码运行次数:0复制fori, v in enumerate(['tic','tac','toe']):
print(i, v)
输出:
0 tic
1 tac
2 toe
数据库操作
python使用pymysql包操作mysql数据库
代码语言:txt复制#!/usr/bin/python3
import pymysql
#打开数据库连接
db=pymysql.connect("localhost","testuser","test123","TESTDB")
#使用cursor()方法获取操作游标
cursor=db.cursor()
#SQL插入语句
sql="INSERTINTOEMPLOYEE(FIRST_NAME,LAST_NAME,AGE,SEX,INCOME)
VALUES('%s','%s','%d','%c','%d')"%('Mac','Mohan',20,'M',2000)
try:
#执行sql语句
cursor.execute(sql)
#执行sql语句
db.commit()
except:
#发生错误时回滚
db.rollback()
#关闭数据库连接
db.close()
#获取所有记录列表
results=cursor.fetchall()
for row in results:
print(row[0], row[1])
解析XML
python有三种方法解析XML,SAX,DOM,以及ElementTree:
1.SAX(simpleAPIforXML)
python标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。
SAX是一种基于事件驱动的API。利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器。
- 解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件;2.DOM(DocumentObjectModel)
- 事件处理器则负责对事件作出相应,对传递的XML数据进行处理。
将XML数据在内存中解析成一个树,通过对树的操作来操作XML。
JSON解析
Python3中可以使用json模块来对JSON数据进行编解码,它包含了两个函数:
json.dumps():对数据进行编码。
json.loads():对数据进行解码。
在json的编解码过程中,python的原始类型与json类型会相互转换,具体的转化对照如下:
Python编码为JSON类型转换对应表:
代码语言:txt复制Python JSON
dict object
list,tuple array
str string
int,float,int-&float-derivedEnums number
True true
False false
None null
JSON解码为Python类型转换对应表:
代码语言:txt复制JSON Python
object dict
array list
string str
number(int) int
number(real) float
true True
false False
null None
如果你要处理的是文件而不是字符串,你可以使用json.dump()和json.load()来编码和解码JSON数据。例如:
代码语言:txt复制#写入JSON数据
wit hopen('data.json','w')asf:
json.dump(data,f)
#读取数据
with open('data.json','r')asf:
data=json.load(f)
时间
从返回浮点数的时间辍方式向时间元组转换,只要将浮点数传递给如localtime之类的函数。
代码语言:txt复制#!/usr/bin/python3
import time
localtime=time.localtime(time.time())
print("本地时间为:",localtime)
以上实例输出结果:
本地时间为:time.struct_time(tm_year=2016,tm_mon=4,tm_mday=7,tm_hour=10,tm_min=28,tm_sec=49,tm_wday=3,tm_yday=98,tm_isdst=0)
assert断言
代码语言:txt复制#如果条件不成立,则打印出'this is error'并抛出AssertionError异常
assert false,'this is error'
高级特性
socket编程
服务端代码
代码语言:txt复制#!/usr/bin/python3
#文件名:server.py
#导入socket、sys模块
import socket
import sys
#创建socket对象
serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#获取本地主机名
host=socket.gethostname()
port=9999
#绑定端口
serversocket.bind(host,port)
#设置最大连接数,超过后排队
serversocket.listen(5)
whileTrue:
#建立客户端连接
clientsocket,addr=serversocket.accept()
print("连接地址:%s"%str(addr))
msg='HelloWorld!' "rn"
clientsocket.send(msg.encode('utf-8'))
clientsocket.close()
客户端代码
代码语言:txt复制#!/usr/bin/python3
#文件名:client.py
#导入socket、sys模块
importsocket
importsys
#创建socket对象
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#获取本地主机名
host=socket.gethostname()
#设置端口好
port=9999
#连接服务,指定主机和端口
s.connect(host,port)
#接收小于1024字节的数据
msg=s.recv(1024)
s.close()
print(msg.decode('utf-8'))
多线程:
代码语言:txt复制#!/usr/bin/python3
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
defrun(self):
print("开启线程:" self.name)
#获取锁,用于线程同步
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("退出主线程")
队列
代码语言:txt复制#!/usr/bin/python3
import queue
import threading
import time
exitFlag=0
class myThread(threading.Thread):
def__init__(self,threadID,name,q):
threading.Thread.__init__(self)
self.threadID=threadID
self.name=name
self.q=q
def run(self):
print("开启线程:" self.name)
process_data(self.name,self.q)
print("退出线程:" self.name)
def process_data(threadName,q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data=q.get()
queueLock.release()
print("%sprocessing%s"%(threadName,data))
else:
queueLock.release()
time.sleep(1)
threadList=["Thread-1","Thread-2","Thread-3"]
nameList=["One","Two","Three","Four","Five"]
queueLock=threading.Lock()
workQueue=queue.Queue(10)
threads=[]
threadID=1
#创建新线程
fort Name in threadList:
thread=myThread(threadID,tName,workQueue)
thread.start()
threads.append(thread)
threadID =1
#填充队列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
#等待队列清空
while not workQueue.empty():
pass
#通知线程是时候退出
exitFlag=1
#等待所有线程完成
for t in threads:
t.join()
print("退出主线程")
以上程序执行结果:
开启线程:Thread-1
开启线程:Thread-2
开启线程:Thread-3
Thread-3processingOne
Thread-1processingTwo
Thread-2processingThree
Thread-3processingFour
Thread-1processingFive
退出线程:Thread-3
退出线程:Thread-2
退出线程:Thread-1
退出主线程
debugger调试
可以通过pdb、IDE等工具进行调试。
Python中有两个内置方法在这里也很有帮助:
- locals:执行locals()之后,返回一个字典,包含(currentscope)当前范围下的局部变量。
- globals:执行globals()之后,返回一个字典,包含(currentscope)当前范围下的全局变量。
邮件发送
代码语言:txt复制#!/usr/bin/python3
import smtplib
from email.mime.text import MIMEText
from email.header import Header
#第三方SMTP服务
mail_host="smtp.XXX.com"#设置服务器
mail_user="XXXX"#用户名
mail_pass="XXXXXX"#口令
sender='from@w3cschool.cn'
receivers=['429240967@qq.com']#接收邮件,可设置为你的QQ邮箱或者其他邮箱
message=MIMEText('Python邮件发送测试...','plain','utf-8')
message['From']=Header("hello world",'utf-8')
message['To']=Header("测试",'utf-8')
subject='PythonSMTP邮件测试'
message['Subject']=Header(subject,'utf-8')
try:
smtpObj=smtplib.SMTP()
smtpObj.connect(mail_host,25)#25为SMTP端口号
smtpObj.login(mail_user,mail_pass)
smtpObj.sendmail(sender,receivers,message.as_string())
print("邮件发送成功")
except smtplib.SMTPException:
print("Error:无法发送邮件")
CGI
通用网关接口(CommonGatewayInterface),它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端HTML页面的接口。
所有的HTTP服务器执行CGI程序都保存在一个预先配置的目录。这个目录被称为CGI目录,并按照惯例,它被命名为/var/www/cgi-bin目录。
CGI文件的扩展名为.cgi,python也可以使用.py扩展名。
python cgi编程类似于jsp编程,获取get或post请求的处理方法如下:
代码语言:python代码运行次数:0复制import cgi,cgitb
#创建FieldStorage的实例化
form=cgi.FieldStorage()
#获取数据
site_name=form.getvalue('name')
site_url=form.getvalue('url')
print("Content-type:text/html")
print()
print("<html>")
print("<head>")
print("<metacharset="utf-8">")
print("<title>CGI测试实例</title>")
print("</head>")
print("<body>")
print("<h2>%s官网:%s</h2>"%(site_name,site_url))
print("</body>")
print("</html>")