面向對象 - 多重繼承(一個類繼承多個類)
- 如果一個類有多個父類,而多個父類又有公共的父類(菱形/磚石繼承)
那麼在搜索屬性和方法時搜索的依據是c3算法(類似於廣度優先搜索)
這個是Python3中的一個改進,在此之前搜索的額算法是深度優先搜索(DFS) - 在實際開發儘量避免多重繼承,無法避免的時候可以把除第一父類外的父類設定爲抽象類,子類在繼承的時候重寫方法
from abc import ABCMeta,abstractmethod
class Father(object):
def __init__(self, name):
self._name = name
def drink1(self):
print(self._name + '正在喝酒')
def gamble(self):
print(self._name + '正在賭博')
class Monk(object, metaclass=ABCMeta):
def __init__(self, name):
self._name = name
@abstractmethod
def eat_vegetable(self):
pass
@abstractmethod
def chant(self):
pass
class Musicion(object, metaclass=ABCMeta):
def __init__(self, name):
self._name = name
@abstractmethod
def drink2(self):
pass
@abstractmethod
def play_piano(self):
pass
class Son(Father, Monk, Musicion):
def __init__(self, name, nickname, artname):
Father.__init__(self, name)
self._nickname = nickname
self._artname = artname
def play_piano(self):
print(self._artname + '正在彈鋼琴')
def read(self):
print(self._nickname + '正在念經')
def drink1(self):
print(self._name + '正在喝五糧液')
def drink2(self):
print(self._artname + '正在喝王老吉')
def main():
son = Son('蓋小倫', '智空', '銀河之力')
son.drink()
# Musicion.drink(son)
son.chant()
son.play_piano()
if __name__ == '__main__':
main()
版本控制Subversion(集中控制) / Git(分佈控制)
- 使用Git版本控制操作步驟:
命令提示符進入需要版本控制的文件夾
git init # 初始化,建成倉庫,可以記錄歷史版本
git add .(導入當前文件夾所有文件) # git add test007.py只導入test007.py這個文件
git status # 查看修改後的結果/狀態
git commit -m ‘修正了一個bug’ #說明修改原因(本地版本控制)
git remote add origin https//…. # 與遠端倉庫建立聯繫
git push origin master # 推送到遠程倉庫
概要1:git init - git add . - git status - git commit -m ‘提交原因’ (本地版本控制)
2: git clone https…實際開發中可以先建好遠程倉庫,拷貝到本地後再開始編輯以及推送到遠程倉庫
3: 遠端git remote add origin https//… - git pull https//…(遠端倉庫拉到本地)- git push origin master…(推送到遠端倉庫)
- 常用命令
git pull – cat test007.py # 查看當前文檔內容
git branch查看分支 git branch new_function建立新分支 git merge new-function合併分支 git branch -d new-function rm
cls # 清屏
cd ./cd .. # 回到當前/上一級目錄
pwd # print work d…打印當前工作目錄
ls -a #查看倉庫所有文件
git log # 查看歷史版本/日誌
git reset # 回到初始版本
git checkout data.json # 恢復刪除的文件
git clon \http:…. # 克隆雲端文件
正則表達式
正則表達式就是記錄文本規則的代碼,定義字符串的匹配模式。
常用元字符(代表字符串的開頭和結尾,它只匹配一個位置)
. 匹配除換行符以外的任意字符
\w 匹配字母或數字或下劃線或漢字
\s 匹配任意的空白符
\d 匹配數字
\b 匹配單詞的開始或結束
^ 匹配字符串的開始
$ 匹配字符串的結束常用限定符(指定數量的代碼)
*重複零次或更多次
+重複一次或更多次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更多次
{n,m} 重複n到m次常用反義符
\W 匹配任意不是字母,數字,下劃線,漢字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數字的字符
\B 匹配不是單詞開頭或結束的位置
[^x] 匹配除了x以外的任意字符常用分組語法
(exp) 匹配exp,並捕獲文本到自動命名的組裏
(?< name >exp) 匹配exp,並捕獲文本到名稱爲name的組裏,也可以寫成(?’name’exp)
(?:exp) 匹配exp,不捕獲匹配的文本,也不給此分組分配組號
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp後面的位置
(?!exp) 匹配後面跟的不是exp的位置
(? < !exp) 匹配前面不是exp的位置
import re # 導入正則表達式模塊
def main():
username = 'someone'
m = re.match(r'^\w{6,20}$', username)
print(m) # 如果匹配失敗,返回None
if m:
print(m.span()) # 如果匹配成功,拿到匹配的範圍
print(m.group()) # 把匹配到的範圍取出來
if __name__ == '__main__':
main()
我們玩遊戲的時候有些敏感字是不能被輸出的,這時候就可以用*來代替
import re
def main():
re.sub # substitute替換
sentence = '趙信我操你大爺幹你二爺Fuck你姑爺'
pure = re.sub('[艹草操日干肏]|趙信|fuck|shit|傻逼', '*', sentence,
flags=re.IGNORECASE) # |分支, flags標記IGNORECASE忽略大小寫
print(pure) # 輸出"*我*你大爺*你二爺*你姑爺"
if __name__ == '__main__':
main()
process進程,thread線程
進程是操作系統分配內存的基本單元,進程之間的內存是相互隔離的,通過icp機制/管道通信。
一個進程可以劃分爲多個線程,線程是進程的執行單元 ,也是操作系統分配cpu的執行單元;線程啓用的越多,佔用cpu越多。使用多線程/多進程可以提升執行效率,縮短程序執行時間;改善用戶體驗。
- python中使用多進程比多線程更好,因爲多進程相互之間是獨立的,程序執行效率更高。
進程
from multiprocessing import Process
import subprocess # subprocess子進程
import time
import os
def output():
print(os.getpid()) # 啓用多進程
while True:
print('Pong', end = '', flush=True) # flush=True關閉緩存
time.sleep(0.001)
def main():
print(os.getpid) # 打印進程號
p = Process(target=output) # 這裏傳入函數名,表示進程啓用後纔在這個進程裏面去執行函數
p.start()
while True:
print('Ping', end = '', flush=True)
time.sleep(0.001)
def main():
subprocess.call('calc') # call調用calc計算器
subprocess.call('notepad')
if __name__ == '__main__':
main()
線程
- 多線程是共享內存的,共享數據。
python不能用到cpu的多核特性,但是這不代表他的多進程、多線程是無用的。
實際開發中,多線程的程序不好寫,也不好調試,因爲cpu分配是隨機的,運行時如果有bug那麼就不知道它什麼時候回出現問題。 - 創建線程的兩種方式:
1,直接創建Thread對象並通過target參數指定線程啓動後要執行的任務。
2,繼承Thread自定義線程,通過重寫run方法指定線程啓動後執行的任務,推薦使用這種方法!
from threading import Thread # from thread是python2中使用的模塊
from time import sleep
def output():
while True:
print('Pong', end='', flush=True)
sleep(0.001)
def main():
t1 = Thread(target=output)
t1.start()
while True:
print('Ping', end='', flush=True)
sleep(0.001)
if __name__ == '__main__':
main()
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# 這裏應該使用元組,並且儘管只有一個元素,但是也要加上逗號,否則就是一個字符串
t1 = Thread(target=output, args=('Ping',))
t1.start()
t2 = Thread(target=output, args=('Pong',))
t2.start()
if __name__ == '__main__':
main()
from threading import Thread
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# daemon=True - 將線程設置爲守護線程(不值得保留的線程),其他線程/主程序如果執行完了,那麼守護線程自動結束
t1 = Thread(target=output, args=('Ping',),daemon=True)
t1.start()
t2 = Thread(target=output, args=('Pong',), daemon=True)
t2.start()
if __name__ == '__main__':
main()
多進程模擬下載文件
如果多個任務之間沒有任何的關聯(獨立子任務),而且希望利用cpu的多核特性,那麼我們推薦使用多進程,因爲任務之間沒有數據交換
import time
import random
from threading import Thread
def download(filename):
print('開始下載%s...' % filename)
delay = random.randint(5,15)
time.sleep(delay)
print('%s下載完成,用時%d秒' % (filename, delay))
# 如果要寫多線程,推薦使用這種方法
class DownloadTask(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename
# 鉤子函數(hook) / 回調函數(callback)(寫了這個方法,但是從來沒有調用它,它是讓系統啓動線程的時候自動回調這個方法)
# 寫程序時啓用線程用start,不能用run!!!
def run(self):
download(self._filename)
def main():
start = time.time()
t1 = DownloadTask('Python從入門到住院.pdf')
t1.start()
t2 = DownloadTask('Pekin Hot.avi')
t2.start()
t1.join() # join等待進程結束(然後再打印時間)
t2.join()
end = time.time()
print('總共耗費了%f秒' % (end - start))
if __name__ == '__main__':
main()
網絡編程
- 計算機網絡:是多臺獨立自主的計算機形成的一個系統。
連接起來的目的是計算機之間共享資源。
使用TCP(能做到數據不傳丟、流量控制、擁塞控制)/ICP連接起來的叫互聯網。
# 創建一個無功能的服務器
from socket import socket, AF_INET, SOCK_STREAM
# SOCK_STREAM使用tcp,SOCK_DGRAM使用udp
def main():
# 創建一個基於TCP協議的套接字對象
# 因爲我們做的是應用級的服務/產品,所以可以利用現有的傳輸服務來實現數據傳輸
server = socket() # AF_INET, SOCK_STREAM IPv4聯網,只能這麼寫
# 綁定IP地址(網絡上主機的身份標識)和端口(用來區分不同服務的IP 地址的擴展,一個端口對應一個服務)(端口不是一個設備)
server.bind(('10.7.189.75', 6543)) # ip寫成localhost表示本地,6543表示端口號
# 開始監聽客戶端的連接
server.listen(512) # 512表示隊列大小
print('服務器已經啓動正在監聽...')
while True:
# 通過accept方法接收客戶端的連接
# accept方法是一個阻塞式的方法,如果沒有客戶端連上來
# 那麼accept方法就會讓代碼阻塞,知道有客戶端連接成功才返回
# accept方法返回一個元組,元組中的第一個值代表客戶端的對象
# 元組中的第二個值又是一個元組,其中有客戶端的IP地址和客戶端的端口
# client = server.accept()
# print(client)
client, addr = server.accept()
print(addr, '連接成功.')
client.send('hello789'.encode('utf-8'))
client.close()
if __name__ == '__main__':
main()
模擬一個聊天服務器
from socket import socket
from threading import Thread
# TCP - Transfer Control Protocol
# UDP - User Datagram Protocol
def main():
class ClientHandler(Thread):
def __init__(self, client):
super().__init__()
self._client = client
def run(self):
while True:
try:
data = self._client.recv(1024) # 返回的是二進制數據
for client in clients:
# if client != self._client 不給自己轉發消息
client.send(data) # 轉發消息
if data.decode('utf-8') == 'byebye':
clients.remove(self._client)
self._client.close() # 與說‘byebye’的客戶端斷開連接
break
except Exception as e: # 獲取異常消息
print(e) # 打印異常消息
clients.remove(self._client) # 移除異常客戶端
break
server = socket()
# 這裏可以使用Python命令行參數 - sys.argv
server.bind(('10.7.189.75', 54321)) # 端口號不要跟敏感號重複,建議取1025-65536區間
# 開始監聽
server.listen(512)
clients = []
while True:
# 接收用戶請求
client, addr = server.accept()
clients.append(client)
ClientHandler(client).start()
if __name__ == '__main__':
main()