經驗拾憶(純手工)=> Python好用深度技能工具介紹

單元素元祖:

a = (1)    # 這是整數1
a = (1,)   # 這纔是元祖
也許這兩行,大家當時疑惑過,而且如今也都知道了,固然重點並不在這裏。。

我無聊的時候想過,爲何單元素元祖要這樣設計 -> (1,)?
很少廢話,看下面代碼,本身理解:
    a = (3,)
    a = (3)
    
    a = (1+2)
    a = (1+2,)
    
    a = (1+2) + (3+4)
    a = (1+2,) + (3+4,)

注:
    這是我我的原創理解的一個微不足道的知識點,可是印象卻特別深入。
    由於我反向推測出 設計者爲何會設計出這種語法。
    (固然,也許個人推測和設計者當時的想法的並不同~~~手動滑稽)

深/淺拷貝-copy/deepcopy(皮/肉)

"""
    最開始接觸深淺拷貝的時候沒太大感受,只是普通的以爲避免數據污染就夠了
    後來有一次用scrapy寫爬蟲的時候,層次太多致使內存有些頂不住。
    後來用的 deepcopy() 來 優化  scrapy 的 meta, 雖然效果不是特別明顯,可是感受深淺拷貝頗有用
"""
    1. =號,不拷貝
        =號就意味着,引用指向同一個地址空間,‘敵動我動,敵不動我不懂’ 的感受。 LOL一句話:"連體嬰兒"~~
    2. copy:也稱淺拷貝
        我用最簡單的話解釋一下:淺拷貝就是隻能拷貝最外面的一層皮,來獨立開闢空間使用,再深仍是共用的
        eg:
            from copy import copy
            from copy import deepcopy
            
            a = [[1,2,3],[4,5,6]]
            b = deepcopy(a)
            b[0] = 0            # 這就是最外面的一層皮
            print(b)
            print(a)
    
    3. deepcopy:顧名思義了,深拷貝
       若是你聽懂我上面的話,我感受這個就更好理解了, 淺拷貝是皮,深拷貝那就是肉了唄。
       沒錯,不管套了幾層的序列結構,每一層都是獨立開闢空間,獨立指向。
            from copy import copy
            from copy import deepcopy
            
            a = [[1,2,3],[4,5,6]]
            b = deepcopy(a)
            b[0][1] = 0    # 看清楚,這回就是裏面的肉了, 深拷貝:你改哪裏都行,哪裏都與我無關
            print(b)
            print(a)

lambda黑科技

"""lambda至關於匿名函數,可使代碼簡介,但有時也會被人唾棄,但我仍然喜歡用lambda"""

1. 試想:若是你想在lambda調用多個函數,該如何寫?
    lambda: (print(1),print(2))    # 最外層加個括號便可
    
2. 若是你想讓這個 lambda函數直接自執行,而不是經過賦予一個函數引用再執行?
    1. 這個也是我本身瞎鼓搗出來的。
    2. 雖然我JS水平很垃圾,可是我知道JS匿名函數有一種執行方式叫作 ‘自執行’。
    3. 把上面類比一下。
    
    看吧,這就是Python版的匿名函數自執行方法。
        Python版本: (lambda a:print(a))(1)        
        JS版:       (function(){})()

lambda的虛僞替代品-operator

"""
    聽說這個模塊能夠替代lambda, 我的理解此模塊並不那麼太有實用價值,理解成本也偏高,
    建議:若是不喜歡lambda或者lambda用的不多的人,能夠研究一下此模塊。此模塊的意圖仍是能夠的。
    我仍是喜歡使用 lambda
"""
直接上個例子:(字典基於Value來排序) 
    傳統lambda寫法:
        In [27]: a = {'1':6, '2':5, '3':4}
        In [28]: sorted(a.items(), key=lambda a:a[1])   # 看key= 這裏
        Out[28]: [('3', 4), ('2', 5), ('1', 6)]
                                
    operator寫法:
        from operator import itemgetter
        
        In [25]: a = {'1':6, '2':5, '3':4}
        In [26]: sorted(a.items(), key=itemgetter(1))   # 就是key= 這裏有區別
        Out[26]: [('3', 4), ('2', 5), ('1', 6)]

