2. python高级应用
一. 面向对象
1.1 类
#类定义
class Employee:
   '所有员工的基类'	#类文档字符串
   empCount = 0 #类变量public static的
   def __init__(self, name, salary):	#构造方法
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def __del__(self): 					#析构函数
      class_name = self.__class__.__name__
      print class_name, "销毁"
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount
   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
#创建对象
emp1 = Employee("Zara", 2000)
#访问属性
emp1.displayEmployee()
print "Total Employee %d" % Employee.empCount
1.2 类属性
类属性可以增删改
emp1.age = 7  # 添加一个 'age' 属性
emp1.age = 8  # 修改 'age' 属性
del emp1.age  # 删除 'age' 属性
访问属性的函数:hasattr,getattr,setattr,delattr
hasattr(emp1, 'age')    # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age')    # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(empl, 'age')    # 删除属性 'age'
内置属性
- dict : 类的属性(包含一个字典,由类的数据属性组成)
- doc :类的文档字符串
- name: 类名
- module: 类定义所在的模块(类的全名是'main.className',如果类位于一个导入模块mymod中,那么className.module 等于 mymod)
- bases : 类的所有父类构成元素(包含了以个由所有父类组成的元组)
属性输出例子:
Employee.__doc__: 所有员工的基类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': '\xe6\x89\x80\xe6\x9c\x89\xe5\x91\x98\xe5\xb7\xa5\xe7\x9a\x84\xe5\x9f\xba\xe7\xb1\xbb', '__init__': <function __init__ at 0x10a939578>}
私有的属性与方法要加__,公有的不用,例子如下:
class JustCounter:
	__secretCount = 0  # 私有变量
	publicCount = 0    # 公开变量
	def __count1(self):   # 私有函数
		print self.__secretCount
	def count2(self):   # 公有函数
		print self.__count1
访问某个类私有属性的方法:
object._className__attrName
# 这个方法会报错
print counter.__secretCount 
# 成功
print counter._JustCounter__secretCount
1.3 类销毁
支持析构函数。
引用计数追踪内存对象,内部称为引用计数器,引用为0等待回收。
a = 40      # 创建对象  <40>
b = a       # 增加引用, <40> 的计数
c = [b]     # 增加引用.  <40> 的计数
del a       # 减少引用 <40> 的计数
b = 100     # 减少引用 <40> 的计数
c[0] = -1   # 减少引用 <40> 的计数
针对循环应用的情况,还具有一个循环垃圾收集器。清理哪些未引用的循环。
1.4 类继承
- 支持多继承
- 父类的__init__()不会被自动调用,需要手动调用
判断是子类或实例子
issubclass(sub,sup)
isinstance(obj, Class)
1.5 方法重写
类通用的方法
| 方法 | 描述 & 简单的调用 | 
|---|---|
| init ( self [,args...] ) | 构造函数 简单的调用方法: obj = className(args) | 
| del( self ) | 析构方法, 删除一个对象 简单的调用方法 : dell obj | 
| repr( self ) | 转化为供解释器读取的形式 简单的调用方法 : repr(obj) | 
| str( self ) | 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj) | 
| cmp ( self, x ) | 对象比较 简单的调用方法 : cmp(obj, x) | 
| 运算符重载 | 
class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2
运算符重载部分参考:
http://blog.csdn.net/adupt/article/details/4551890
http://blog.csdn.net/adupt/article/details/4551910
二. 正则表达式
2.1 匹配
re模块,提供perl风格正则模式
re.match
re.match(pattern, string, flags=0) #flags区分大小写、多行匹配等
只能从起始位置匹配,flags控制匹配方式,如果成功返回匹配对象,如果失败返回None
group()/groups
用来提取截取的分组,用()括起来的就是分组,例子:
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)   #123abc456,返回整体
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)   #123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)   #abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)   #456
re.search
re.search(pattern, string, flags=0)
返回第一个匹配
2.2 替换
re.sub
re.sub(pattern, repl, string, count=0, flags=0)
count是替换次数,repl是替换内容,如果是''就是删除。例子:
# Delete Python-style comments
num = re.sub(r'#.*$', "@", phone, 1, 0)
print "Phone Num : ", num
# Remove anything other than digits
num = re.sub(r'\D', "@", phone, 1, 0)
print "Phone Num : ", num
所有的flag如下:
| 修饰符 | 描述 | 
|---|---|
| re.I | 使匹配对大小写不敏感 | 
| re.L | 做本地化识别(locale-aware)匹配 | 
| re.M | 多行匹配,影响 ^ 和 $ | 
| re.S | 使 . 匹配包括换行在内的所有字符 | 
| re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. | 
| re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 | 
2.3 模式和例子
见:
http://www.runoob.com/python/python-reg-expressions.html
三. Socket
3.1 socket
socket()
#参数
#family: 套接字家族可以使AF_UNIX或者AF_INET
#type: 面向连接:SOCK_STREAM , 非连接:SOCK_DGRAM
#protocol: 一般不填默认为0.
socket.socket([family[, type[, proto]]])
Socket方法:
服务器端
| 函数 | 描述 | 
|---|---|
| s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。 | 
| s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。 | 
| s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 | 
服务端例子:
import socket               # 导入 socket 模块
s = socket.socket()         # 创建 socket 对象
host = socket.gethostname() # 获取本地主机名
port = 12345                # 设置端口
s.bind((host, port))        # 绑定端口
s.listen(5)                 # 等待客户端连接
while True:
    c, addr = s.accept()     # 建立客户端连接。
    print '连接地址:', addr
    c.send('欢迎访问菜鸟教程!')
    c.close()                # 关闭连接
