一、isinstance(obj, cls)
檢查obj是否是類 cls 的對象
class Foo(object):
pass
obj = Foo()
isinstance(obj, Foo)
可以判斷屬於某個類,或者屬於某個類的父類。
作用:在用戶輸入的時候,可以對輸入的數據進行分類操作,然後再和數據庫交互。
二、issubclass(sub, super)
檢查sub類是否是 super 類的派生類
class Foo(object):
pass
class Bar(Foo):
pass
issubclass(Bar, Foo)
三、異常處理
基本格式:
try:
pass
except Exception,ex:
pass
舉例:
while True:
num1 = raw_input('num1:')
num2 = raw_input('num2:')
try:
num1 = int(num1)
num2 = int(num2)
result = num1 + num2
except Exception, e:
print '出現異常,信息如下:'
print e
捕獲到異常後,返回一個信息,此處e一般可以輸出在日誌中,以便查看出錯的內容。
常見異常:
AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x
IOError 輸入/輸出異常;基本上是無法打開文件
ImportError 無法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典裏不存在的鍵
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,代碼不能編譯(個人認爲這是語法錯誤,寫錯了)
TypeError 傳入對象類型與要求的不符合
UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量,
導致你以爲正在訪問它
ValueError 傳入一個調用者不期望的值,即使值的類型是正確的
代碼塊中可能出現的任意異常:
s1 = 'hello'
try:
int(s1)
except IndexError,e:
print e
except KeyError,e:
print e
except ValueError,e:
print e
萬能異常 在python的異常中,有一個萬能異常:Exception,他可以捕獲任意異常,即:
s1 = 'hello'
try:
int(s1)
except Exception,e:
print e
對於特殊處理或提醒的異常需要先定義,最後定義Exception來確保程序正常運行。
s1 = 'hello'
try:
int(s1)
except KeyError,e:
print '鍵錯誤'
except IndexError,e:
print '索引錯誤'
except Exception, e:
print '錯誤'
異常其他結構
try:
# 主代碼塊
pass
except KeyError,e:
# 異常時,執行該塊
pass
else:
# 主代碼塊執行完,執行該塊
pass
finally:
# 無論異常與否,最終執行該塊
pass
主動觸發異常
try:
raise Exception('錯誤了。。。') ##主動觸發異常
except Exception,e:
print e
自定義異常
class WupeiqiException(Exception):
def __init__(self, msg):
self.message = msg
def __str__(self):
return self.message
try:
raise WupeiqiException('我的異常')
except WupeiqiException,e:
print e
斷言:
# assert 條件
assert 1 == 1
如果上面的條件成立,纔會執行下面的代碼。
assert 1 == 2
上面的條件不成立,則會退也程序。
它相當於raise類似。
##在print 一個對象的時候,一般打印出來的都是該對象下的__str__方法。
四、反射
常用框架類型:
MVC框架:
models
views
controllers
MTV框架:
models
templates
views
手動獲取url原理:
url='aaa/bbb'
d,e= url.split('/')
print d
print e
反射函數:getattr
首先新建一個py模塊myflas.py,創建兩個函數,內容如下:
def a():
return 'hello tingyun'
def b():
return "hello mynetuser"
再新建一個文件,導入上面的模塊:
import myflas
fun1=getattr(myflas,'a')
print fun1()
fun2=getattr(myflas,'b')
print fun2()
通過getattr內置函數來獲取myflas模塊中的兩個函數a 和 b,如果找到了,就將該函數返回給新的值,此處fun1函數就是a函數名。
setattr 作用:在模塊中添加一個成員
setattr(myflas,'bright',lambda x,y:x+y)
fun3=getattr(myflas,'bright')
print fun3(43,98)
在myflas中新增加一個函數bright。
>>> hasattr(system,'argv') ##hasattr用來判斷system模塊中有沒有argv函數
True
>>> delattr(system,'argv') ##delattr刪除system模塊中的argv函數
以上四個函數:hasattr,getattr,setattr,delattr除了可以對模塊進行操作以外,還可以對類和對象中的成員進行操作。
多層反射:
反射的函數可以對模塊或類進行操作,但是當一個類在一個模塊中時,此時只用一次反射也只能將模塊中的函數進行處理,卻不能對模塊中的類進行處理,此時就需要多層的反射來處理。
首先用一個getattr獲取模塊中的類,將此類賦值一個變量,再對該對象進行getattr來獲取類中的靜態方法。
總結,getattr就是去一個容器(包括模塊和類等)中找它的元素。
五、動態模塊導入
如果導入的模塊還未確定的變量名,此時就可以用以下方法來導入:
__import__('obj')
下面的表示將導入的動態模塊命名爲opt,此功能模import x as y.
opt=__import__('obj')
舉例:
modu=raw_input('pls input a name:')
opt=__import__(modu)
此處的modu是一個變量,因此用上面的方法來導入後,即可進行正常的模塊操作了。
六、設計模式
1、單例模式
單例模式用來保證內存中僅存在一個實例!!!
如以下例子中,當多個用戶對以下類請求多次時,會在內存中創建很多完全一樣的實例,這樣會導致內存空間的浪費:
#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server
class DbHelper(object):
def __init__(self):
self.hostname = '1.1.1.1'
self.port = 3306
self.password = 'pwd'
self.username = 'root'
def fetch(self):
# 連接數據庫
# 拼接sql語句
# 操作
return 'fetch'
def create(self):
# 連接數據庫
# 拼接sql語句
# 操作
return 'create'
def remove(self):
# 連接數據庫
# 拼接sql語句
# 操作
return 'remove'
def modify(self):
# 連接數據庫
# 拼接sql語句
# 操作
return 'modify'
class Handler(object):
def index(self):
# 創建對象
db = DbHelper()
db.fetch()
return 'index'
def news(self):
return 'news'
def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
temp = url.split('/')[1]
obj = Handler()
is_exist = hasattr(obj, temp)
if is_exist:
func = getattr(obj, temp)
ret = func()
return ret
else:
return '404 not found'
if __name__ == '__main__':
httpd = make_server('', 8001, RunServer)
print "Serving HTTP on port 8001..."
httpd.serve_forever()
因此通過面向對象的特性,構造出單例模式:
# ########### 單例類定義 ###########
class Foo(object):
__instance = None
@staticmethod
def singleton():
if Foo.__instance:
return Foo.__instance
else:
Foo.__instance = Foo()
return Foo.__instance
# ########### 獲取實例 ###########
obj = Foo.singleton()
以上的類中有一個singleton方法被定義爲靜態方法,此方法無需實例化可直接調用,第一次調用時私有靜態字段__instance爲空,則會把Foo類實例化到__instance私有靜態字段中成爲一個對象,再返回此私有字段;第二次調用時,此私有靜態字段就是實例化的Foo類,就相當於又調用了上一次實例化的那個對象,以及以後每次調用時都會使用此對象,就相當於只創建一次對象,會實多次使用,這就是單例模式。但是單例模式只適用於沒有數據庫連接池的情況下使用。
七、socker原理
http一般的鏈接(除長鏈接)是在請求一次,回覆請求後會立即斷開。http協議是基於tcp連接創建的。
tcp連接可以通過socket來創建。
ocket通常也稱作"套接字",用於描述IP地址和端口,是一個通信鏈的句柄,應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。
socket起源於Unix,而Unix/Linux基本哲學之一就是“一切皆文件”,對於文件用【打開】【讀寫】【關閉】模式來操作。socket就是該模式的一個實現,socket即是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉)
web服務應用:
import socket
def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 200 OK\r\n\r\n")
client.send("Hello, World")
def main():
#創建socket對象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#使用bind方法來監聽端口
sock.bind(('localhost',8080))
#開始監聽,5最大連接數
sock.listen(5)
while True:
#accept會阻塞住程序的運行,等待有請求連接
connection, address = sock.accept()
#connection:代表連接;address: 代表客戶端連接地址
handle_request(connection)
connection.close()
if __name__ == '__main__':
main()
#python中所有的框架都是基於socket連接來開發的。如果不想讓accept阻塞程序運行可以用:
server.setblocking(False),但是此時如果accept在接收不到請求的時候,會報錯,recv也會報錯。
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
參數一:協議,地址簇
socket.AF_INET IPv4(默認)
socket.AF_INET6 IPv6
socket.AF_UNIX 只能夠用於單一的Unix系統進程間通信
參數二:TCP或UDP類型
socket.SOCK_STREAM 流式socket , for TCP (默認)
socket.SOCK_DGRAM 數據報式socket , for UDP
socket.SOCK_RAW 原始套接字,普通的套接字無法處理ICMP、IGMP等網絡報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。
socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於高級用戶或管理員運行的程序使用。
socket.SOCK_SEQPACKET 可靠的連續數據包服務
參數三、0
0是根據IPV4或V6、TCP或UDP來自動選擇一個合適的協議。
自己編寫socker服務端和客戶端:
server:
#coding:utf8
import socket
server=socket.socket()
server.bind(('127.0.0.1',8571))
server.listen(2) #最大連接數
while True:
#阻塞中,獲取連接和地址
print 'waiting...'
connect,addr = server.accept()
#接收客戶端的數據,最多一次爲小於或等於1024字節
client_data=connect.recv(1024)
print client_data
#通過緩衝區向客戶端發送數據(緩衝區有算法來定何時發送)
connect.send('abcdefg')
#立即讓緩衝區發送數據到客戶端
#connect.sendall('abcdefg')
connect.close()
client:
#coding:utf8
import socket
client=socket.socket()
#連接到服務器
client.connect(('127.0.0.1',8571))
client.send('help me')
#接收服務端傳來的數據
server_data=client.recv(1024)
print server_data
client.close()
socket常用的方法:
sk.bind(address)
s.bind(address) 將套接字綁定到地址。address地址的格式取決於地址族。在AF_INET下,以元組(host,port)的形式表示地址。
sk.listen(backlog)
開始監聽傳入連接。backlog指定在拒絕連接之前,可以掛起的最大連接數量。
backlog等於5,表示內核已經接到了連接請求,但服務器還沒有調用accept進行處理的連接個數最大爲5
這個值不能無限大,因爲要在內核中維護連接隊列
sk.setblocking(bool)
是否阻塞(默認True),如果設置False,那麼accept和recv時一旦無數據,則報錯。
sk.accept()
接受連接並返回(conn,address),其中conn是新的套接字對象,可以用來接收和發送數據。address是連接客戶端的地址。
接收TCP 客戶的連接(阻塞式)等待連接的到來
sk.connect(address)
連接到address處的套接字。一般,address的格式爲元組(hostname,port),如果連接出錯,返回socket.error錯誤。
sk.connect_ex(address) #如果連接出錯,不會報異常,會返回一個錯誤編碼
同上,只不過會有返回值,連接成功時返回 0 ,連接失敗時候返回編碼,例如:10061
sk.close()
關閉套接字
sk.recv(bufsize[,flag])
接受套接字的數據。數據以字符串形式返回,bufsize指定最多可以接收的數量。flag提供有關消息的其他信息,通常可以忽略。
sk.recvfrom(bufsize[.flag]) #多用於UDP協議
與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。
sk.send(string[,flag])
將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小。即:可能未將指定內容全部發送。
sk.sendall(string[,flag])
將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。
內部通過遞歸調用send,將所有內容發送出去。
sk.sendto(string[,flag],address) #用於UDP,不需要建立加接直接發送,指定發送的主機地址
將數據發送到套接字,address是形式爲(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。該函數主要用於UDP協議。
sk.settimeout(timeout) #用於客戶端,設置超時時間,大於此時間自動放棄連接
設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因爲它們可能用於連接的操作(如 client 連接最多等待5s )
sk.getpeername() #針對客戶端返回服務器的地址和端口
返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。
sk.getsockname() #針對服務端,返回服務器自己的地址和端口
返回套接字自己的地址。通常是一個元組(ipaddr,port)
sk.fileno()
套接字的文件描述符
##################################################
##智能機器人
server端:
#coding:utf8
import socket
ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
event={'2':'通過可能會被錄音.balabala一大推',
'3':'這個可能是你操作不當的問題',
'4':'這個網絡的問題'
}
while True:
conn,address = sk.accept()
conn.sendall('歡迎致電 10086,請輸入1xxx,0轉人工服務.')
Flag = True
while Flag:
data = conn.recv(1024)
print data
if data == 'exit':
Flag = False
elif data in event.keys():
conn.sendall(event.get(data))
else:
conn.sendall('請重新輸入.')
conn.close()
#此服務端是單線程,同一時間只能處理一個請求,第二個請求到來只能等待
client端:
#coding:utf8
import socket
ip_port = ('127.0.0.1',8888)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5) ##設置超時時間
while True:
data = sk.recv(1024)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break
sk.close()
#多線程socker服務端:
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request #每一個客戶端
print "client is : ",self.client_address
conn.sendall('歡迎致電 10086,請輸入1xxx,0轉人工服務.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('通過可能會被錄音.balabala一大推')
else:
conn.sendall('請重新輸入.')
if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
#這個多線程服務的固定格式,就是必須要定義一個類,此類要繼承SocketServer.BaseRequestHandler類。而且類中必須有一個方法名叫handle,不能更改。所有過來的請求,都會去找此handle方法處理,再將此類傳給ThreadingTCPServer處理,它在內部增加了多線程的機制。serve_forever()用來啓動多線程服務。每次來一個請求,ThreadingTCPServer類都會實例化一個MyServer類來處理請求。