若是上面兩種新舊方法都很模糊,那麼我再解釋一下: 我認爲上面能讓人頭疼的也就是 索引 1 了!!!!
    sorted, map這種高階函數,我以前也單獨講過,它會把 一個序列的每個元素用管道函數進行映射。
    
    sorted稍微特殊一點,它的管道函數方法變成了key=這裏: (變相理解爲 指定排序的基準/參考)
        1. key=lambda a:a[1]
            指定基準:序列a的 每子元素 的 第1號索引子元素    # eg: [[1,2],[3,4],[5,6]]  就是2,4,6
        
        2. key=itemgetter(1)
            指定基準:同上如出一轍,只不過寫法不同,邏輯步驟就是 原本來本從 lambda那裏演變過來的。
            
總結與我的觀點:
    1. operator 模塊只是 lambda 使用思想 的 高一層的封裝
    2. 讓使用者能夠忽略lambda格式細節
    3. 可是我認爲 若是lambda都用很差, 那麼 這個 itemgetter(1) 這種子元素 索引的指定 也會很困難
    4. 因此我仍是建議用 lambda, 當你 lambda思想練熟了以後, 用 operator看看官方文檔就是很快的事情

封包/拆包(解構賦值)/函數佔位參數騷操做

"""
    再次說明一下:我寫的全部的都是Py3的/   Py2的解構賦值可能有些出入,此處我只說Py3
"""

封包:
    1)
        def f(a,*b):
            print(a)    # 1
            print(b)    # (2,3,4)
        f(1,2,3,4)
    2) 
        def f(**kwargs):
            print(kwargs)    # {'a': 3, 'b': 4}
        f(**dict(a=3,b=4))
        
拆包(解構賦值):
    """
        我說過太屢次了, ES6的語法和Python很像。解構賦值這個詞也是從ES6聽到的。
        不過ES6的解構,還能夠解構 {} 和 解構空值 和 解構默認值,   而Python不能夠
    """
    1)  只要第一個
            a, *_ = range(5)
            print(a, _)     # 0  [1, 2, 3, 4]

    2)  只要第一個和最後一個
            a, *_, c = range(5)
            print(a, _, c)    # 0  [1, 2, 3]  4
            
    3)  只要最後一個
            *_, b = range(5)
            print(_, b)      # [0, 1, 2, 3]  4


函數佔位參數騷操做:
    """
        這是我在源碼中看到的,當時以爲很驚訝,本身試了一下,下面說下本身的理解:
        這個*的做用就是: (*後面的參數是 調用時 必須命名 且 必須傳遞 的參數)
            a你必須給我傳過來,可是你不寫   a=
            b你必須給我傳過來,可是你必須寫 b=
    """
    def f(a,*,b):
        print(a)
        print(b)
    f(1,b=3)    # f(a=1,b=3)    # 只能經過這兩種方式調用

反射-getattr & setattr & hasattr & delattr & import_module

綜合例子:
    from importlib import import_module
    random = import_module('random')          # 動態反射導入模塊  
    # 或 random = __import__('random')         
    if hasattr(random, 'randint'):            # 檢測模塊中是否有函數
        randint = getattr(random,'randint')   # 動態反射導入函數
        print(eval('randint(0,1)'))               # 字符串轉語句執行(相似反射)
    
getattr & setattr & hasattr & delattr 講解:
    hasattr & getattr
        random = __import__('random')
        if hasattr(random,'randint'):    # 檢測 random 模塊中是否有 randint 函數
            randint = getattr(random,'randint')
            print(randint(0,1))
            
    delattr & hasattr 
        delattr(random, 'randint')      # 動態刪除模塊中的 randint函數
        if not hasattr(random,'randint'):
            print('沒有此函數了,讓delattr刪除了')
            
    setattr & getattr                   # 動態從新設置模塊的 randint函數,並給個函數體
        setattr(random, 'randint', lambda:print('設置這個方法湊合用把。'))
        randint = getattr(random, 'randint')
        randint()

模塊從新導入到內存-reload

from imp import reload
import time
reload(time)
print(time.time())

進度條-tqdm