客户端套接字
| 函数 | 描述 | 
|---|---|
| s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 | 
| s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 | 
客户端例子:
import socket               # 导入 socket 模块
s = socket.socket()         # 创建 socket 对象
host = socket.gethostname() # 获取本地主机名
port = 12345                # 设置端口好
s.connect((host, port))
print s.recv(1024)
s.close()  
公共用途的套接字函数
| 函数 | 描述 | 
|---|---|
| s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 | 
| s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 | 
| s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 | 
| s.recvform() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 | 
| s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。 | 
| s.close() | 关闭套接字 | 
| s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 | 
| s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) | 
| s.setsockopt(level,optname,value) | 设置给定套接字选项的值。 | 
| s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值。 | 
| s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) | 
| s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。 | 
| s.fileno() | 返回套接字的文件描述符。 | 
| s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 | 
| s.makefile() | 创建一个与该套接字相关连的文件 | 
3.2 Internet 模块
| 协议 | 功能用处 | 端口号 | Python 模块 | 
|---|---|---|---|
| HTTP | 网页访问 | 80 | httplib, urllib, xmlrpclib | 
| NNTP | 阅读和张贴新闻文章,俗称为"帖子" | 119 | nntplib | 
| FTP | 文件传输 | 20 | ftplib, urllib | 
| SMTP | 发送邮件 | 25 | smtplib | 
| POP3 | 接收邮件 | 110 | poplib | 
| IMAP4 | 获取邮件 | 143 | imaplib | 
| Telnet | 命令行 | 23 | telnetlib | 
| Gopher | 信息查找 | 70 | gopherlib, urllib | 
| 详见: | |||
| https://docs.python.org/2/library/socket.html | |||
四. 多线程
4.1 创建线程
创建线程两种方式:1.函数创建; 2.类包装
#function - 线程函数。
#args - 传递给线程函数的参数,他必须是个tuple类型。
#kwargs - 可选参数。
thread.start_new_thread ( function, args[, kwargs] )
例子:
# 为线程定义一个函数
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )
# 创建两个线程
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"
while 1:
   pass
线程结束:thread.exit()或自然结束
4.2 线程模块
threading模块
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
threading.Thread类
run(): 用以表示线程活动的方法。
start():启动线程活动。
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。
例子如下:
import threading
import time
exitFlag = 0
class myThread (threading.Thread):   #继承父类threading.Thread
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 
        print "Starting " + self.name
        print_time(self.name, self.counter, 5)
        print "Exiting " + self.name
