python重要模塊學習一

包含:

  • 1、利用SocketServer進行網絡編程
  • 2、IO多路復用 select
  • 3、多線程 threading
  • 4、抽象基類abc
  • 5、inspect模塊

1、利用SocketServer進行網絡編程

網絡編程最基礎是 socket模塊,下面介紹SocketServer模塊,關于更多,參考
服務器端

#! /usr/bin/env python
#--*--coding:utf8--*--
from SocketServer import (TCPServer as TCP,StreamRequestHandler as SRH)
from time import ctime
HOST = ''
PORT = 21567
ADDR = (HOST, PORT)
class MyRequestHandle(SRH):
    def handle(self):
        print '...connected from :', self.client_address
        self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline()))

tcpServer = TCP(ADDR,MyRequestHandle)
print 'waiting for connecting'
tcpServer.serve_forever()

客戶端

#! /usr/bin/env python
#--*--coding:utf8--*--

from socket import *

HOST = 'localhost'
PORT = 21567
BUFFER = 1024
ADDR = (HOST,PORT)

while True:
    tcpclisock = socket(AF_INET,SOCK_STREAM)
    tcpclisock.connect(ADDR)
    data = raw_input('>')
    if not data:
        break

    tcpclisock.send('%s\r\n' % data)
    data = tcpclisock.recv(BUFFER)
    if not data:
        break
    print data.strip()
    tcpclisock.close()

2、IO多路復用 select

程序來源:http://python.jobbole.com/84058/

import select
import socket
import sys
 
HOST = 'localhost'
PORT = 5000
BUFFER_SIZE = 1024
 
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(5)
 
inputs = [server, sys.stdin]
running = True
 
while True:
    try:
        # 調用 select 函數,阻塞等待
        readable, writeable, exceptional = select.select(inputs, [], [])
    except select.error, e:
        break
 
    # 數據抵達,循環
    for sock in readable:
        # 建立連接
        if sock == server:
            conn, addr = server.accept()
            # select 監聽的socket
            inputs.append(conn)
        elif sock == sys.stdin:
            junk = sys.stdin.readlines()
            running = False
        else:
            try:
                # 讀取客戶端連接發送的數據
                data = sock.recv(BUFFER_SIZE)
                if data:
                    sock.send(data)
                    if data.endswith('\r\n\r\n'):
                        # 移除select監聽的socket
                        inputs.remove(sock)
                        sock.close()
                else:
                    # 移除select監聽的socket
                    inputs.remove(sock)
                    sock.close()
            except socket.error, e:
                inputs.remove(sock)
 
server.close()

Linux select模塊基本原理可以在高級IO中簡單回顧,python中對select函數API做了簡單修改,select.select(rlist, wlist, xlist[, timeout])
程序中 inputs = [server, sys.stdin]為讀監聽列表,列表中是需要監聽的文件描述符。當某個準備就緒時,會返回三個列表readable, writeable, exceptional,否則一直等待。通過類似下列語句

for sock in readable:
        # 建立連接
        if sock == server:

輪詢判斷哪個描述符準備好,并進行相應操作。

select的不足

select優點之一就是跨平臺的特性并且在描述符數量小時用起來很好。但也存在以下問題:
select需要遍歷監視的文件描述符,并且這個描述符的數組還有最大的限制。隨著文件描述符數量的增長,用戶態和內核的地址空間的復制所引發的開銷也會線性增長。即使監視的文件描述符長時間不活躍了,select還是會線性掃描。
為了解決這些問題,操作系統又提供了poll方案,但是poll的模型和select大致相當,只是改變了一些限制。目前Linux最先進的方式是epoll模型。

3、多線程 threading

參考來源 :http://python.jobbole.com/81546/
官方文檔

兩種創建線程方法:

1、繼承Thread類,重寫他的run方法

import threading, time, random
count = 0
class Counter(threading.Thread):
    def __init__(self, lock, threadName):
        '''@summary: 初始化對象。      
        @param lock: 瑣對象。
        @param threadName: 線程名稱。
        '''
        super(Counter, self).__init__(name = threadName)  #注意:一定要顯式的調用父類的初始
化函數。
        self.lock = lock
    
    def run(self):
        '''@summary: 重寫父類run方法,在線程啟動后執行該方法內的代碼。
        '''
        global count
        self.lock.acquire()
        for i in xrange(10000):
            count = count + 1
        self.lock.release()
lock = threading.Lock()
for i in range(5): 
    Counter(lock, "thread-" + str(i)).start()
time.sleep(2)   #確保線程都執行完畢
print count

這里要說明一下run方法 和start方法: 它們都是從Thread繼承而來的,run()方法將在線程開啟后執行,可以把相關的邏輯寫到run方法中(通常把run方法稱為活動[Activity]。);start()方法用于啟動線程。