for x in tqdm(range(100)):
    import time
    time.sleep(1)
    print(x)
tqdm包裝一個可迭代對象, 只是裝飾了一下,使用方法仍是像原來同樣使用。

票數統計-Counter

In [2]: from collections import Counter

In [3]: Counter([1,2,3,4])
Out[3]: Counter({1: 1, 2: 1, 3: 1, 4: 1})

In [4]: Counter([1,1,1,2,2,3])    # 統計頻次
Out[4]: Counter({1: 3, 2: 2, 3: 1})

In [5]: Counter([1,1,1,2,2,3]).most_common(1)    # 頻次最多的前1個
Out[5]: [(1, 3)]

文件 複製/移動-shutil

import shutil
shutil.copy(源,目標)    # 複製
shutil.move(源,目標)    # 移動,更名
shutil.rmtree(r'目錄名')  # 刪除目錄(級聯刪除)    # 參數只能是目錄

文件遍歷-os.walk

"""
    os.walk() 是一個深度遍歷模式的文件遍歷函數
    返回值是一個迭代器,遍歷這個迭代器後,每一次的返回值都是以下順序三種構成
        1. current_path: 當前路徑 
        2. dir_list:     其下目錄列表
        3. file_list:    其下文件列表
    
"""
import os
file_generator = os.walk('D:/虛擬E盤-代碼空間/TF2')
for current_dir, dir_list, file_list in file_generator:
    print(current_dir, dir_list, file_list)

非阻塞執行cmd/shell-subprocess

"""
    主要代替os.system
""" 
import subprocess
res = subprocess.run('dir', shell=True, stdout=subprocess.PIPE) # 結果輸入到res管道中去
print(res.stdout.decode('gbk'))    # res管道中有輸出日誌,若是在win下,須要 decode

排列組合-itertools模塊

import itertools
list(itertools.product([1,2,3],repeat=3))    # 複製3份有序全排列, repeat=3    
list(itertools.permutations([1,2,3], 3))     # 內部有序排列, 3表示最後排列爲幾位
list(itertools.permutations([1,2,3,4],3))    # 無序組合, 3表示3位

枚舉-emunerate

In [100]: list(enumerate(list('abcde'),start=1))    # 默認從0,開始標號, start=1就從1開始
Out[100]: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]

In [108]: list(enumerate(((1,2),(3,4))))
Out[108]: [(0, (1, 2)), (1, (3, 4))]        

In [106]: list(enumerate({"a":'c','b':'d'}))
Out[106]: [(0, 'a'), (1, 'b')]

global & nonlocal & globals() & locals()

global: 函數外的變量只能在函數內部取值,而不能修改, 若是想要在函數內部修改外部變量, ‘global 變量名’ 便可
    a = 1
    def f():
        global a
        a += 1
        print(a)
    f()
        
nonlocal: 原理同上如出一轍,只不過應用場景是閉包了,代碼以下:
    def f():
        a = 1
        def f1():
            nonlocal a
            a = a+1
            print(a)
        f1()
    f()

日曆-calendar

import calendar
calendar.calendar(2019)    # 返回2019年的日曆
calendar.month(2919,5)    # 返回2019年5月的日曆
calendar.isleap(2000)    # 判斷2000年是否爲閏年

時間/日期-time/datetime

import time
1. 時間戳:
    time.time()
    
2. 字符串轉時間(p-pass方便記憶)
    from datetime import datetime
    fordate = datetime.strptime('2019-5-25 9:30:30', '%Y-%m-%d %H:%M:%S')
    print(fordate)

3. 時間轉字符串(f-from方便記憶)
    from datetime import datetime
    strdate = datetime.strftime(fordate, '%Y-%m-%d %H:%M:%S')
    print(strdate)
    
4. 初始化時間
    from datetime import datetime
    dt1 = datetime(2019,5,25,9,37)    # 初始化時間爲 datetime格式
    dt1 = datetime.now()   # 獲取當前時間爲 datetime格式
    print(dt1.year)
    print(dt1.month)
    print(dt1.day)
    print(dt1.hour)
    print(dt1.minute)
    print(dt1.second)
相關文章
相關標籤/搜索