def print_time(threadName, delay, counter):
    while counter:
        if exitFlag:
            thread.exit()
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启线程
thread1.start()
thread2.start()
print "Exiting Main Thread"
4.3 线程同步
Thread对象的Lock和Rlock实现锁,有acquire和release方法。
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
    def run(self):
        print "Starting " + self.name
       # 获得锁,成功获得锁定后返回True
       # 可选的timeout参数不填时将一直阻塞直到获得锁定
       # 否则超时后将返回False
        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 "Exiting Main Thread"
4.4 Queue
Queue提供:Queue,LifoQueue,PriorityQueue都实现了锁。
Queue模块中的常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作
例子:
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 "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name
def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %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
# 创建新线程
for tName 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 "Exiting Main Thread"
## 五. python xml解析 SAX : python内置sax解析器,触发事件调用用户定义的回调函数 DOM : 在内存中解析成一棵树 ElementTree : 更方便友好,解析成树
5.1 SAX
解析器:读取XML文档,并向事件处理器发送事件
事件处理器:对事件作出相应,对传递的XML数据进行处理
ContentHandler类方法
| 方法 | 调用时机 | 
|---|---|
| characters(content) | 开始和结束标签之间 | 
| startDocument() | 文档启动的时候调用 | 
| endDocument() | 解析器到达文档结尾时调用 | 
| startElement(name, attrs) | 遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典 | 
| endElement(name) | 遇到XML结束标签时调用 | 
xml类方
make_parser
xml.sax.make_parser( [parser_list] )	#parser_list可选参数,解析器列表
parser
#xmlfile - xml文件名
#contenthandler - 必须是一个ContentHandler的对象
#errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象
xml.sax.parse( xmlfile, contenthandler[, errorhandler])
parseString
#xmlstring - xml字符串
#contenthandler - 必须是一个ContentHandler的对象
#errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象
xml.sax.parseString(xmlstring, contenthandler[, errorhandler])
import xml.sax
class MovieHandler(xml.sax.ContentHandler):
    def __init__(self):
        self.CurrentData = ""
        self.type = ""
        self.format = ""
        self.year = ""
        self.rating = ""
        self.stars = ""
        self.description = ""
    # 元素开始事件处理
    def startElement(self, tag, attributes):
        print "<",tag,">",
    # 元素结束事件处理
    def endElement(self, tag):
        print "</",tag,">",
    # 内容事件处理
    def characters(self, content):
        if(content):
            print content,
            
if (__name__ == "__main__"):
    # 创建一个 XMLReader
    parser = xml.sax.make_parser()
    # turn off namepsaces
    parser.setFeature(xml.sax.handler.feature_namespaces, 0)
    # 重写 ContextHandler
    Handler = MovieHandler()
    parser.setContentHandler(Handler)
    parser.parse("movies.xml")
5.2 DOM
主要方法:
minidom.parse(filename):加载读取XML文件
doc.documentElement:获取XML文档对象
node.getAttribute(AttributeName):获取XML节点属性值
node.getElementsByTagName(TagName):获取XML节点对象集合
node.childNodes :返回子节点列表。
node.childNodes[index].nodeValue:获取XML节点值
node.firstChild:访问第一个节点,等价于pagexml.childNodes[0]
访问元素属性:
Node.attributes["id"]
a.name #就是上面的 "id"
a.value #属性的值
import xml.dom.minidom
dom1=xml.dom.minidom.parse('book.xml')
root=dom1.documentElement
book={}
booknode=root.getElementsByTagName('list')
for booklist in booknode:
    print '='*20
    print 'id:'+booklist.getAttribute('id')
    for nodelist in  booklist.childNodes:
        if nodelist.nodeType ==1:
            print nodelist.nodeName+':',
        for node in nodelist.childNodes:
            print node.data
参考:
http://www.cnblogs.com/xiaowuyi/archive/2012/10/17/2727912.html
5.3 ElementTree
Python标准库中有两种实现:xml.etree.ElementTree是纯python实现, xml.etree.cElementTree是c实现,尽量用这个。
常用方法:
tag获取节点名
attrib获取属性值
text获取节点值
文件加载方式:
root = ET.parse('book.xml')  	#加载文件
root = ET.fromstring(xmltext) 	#加载字符串
获取节点
booiter()	顺序遍历根节点下的全部节点
findall('list')  获取全部子节点
find('list')  	获取第一个子节点
例子:
try:                                           # 导入模块  
    import xml.etree.cElementTree as ET  