2、創建一個threading.Thread對象,在它的初始化函數(init)中將可調用對象作為參數傳入

import threading, time, random
count = 0
lock = threading.Lock()
def doAdd():
    '''@summary: 將全局變量count 逐一的增加10000。
    '''
    global count, lock
    lock.acquire()
    for i in xrange(10000):
        count = count + 1
    lock.release()
for i in range(5):
    threading.Thread(target = doAdd, args = (), name = 'thread-' + str(i)).start()
time.sleep(2)   #確保線程都執行完畢
print count

threading.Thread類的初始化函數原型:
def __init__(self, group=None, target=None, name=None, args=(), kwargs={})

  • 參數group是預留的,用于將來擴展;
  • 參數target是一個可調用對象(也稱為活動[activity]),在線程啟動后執行;
  • 參數name是線程的名字。默認值為“Thread-N“,N是一個數字。
  • 參數args和kwargs分別表示調用target時的參數列表和關鍵字參數

更多參考方法和屬性參考 http://python.jobbole.com/81546/

條件變量

多線程中條件變量應用也很廣泛,用于兩個線程之間對某個共享信息之間的通信,比如線程A中等待某條件為真,該條件在線程B中改變,當成真時,發送一個信號給線程A繼續運行

import threading, time
class Hider(threading.Thread):
    def __init__(self, cond, name):
        super(Hider, self).__init__()
        self.cond = cond
        self.name = name
    
    def run(self):
        time.sleep(1) #確保先運行Seeker中的方法   
        
        self.cond.acquire() #b    
        print self.name + ': 我已經把眼睛蒙上了'
        self.cond.notify()
        self.cond.wait() #c    
                         #f 
        print self.name + ': 我找到你了 ~_~'
        self.cond.notify()
        self.cond.release()
                            #g
        print self.name + ': 我贏了'   #h
        
class Seeker(threading.Thread):
    def __init__(self, cond, name):
        super(Seeker, self).__init__()
        self.cond = cond
        self.name = name
    def run(self):
        self.cond.acquire()
        self.cond.wait()    #a    #釋放對瑣的占用,同時線程掛起在這里,直到被notify并重新占有瑣。
                            #d
        print self.name + ': 我已經藏好了,你快來找我吧'
        self.cond.notify()
        self.cond.wait()    #e
                            #h
        self.cond.release() 
        print self.name + ': 被你找到了,哎~~~'
        
cond = threading.Condition()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()

注意到,在seeker函數和Hider函數中都有一個self.cond.acquire(),就是說同一把鎖獲得了兩次,這在一般的lock對象中會發生死鎖,threadiong.Condition在內部維護一個RLock對象,
兩者區別是:

這兩種瑣的主要區別是:RLock允許在同一線程中被多次acquire。而Lock卻不允許這種情況。注意:如果使用RLock,那么acquire和release必須成對出現,即調用了n次acquire,必須調用n次的release才能真正釋放所占用的瑣。

threading中還有一個Event方法,可以實現和條件對象類似的功能,內部維護一個標識符來實現線程間的同步問題。

threading.Event()   # 初始化一個Event
Event.wait([timeout])
堵塞線程,直到Event對象內部標識位被設為True或超時(如果提供了參數timeout)。
Event.set()
將標識位設為Ture
Event.clear()
將標識伴設為False。
Event.isSet()
判斷標識位是否為Ture。

還有個常用的模塊是Timer,可以指定時間間隔執行某個操作

def hello():
    print "hello, world"
t = Timer(3, hello)
t.start() # 3秒鐘之后執行hello函數。

4、抽象基類abc

參考來源 http://www.lxweimin.com/p/19ed49293168
https://segmentfault.com/a/1190000007921371
python中并沒有提供抽象類與抽象方法,但是提供了內置模塊abc(abstract base class)來模擬實現抽象類。
抽象類,顧名思義,是在更高的邏輯層面上定義了函數API,比如將動物定義為一個抽象類,定義抽象方法 奔跑,叫聲等,可以不作具體實現,二是其子類做相應實現,比如狗,雞等各自實現自己的方法。
通過@abc.abstractmethod將方法聲明為抽象方法,比如:

