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.jianshu.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阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,612评论 18 399
  • 线程状态新建,就绪,运行,阻塞,死亡。 线程同步多线程可以同时运行多个任务,线程需要共享数据的时候,可能出现数据不...
    KevinCool阅读 798评论 0 0
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,094评论 0 62
  • //今天遇到了一个问题//applicationWillTerminate:(UIApplication *)ap...
    CoderSahara阅读 2,278评论 0 0
  • 夜色之浓,莫过于黎明前的黑暗 ——读《牧羊少年奇幻之旅》有感 “在人生的某个时候,我们失去了对自己生活的掌控...
    玲玲姐姐阅读 832评论 0 2