except ImportError:  
    import xml.etree.ElementTree as ET  
  
import xml.etree.ElementTree as ET
tree = ET.parse('country_data.xml')
root = tree.getroot()
#打印根节点下的全部country标签
for country in root.findall('country'): 
    print country.tag, country.attrib
# 遍历全部节点
for country in root.iter():
    print country.tag, country.attrib
参考:参考:https://docs.python.org/3/library/xml.etree.elementtree.html
六. Python json
6.1 json包
dumps对简单对象进行json编码
obj = [[1,2,3],123,123.123,'abc',{'key1':(1,2,3),'key2':(4,5,6)}]
encodedjson = json.dumps(obj)
json编码过程,会将python类型转化为json类型
| Python | Json | 
|---|---|
| dict | object | 
| list,tuple | array | 
| str,unicode | string | 
| int,long,float | number | 
| True | true | 
| False | false | 
| None | null | 
json.loads()获得原始数据
decodejson = json.loads(encodedjson)
print type(decodejson)
print decodejson[4]['key1']
print decodejson
json又转化为Python,存在类型转换
| Json | Python | 
|---|---|
| object | dict | 
| array | list | 
| string | unicode | 
| number(int) | int,long | 
| number(real) | float | 
| true | True | 
| false | False | 
| null | None | 
| 另外: | |
| sort_keys 设定排序 | |
| separators 移除空格 | |
| indent 格式化输出 | |
| skipkeys 出错误的会忽略 | 
#sort_keys
d1 = json.dumps(data1,sort_keys=True)
#indent
d1 = json.dumps(data1,sort_keys=True,indent=4)
#separators
print 'dumps(data, separators):', len(json.dumps(data, separators=(',',':')))
#skipkeys
print json.dumps(data,skipkeys=True)
3.2 自定的数据类型
class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __repr__(self):
        return 'Person Object name : %s , age : %d' % (self.name,self.age)
if __name__  == '__main__':
    p = Person('Peter',22)
    print p
直接转化会报错,有两个方法:
方法1:自己写转化函数
import Person
import json
 
p = Person.Person('Peter',22)
 
def object2dict(obj):
    #convert object to a dict
    d = {}
    d['__class__'] = obj.__class__.__name__
    d['__module__'] = obj.__module__
    d.update(obj.__dict__)
    return d
 
def dict2object(d):
    #convert dict to object
    if'__class__' in d:
        class_name = d.pop('__class__')
        module_name = d.pop('__module__')
        module = __import__(module_name)
        class_ = getattr(module,class_name)
        args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args
        inst = class_(**args) #create new instance
    else:
        inst = d
    return inst
 
d = object2dict(p)
print d
#{'age': 22, '__module__': 'Person', '__class__': 'Person', 'name': 'Peter'}
 
o = dict2object(d)
print type(o),o
#<class 'Person.Person'> Person Object name : Peter , age : 22
 
dump = json.dumps(p,default=object2dict)
print dump
#{"age": 22, "__module__": "Person", "__class__": "Person", "name": "Peter"}
 
load = json.loads(dump,object_hook = dict2object)
print load
#Person Object name : Peter , age : 22
方法2:继承JSONEncoder和JSONDecoder类
import Person
import json
 
p = Person.Person('Peter',22)
 
class MyEncoder(json.JSONEncoder):
    def default(self,obj):
        #convert object to a dict
        d = {}
        d['__class__'] = obj.__class__.__name__
        d['__module__'] = obj.__module__
        d.update(obj.__dict__)
        return d
 
class MyDecoder(json.JSONDecoder):
    def __init__(self):
        json.JSONDecoder.__init__(self,object_hook=self.dict2object)
    def dict2object(self,d):
        #convert dict to object
        if'__class__' in d:
            class_name = d.pop('__class__')
            module_name = d.pop('__module__')
            module = __import__(module_name)
            class_ = getattr(module,class_name)
            args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args
            inst = class_(**args) #create new instance
        else:
            inst = d
        return inst
d = MyEncoder().encode(p)
o =  MyDecoder().decode(d)
 
print d
print type(o), o
参考:
http://www.cnblogs.com/coser/archive/2011/12/14/2287739.html
 
                    
                
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号