import abc
class PluginBase(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def load(self, input):
        """Retrieve data from the input source and return an object."""
        return
    
    @abc.abstractmethod
    def save(self, output, data):
        """Save the data object to the output."""
        return

具體化抽象基類有以下兩種方式,

1、繼承
class SubclassImplementation(PluginBase):

    def load(self, input):
        return input.read()

    def save(self, output, data):
        return output.write(data)

if __name__ == '__main__':
    print 'Subclass:', issubclass(SubclassImplementation, PluginBase)
    print 'Instance:', isinstance(SubclassImplementation(), PluginBase)

繼承方式的優點:直接從抽象基類派生子類有一個好處,除非子類實現抽象基類的抽象方法,否則子類不能實例化。

2、注冊
class RegisteredImplementation(object):

    def load(self, input):
        return input.read()

    def save(self, output, data):
        return output.write(data)

PluginBase.register(RegisteredImplementation)


if __name__ == '__main__':
    print 'Subclass:', issubclass(RegisteredImplementation, PluginBase)
    print 'Instance:', isinstance(RegisteredImplementation(), PluginBase)

注冊方式的缺點:不會出現在類的MRO (Method Resolution Order),故而也不能通過super()來調用抽象方法。當沒有實現抽象方法時,實例化時候不會報錯,只有在調用時候才會報錯。

值得注意的是,抽象類的注冊方法抽象類中 __metaclass__ = abc.ABCMeta,必不可少,否則報錯無register方法。

注意,基類中抽象類的定義方法不會對其子類有強迫作用,比如抽象類為類方法,如下,繼承子類對應方法可以是靜態方法或一般方法。

class PluginBase(object):
    __metaclass__ = abc.ABCMeta
    @classmethod
    @abc.abstractmethod
    def load(cls, input):
        """Retrieve data from the input source and return an object."""
        return 
抽象屬性
import abc
class Base(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def value(self):
        return 'Should never get here'
class Implementation(Base):

    @property
    def value(self):
        return 'concrete property'
try:
    b = Base()
    print 'Base.value:', b.value
except Exception, err:
    print 'ERROR:', str(err)

i = Implementation()
print 'Implementation.value:', i.value

輸出為

ERROR: Can't instantiate abstract class Base with abstract methods value
Implementation.value: concrete property

5、inspect模塊

官網說明為:

The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects. For example, it can help you examine the contents of a class, retrieve the source code of a method, extract and format the argument list for a function, or get all the information you need to display a detailed traceback.
There are four main kinds of services provided by this module: type checking, getting source code, inspecting classes and functions, and examining the interpreter stack.

用到的知識點:

inspect.getmembers(object[, predicate]):

參考: http://blog.csdn.net/yugongpeng_blog/article/details/45670805?readlog
這個方法是dir()的擴展版,如下所示,dir只返回一個列表,沒有對應的值或函數位置

import inspect

class test():
    def __init__(self):
        self.name = 'Yuan'

    def meth(self):
        pass

test = test()
res = inspect.getmembers(test)
print res
print dir(test)
輸出結果:
[('__doc__', None), ('__init__', <bound method test.__init__ of <__main__.test instance at 0x01E9C288>>), ('__module__', '__main__'), ('meth', <bound method test.meth of <__main__.test instance at 0x01E9C288>>), ('name', 'Yuan')]
['__doc__', '__init__', '__module__', 'meth', 'name']

它會將dir()找到的名字對應的屬性一并返回,形如[(name, value), ...]。另外,predicate是一個方法的引用,如果指定,則應當接受value作為參數并返回一個布爾值,如果為False,相應的屬性將不會返回。使用is*(如isclass等)作為第二個參數可以過濾出指定類型的屬性。在ryu源碼中使用為:

clses = inspect.getmembers(mod, lambda cls: (inspect.isclass(cls) and
                                                issubclass(cls, RyuApp) and
                                                mod.__name__ ==
                                                cls.__module__))

對mod對象中的每個模塊,屬性,方法,函數等根據第二個參數進行檢查,當三個判斷都為真才返回。

inspect.getcallargs()

Bind the args and kwds to the argument names of the Python function or method func, as if it was called with them.

 from inspect import getcallargs
>>> def f(a, b=1, *pos, **named):
...     pass
>>> getcallargs(f, 1, 2, 3)
{'a': 1, 'named': {}, 'b': 2, 'pos': (3,)}
>>> getcallargs(f, a=2, x=4)
{'a': 2, 'named': {'x': 4}, 'b': 1, 'pos': ()}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,726評論 18 399
  • 線程狀態新建,就緒,運行,阻塞,死亡。 線程同步多線程可以同時運行多個任務,線程需要共享數據的時候,可能出現數據不...
    KevinCool閱讀 816評論 0 0
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,130評論 0 62
  • //今天遇到了一個問題//applicationWillTerminate:(UIApplication *)ap...
    CoderSahara閱讀 2,304評論 0 0
  • 夜色之濃,莫過于黎明前的黑暗 ——讀《牧羊少年奇幻之旅》有感 “在人生的某個時候,我們失去了對自己生活的掌控...
    玲玲姐姐閱讀 859評論 0 2