Python3.6学习笔记(五)
網(wǎng)絡(luò)編程
網(wǎng)絡(luò)程序出現(xiàn)的比互聯(lián)網(wǎng)要早很多,實(shí)現(xiàn)方式主要依靠網(wǎng)絡(luò)上不同主機(jī)間進(jìn)程的通信,通信協(xié)議最重要的是TCP/IP協(xié)議。在這兩個(gè)協(xié)議基礎(chǔ)上還有很多更高級(jí)的協(xié)議,包括HTTP、SMTP等。要進(jìn)行兩個(gè)主機(jī)間的網(wǎng)絡(luò)通信,必須四個(gè)元素:源地址、源端口號(hào)、目的地址、目的端口號(hào)。
TCP編程
Socket是網(wǎng)絡(luò)編程一個(gè)抽象概念,通常我們用一個(gè)Socket表示“打開(kāi)了一個(gè)網(wǎng)絡(luò)鏈接”,而打開(kāi)一個(gè)Socket需要知道目標(biāo)計(jì)算機(jī)的IP地址和端口號(hào),再指定協(xié)議類型即可。示例代碼實(shí)現(xiàn)了一個(gè)服務(wù)端和客戶端,服務(wù)端將客戶端發(fā)送的內(nèi)容回顯給客戶端,一切都是在命令行下執(zhí)行。圖形界面原理一樣。
import socket import threading import time#服務(wù)端代碼 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 9999))#開(kāi)始監(jiān)聽(tīng)端口,參數(shù)表示最大連接數(shù) s.listen(5) print("Waiting for connection...")def tcplink(sock, addr):print('Accept new connection from %s:%s...' % addr)sock.send(b'Welcome!')while True:data = sock.recv(1024)time.sleep(1)if not data or data.decode('utf-8') == 'exit':breaksock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))sock.close()print('Connection from %s:%s closed.' % addr)while True:sock, addr = s.accept()t = threading.Thread(target=tcplink, args=(sock, addr))t.start()客戶端代碼
import sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立連接: s.connect(('127.0.0.1', 9999)) # 接收歡迎消息: print(s.recv(1024).decode('utf-8')) for data in [b'Michael', b'Tracy', b'Sarah']:# 發(fā)送數(shù)據(jù):s.send(data)print(s.recv(1024).decode('utf-8')) s.send(b'exit') s.close()UDP編程
TCP建立了雙方之間的可靠連接,通信雙方都可以用流的方式發(fā)送數(shù)據(jù)。UDP則是面相無(wú)連接的協(xié)議,使用UDP協(xié)議時(shí),不需要建立連接,只需要知道對(duì)方的IP和端口號(hào),就可以直接發(fā)送數(shù)據(jù)包。但是對(duì)方是否能夠收到就不知道了。它的優(yōu)點(diǎn)是速度快。
服務(wù)端代碼
import socket import threading import times = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 綁定端口: s.bind(('127.0.0.1', 9999))print('Bind UDP on 9999...') while True:# 接收數(shù)據(jù):data, addr = s.recvfrom(1024)print('Received from %s:%s.' % addr)s.sendto(b'Hello, %s!' % data, addr)客戶端代碼
import socket import threading import times = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for data in [b'Michael', b'Tracy', b'Sarah']:# 發(fā)送數(shù)據(jù):s.sendto(data, ('127.0.0.1', 9999))# 接收數(shù)據(jù):print(s.recv(1024).decode('utf-8')) s.close()做了一個(gè)簡(jiǎn)單的對(duì)比,可見(jiàn)UDP的傳輸方式比TCP快了很多。
Web開(kāi)發(fā)
隨著互聯(lián)網(wǎng)流行起來(lái)的B/S模式是Web開(kāi)發(fā)的主要內(nèi)容,包括客戶端展現(xiàn)(HTML、CSS、JAVASCRIPT)以及服務(wù)端處理(靜態(tài)內(nèi)容、CGI、動(dòng)態(tài)語(yǔ)言)。Python提供了很多Web開(kāi)發(fā)框架,能夠?yàn)槲覀兲峁¦eb開(kāi)發(fā)的快速支持。
開(kāi)始WEB開(kāi)發(fā)的話我覺(jué)得最好從HTML入手,然后了解HTTP協(xié)議,這些熟悉之后逐步熟悉CSS、Javascript,然后了結(jié)合后臺(tái)編程語(yǔ)言,完成自己編寫(xiě)網(wǎng)站的小目標(biāo)。
筆者是從PHP學(xué)習(xí)開(kāi)始Web開(kāi)發(fā)的,接觸Python的Web開(kāi)發(fā)還沿用PHP的思路會(huì)產(chǎn)生一些迷惑。PHP從產(chǎn)生之初就是作為Web開(kāi)發(fā)語(yǔ)言而設(shè)計(jì)的,PHP是作為Apache的模塊來(lái)進(jìn)行請(qǐng)求處理和響應(yīng)的,與HTTP相關(guān)的很多基礎(chǔ)處理都是由Apache完成的,mod_php模塊與其對(duì)接生成類似$_POST,$_GET的對(duì)象供PHP腳本使用。
Python有所不同,Python是作為一種通用腳本處理語(yǔ)言產(chǎn)生的,所以它能夠完成的工作更多,也可以作為Web開(kāi)發(fā)語(yǔ)言,只是方式不同。如果Python作為服務(wù)端腳本語(yǔ)言,可以分幾個(gè)層次:如果Python負(fù)責(zé)處理所有的事務(wù),包括TCP鏈接、邏輯處理、內(nèi)容響應(yīng),Python也是可以勝任的,但是這樣開(kāi)發(fā)要做的工作就非常多;如果Python只是負(fù)責(zé)生成HTML文檔,前端使用Apache等,Pyhon只需要負(fù)責(zé)文檔解析。實(shí)現(xiàn)這個(gè)層次,是因?yàn)镻ython提供了WSGI接口(Web Server Gateway Interface),這時(shí)Python的焦點(diǎn)放在接口處理和Web邏輯處理上。第三個(gè)層次就是使用Python的Web框架,現(xiàn)在有很多成熟的框架,包括Django、Flask等。這樣,Python就主要關(guān)注Web處理,包括URL以及對(duì)應(yīng)的函數(shù)處理。
先看一下使用WSGI接口編寫(xiě)簡(jiǎn)單的Web程序,返回一個(gè)簡(jiǎn)單的文字。
# server.py # 從wsgiref模塊導(dǎo)入: from wsgiref.simple_server import make_server # 導(dǎo)入我們自己編寫(xiě)的application函數(shù): from hello import application# 創(chuàng)建一個(gè)服務(wù)器,IP地址為空,端口是8000,處理函數(shù)是application: httpd = make_server('', 8000, application) print('Serving HTTP on port 8000...') # 開(kāi)始監(jiān)聽(tīng)HTTP請(qǐng)求: httpd.serve_forever() # hello.pydef application(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html')])body = '<h1>Hello, %s!</h1>' % (environ['PATH_INFO'][1:] or 'web')return [body.encode('utf-8')]使用WSGI的方式來(lái)進(jìn)行Web開(kāi)發(fā),需要花很多精力來(lái)處理請(qǐng)求和響應(yīng)的對(duì)應(yīng)關(guān)系,這個(gè)時(shí)候可以引入框架。這里以Web.py框架為例。
import weburls = ('/(.*)', 'hello' ) app = web.application(urls, globals())class hello: def GET(self, name):if not name:name = 'World'return 'Hello, ' + name + '!'if __name__ == "__main__":app.run()由此可見(jiàn),使用框架后,我們可以將精力放在URL和對(duì)應(yīng)的處理函數(shù)上。
正則表達(dá)式
正則表達(dá)式說(shuō)起來(lái)是一個(gè)可以講很久的話題,這里簡(jiǎn)單說(shuō)一下 Python 中的使用。
re模塊
Python提供re模塊,包含所有正則表達(dá)式的功能。建議所有處理正則的部分都使用```r```開(kāi)頭,這樣就不需要考慮轉(zhuǎn)義的問(wèn)題。
>>> import re >>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345') <_sre.SRE_Match object; span=(0, 9), match='010-12345'> >>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345') >>>如果匹配則返回一個(gè)Match對(duì)象,沒(méi)找到則返回None。
切分字符串
可以使用正則的切分字符串
>>> re.split(r'\s+', 'a b c') ['a', 'b', ‘c']分組
正則表達(dá)式中提供了()進(jìn)行匹配結(jié)果的分組,如果正則表達(dá)式中定義了組,就可以使用Match對(duì)象的group()方法提取子串。group(0)表示的是原始字符串。
>>> t = '19:05:30' >>> m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t) >>> m.groups() ('19', '05', '30')常用內(nèi)置模塊
datetime
datetime是Python處理日期和時(shí)間的標(biāo)準(zhǔn)庫(kù)。日期操作中,常用的包括獲取當(dāng)前日志、創(chuàng)建一個(gè)日期、計(jì)算兩個(gè)日期的差值、判斷日期的類型、日期與時(shí)間戳的相互轉(zhuǎn)換、字符串與日期類型的相互轉(zhuǎn)換,這些基本上看看例子就可以掌握。
在計(jì)算機(jī)中,時(shí)間實(shí)際上是用數(shù)字表示的。我們把1970年1月1日 00:00:00 UTC+00:00時(shí)區(qū)的時(shí)刻稱為epoch time,記為0(1970年以前的時(shí)間timestamp為負(fù)數(shù)),當(dāng)前時(shí)間就是相對(duì)于epoch time的秒數(shù),稱為timestamp。timestamp 與時(shí)區(qū)沒(méi)有關(guān)系,datetime與時(shí)區(qū)有關(guān)系。
字符串'%Y-%m-%d %H:%M:%S'規(guī)定了日期和時(shí)間部分的格式。詳細(xì)的說(shuō)明請(qǐng)參考Python文檔。字符串轉(zhuǎn)換為日期類型后,默認(rèn)是沒(méi)有帶時(shí)區(qū)信息的。
from datetime import datetime, timedelta, timezone# 獲取當(dāng)前時(shí)間 now = datetime.now() print(now)# 創(chuàng)建一個(gè)指定的日期 wt = datetime(2017,4,12,14,5,15) print(wt)# 將日期類型轉(zhuǎn)換為時(shí)間戳 print( wt.timestamp() )# 將時(shí)間戳轉(zhuǎn)換為日期,加了一個(gè)小時(shí) print( datetime.fromtimestamp(wt.timestamp() + 60*60 ) )# 字符串轉(zhuǎn)換為日期類型 cday = datetime.strptime('2017-4-12 18:19:59', '%Y-%m-%d %H:%M:%S') print(cday)# 將日期類型格式化為字符串顯示 print(now.strftime('%A, %B, %d, %H:%m'))# 日期類型也可以直接使用 + - 進(jìn)行運(yùn)算,引入timedelta可以計(jì)算差值 print(now - timedelta(days=1)) print(now + timedelta(days=1, hours=2))collections
collections 是 Python 內(nèi)建的一個(gè)集合模塊,提供了許多有用的集合類。包括?namedtuple、deque
tuple 可以表示不變集合,但是不方便從名稱上看出用途。通過(guò)使用namedtuple函數(shù),可以創(chuàng)建一個(gè)自定義的tuple對(duì)象,規(guī)定了tuple的個(gè)數(shù),并且可以通過(guò)屬性來(lái)訪問(wèn)元素。
使用 list 存儲(chǔ)數(shù)據(jù)時(shí),,按索引訪問(wèn)元素很快,但是插入和刪除元素就很慢了,因?yàn)閘ist是線性存儲(chǔ),數(shù)據(jù)量大的時(shí)候,插入和刪除效率很低。deque是為了高效實(shí)現(xiàn)插入和刪除操作的雙向列表,適合用于隊(duì)列和棧。deque除了實(shí)現(xiàn)list的append()和pop()外,還支持appendleft()和popleft(),這樣就可以非常高效地往頭部添加或刪除元素。
參考資料:
1、Python Web Server Gateway Interface v1.0
2、Webpy 框架
總結(jié)
以上是生活随笔為你收集整理的Python3.6学习笔记(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python3.6学习笔记(四)
- 下一篇: 介绍一款python类型检查工具pyri