面向對象多重繼承、簡單的版本控制、進程/線程、網絡編程

面向對象 - 多重繼承(一個類繼承多個類)

  • 如果一個類有多個父類,而多個父類又有公共的父類(菱形/磚石繼承)
    那麼在搜索屬性和方法時搜索的依據是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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章