python 11期 第八天

一、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、打開、關閉)

wKiom1bYzKXAzwv3AADA7pMFePI352.png


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類來處理請求。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章