Python精要

入門文章太啰嗦,參考文檔太龐大。
總結(jié)個精要速查,感覺要更直接些。
如果腦子里記得,直接看快速復(fù)習(xí)。
如果腦子不記得,這里就當(dāng)索引吧。
太久沒更新,也太久沒用Python了,回看自己寫的都暈了。慢慢補(bǔ)上示例吧,但精要仍是這篇日志要追求的——2021.3

胡言亂語:Python這個語言有點奇葩,自帶Pythoner的文化和約定熟成,其他語言轉(zhuǎn)過來的程序員看Pythonic的代碼還真會有點莫名其妙。當(dāng)這些“約定”比關(guān)鍵字還多時,你會發(fā)現(xiàn)其實這東西并不是那么容易上手的,特別是看別人的代碼時。明明用人話(應(yīng)該是標(biāo)準(zhǔn)程序流程)來實現(xiàn)的邏輯,Pythoner可以用更簡潔的代碼實現(xiàn)(比如一行天書般的代碼干了很多事情),其中包含了門外漢不明白的某些“隱喻”,或者被稱為語法糖?。無疑,這增加了初學(xué)者學(xué)習(xí)的難度,當(dāng)然同時增加了入門后的裝逼資本。

  1. 語法與書寫風(fēng)格:縮進(jìn)風(fēng)格是Python特有的,每縮進(jìn)一級相當(dāng)于一層代碼塊。注釋用#(單行)和''' '''及 """ """(多行)。三引號是定義多行字符串不賦給變量即用于注釋。變量、函數(shù)命名大小寫敏感,__name__之類的變量名是預(yù)定義的,如程序是直接被解釋器調(diào)用執(zhí)行,則__name__的值為字符串'__main__'。
# This is a test
def foo(p: str):
    """
    Description of the function of foo
    :param p: Description of parameter a
    :return: Description of return value
    """
    print(a)
if __name__=='__main__':
    foo('Hello world')
  1. 常用數(shù)據(jù)類型:Python是動態(tài)強(qiáng)類型語言,變量可以保存"單值",對象和函數(shù)(實際上Python中萬物皆對象,int整型也是,變量名只是對象地址空間的引用,內(nèi)存是動態(tài)管理的,當(dāng)一個變量被賦新值時并不是在原來地址寫入新值,而是原有的地址被放棄交由垃圾回收機(jī)制處理,在新地址創(chuàng)建新值并將變量名引用到新地址
  • "單值"數(shù)據(jù)類型:數(shù)值(整,浮,復(fù)x+yj),布爾
  • 字符串(字符序列,可切片可索引但不可修改元素),字符串定義的前綴修飾:b'123'定義bytes,u'abc'定義unicode字符串(Python3已不需要),r'a\b'不進(jìn)行轉(zhuǎn)義,f'abc:{abc}'格式化變量到字符串中完成拼接。
  • None 表示一個空對象
a = 1
a = a + 1.2 # 升為浮點數(shù)
c = a + '-' + b # 錯:類型不兼容,必須顯式轉(zhuǎn)換
a = '1' # 但可以重新賦值
d = 1 + 2j # 復(fù)數(shù),好像一般用不到
# 以上操作本質(zhì)都是動態(tài)內(nèi)存操作,值或類型變化實際是生成了新值重新綁定到變量上,語法層面顯示出動態(tài)和強(qiáng)類型特征
  • 類型轉(zhuǎn)換:int()/str()/float()/complex(),類型名對應(yīng)的函數(shù)完成轉(zhuǎn)換
  • bytes類型與str類型及轉(zhuǎn)換: bytes可以看成是裸字節(jié),這些字節(jié)表示什么,需要提供編碼信息如encoding='utf-8'
a = b'abc'
b = str(a, encoding='utf-8')  # 'abc'
c = bytes(b, encoding='utf-8') # b'abc'
a == c # True
  1. 運(yùn)算符:
    算術(shù)運(yùn)算:+-/%,*冪,//整除
    邏輯運(yùn)算:比較類似C語言== > < >= <=,邏輯表達(dá)式is/is not,in/not in,not,and,or(優(yōu)先級遞減),當(dāng)然優(yōu)先級()走遍天下。比值相同用==,比地址相同用is。相關(guān)應(yīng)用:比類型家譜type().__name__/isinstance()/issubclass()。仿三目運(yùn)算:a=b if condition else c。
    整數(shù)位操作:&|^~>><<

  2. 序列、集合與字典:

  • 序列:tuple和list;集合:set;字典:dict。存放多值或鍵值對
  • 序列與集合的特點總結(jié): tuple: ()有序-只讀-可重復(fù),list: []有序-讀寫-可重復(fù),set:{}無序-讀寫-非重復(fù),有序類型支持索引取值
  • 共性:len(O)計數(shù),max(O)/min(O)取最值,O.clear()清空,i in/not in O,for i in O,最值計算可自定義比較的key:
# 示例數(shù)據(jù):一個包含字典對象的列表
data = [
    {'name': 'Alice', 'score': 85},
    {'name': 'Bob', 'score': 92},
]
# 自定義比較函數(shù),按分?jǐn)?shù)找到最高分
def get_score(student):
    return student['score']
# 輸出最高分的學(xué)生信息
print(max(data, key=get_score)["name"])  #Bob

序列可作為參數(shù)傳入iter()生成迭代器

x = [1, 1, 3, 2]
x = list(set(x)) # 去重
a = (1,2,3)
print(len(a)) # 3
print(1 in a) # True
i = iter(a)
print(next(i)) # 1
print(next(i)) # 2
print(next(i)) # 3
  • 索引(僅序列類型支持):
    • 支持多維;
    • list/tuple有序,0正序起始/-1倒序起始,切片;支持.count(item)對某元素計數(shù);支持+和*運(yùn)算符累加序列
a = (1,2,3)
print(a[0]) # 1,首位
print(a[-1]) # 3,末位,注意與下面切片的區(qū)別
print(a[:-1] # (1,2),切片操作:注意不含末位,這里a[:-1]與a[:2]等價,結(jié)果為(1,2)
print(a[:2]) # (1,2)
print(a[:3] # (1,2,3),含末位,大于列表長度不報錯,只取到最末位,a[:3]與a[:]等價
  • dict無序,O[’keyname‘] 訪問元素,字典的key可以是數(shù)值序號,更常用是字符串
  • 修改(tuple只讀除外):
    • list通過索引位置O.append(item)/O.extend(seq)/O.insert(idx,item)/O.pop([idx=-1])增/返回并刪,索引元素賦值修改,值刪除O.remove(),O.sort(key=None, reverse=False)/O.reverse()換序
    • dict直接通過['keyname']索引元素增改;O.update(dict)增加,O.pop('keyname',[default])返回并刪除元素,迭代用O.keys()/O.values()/O.items()
    • set通過O.add(item)/O.update(seq)增加,O.remove(val)/O.discard(val)刪除,O.pop()隨機(jī)刪除。
    • 通用刪除:del var刪除變量(對數(shù)據(jù)的引用)達(dá)到刪除變量及元素(如能索引到)的目的。
    • list,dict,set的賦值=為引用,要拷貝使用O.copy()方法,注意為淺拷貝,元素中的序列類型仍引用原地址。要使用深拷貝,import copy模塊,new=copy.deepcopy(old)
  • 注意:
    • tuple:只讀;定義單元素tuple元素后要加逗號結(jié)尾,
    • set:不重復(fù),可用兩個相反類型轉(zhuǎn)換去重list;支持&|集合運(yùn)算;空集合用set()創(chuàng)建
    • [含x表達(dá)式 for x in list]生成按各元素按表達(dá)式計算的新列表
  1. 字符串續(xù):
  • 編碼與表示:python 3內(nèi)碼為unicode,前綴u'字符串'已不必要,'\u十六進(jìn)制編碼'等價于該內(nèi)碼unicode字符。前綴b'字符串'等價于bytes串(ascii)。.encode()/.decode():unicode,utf-8,gb2312,gbk...與對應(yīng)編碼的byte序列互轉(zhuǎn);前綴r'字符串'忽略串中轉(zhuǎn)義符(raw的意思)
  • 轉(zhuǎn)義:\oii八進(jìn)制數(shù),\xii十六進(jìn)制數(shù),\000空,行尾\續(xù)行
  • ’’’ ’’’/“”“ ”“”:生成raw字符串,可用于注釋
  • 運(yùn)算:+,*;序列操作(for in,索引,切片,len(),in/not in,iter()參數(shù));格式化(類C):'%s%d%.2f'%('ABC',1,3.1415)
  • 方法:.replace(),.split(),.join(),.strip(),.is...系列,.find()/.index()
  • 單字符操作:ord(),chr()
  • 注意,與C/C++不同Python字符串不能通過下標(biāo)索引修改其中的字符
  • 有時字符串可以看成一種序列類型(沒有clear等方法),但可以使用len(),max(),min()函數(shù)對其操作
  • 與序列類型一樣可以用for i in X或內(nèi)置函數(shù)for i, element in enumerate()來遍歷,用in和not in檢查是否包含字符
  1. 控制:
  • 縮進(jìn)形成代碼塊,條件if/else/elif,循環(huán)for in/while,break/continue,range(start,stop[,step])常用于生成for in序列
  • with context [as var]:(換行) block,語句塊結(jié)束會關(guān)閉上下文,類似try finally,但不捕獲異常。常用于文件處理等,這個上下文是一個自定義類,必須實現(xiàn)__enter__和__exit__方法,具體見類。
  • pass占位符
  1. 異常:
    try:
    except Exception1 as e1: # 捕獲特定異常
    else: # 無異常的處理
    finally: # 無論如何都處理
    raise # 拋出異常
    異常處理可以層疊,直到最后finally
  2. 函數(shù):def func(para, defpara=default, *args, **args): block return [expression](此處省略換行縮進(jìn))
  • 參數(shù):str,number,tuple為值復(fù)制,其他對象為傳引用(事實上作為性能優(yōu)化,只要不修改值的內(nèi)容,任何參數(shù)傳入時都是引用,str/number/tuple會在值被修改時才復(fù)制,而函數(shù)內(nèi)創(chuàng)建的值作為返回值,調(diào)用者也是直接引用同一地址,直到值被修改而創(chuàng)建新的地址)
  • 返回值:return 表達(dá)式,可以為任意對象
def foo(param1: int):
    print(id(param1))
    param1=2
    print(id(param1))
    return param1
a = 1
print(id(a))
a = foo(a)
print(id(a))
  • 調(diào)用:指定參數(shù)名可無視順序,不輸入的使用默認(rèn)參數(shù)(如有否則報錯),不定長參數(shù):從定長位置之后的部分,*聲明的會作為tuple傳入,**聲明的調(diào)用時必須以鍵值對輸入?yún)?shù)會作為dict傳入
  • 函數(shù)是一個對象,保存在對應(yīng)的命名變量中,變量可指向新的函數(shù)而“覆蓋”系統(tǒng)函數(shù)。
  • 特殊函數(shù)
    • 生成器/迭代器:使用yield輸出某次結(jié)果的函數(shù),函數(shù)返回值是一個迭代器對象,使用next(迭代器對象)獲得下一次yield輸出。yield保留函數(shù)作用域結(jié)束當(dāng)前運(yùn)行輸出相應(yīng)的值,等待下一次被next()調(diào)用時繼續(xù)運(yùn)行,一般在循環(huán)體內(nèi)實現(xiàn)迭代直至到return語句釋放作用域中的變量。只要函數(shù)出現(xiàn)了yield,return的返回值就作廢了,return僅作為函數(shù)終點比如有條件提前結(jié)束迭代(函數(shù)返回值固定為迭代器對像obj,取下個輸出通過next(obj)得到y(tǒng)ield返回值)。
def _range(start, end): 
    while start < end: 
        yield start # 每次被調(diào)用next或for迭代到這里返回start的值,直到最后一個yield結(jié)束,局部變量的值仍保持,下次迭代從這里繼續(xù)往下執(zhí)行
        start += 1
for i in _range(1, 5): 
    print(i) # 每次迭代得到一個返回值
  • 函數(shù)參數(shù):函數(shù)本身也是對象,可作為參數(shù)傳給其他函數(shù),函數(shù)名也就是一個函數(shù)對象的變量引用(Python中你甚至可以覆蓋系統(tǒng)函數(shù)——函數(shù)名也只不過是個指向函數(shù)對象的引用,所以,你可以用exit=print這樣的語句把exit()函數(shù)的功能變成print())。
  • 函數(shù)返回值/閉包:函數(shù)本身可作為返回值,如將函數(shù)(母函數(shù))內(nèi)部嵌套的函數(shù)作為返回值返回,從而使母函數(shù)作用域中的參數(shù)、變量打包入該返回函數(shù)以在外部繼續(xù)訪問,該子函數(shù)要修改母函數(shù)變量在函數(shù)定義中要nonlocal聲明,注意如子函數(shù)中如修改了母函數(shù)的變量,該修改會一直保持,再次調(diào)用該子函數(shù)時可能影響結(jié)果——但多次調(diào)用母函數(shù)返回的閉包子函數(shù)相互不影響。
  • 高階函數(shù)/裝飾器:高階函數(shù)是參數(shù)或/和返回值為函數(shù)的函數(shù)。典型高階函數(shù):map(func1, list),reduce(func2, list),map中的func1接受一個參數(shù)依次計算list元素,reduce中的func2接受兩個參數(shù)依次從list中取元素計算并將結(jié)果作為下次計算的第一個參數(shù)。裝飾器是一種高階函數(shù),接收一個函數(shù)參數(shù)返回一個函數(shù),從而實現(xiàn)了將傳入的函數(shù)增加功能的能力(返回的函數(shù)調(diào)用傳入函數(shù)又運(yùn)行了自己的額外代碼)。
from functools import wraps

def d1(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        print("Before calling")
        res = f(*args, **kwargs)
        print("After calling")
        return res
    return decorated

高階函數(shù)是用代碼實現(xiàn)的,所以本質(zhì)上不屬于語法層面的規(guī)則,但Python規(guī)定了用@號加裝飾器名放在原函數(shù)定義的前一行的語法規(guī)則,即覆蓋了原函數(shù)名,使其指向了裝飾器的返回函數(shù)。

@d1
@d2
def foo():
    pass
# 以上代碼等價于代價:
def foo():
    pass
foo = d1(d2(foo))
# 所以,@語法 是語法規(guī)則,還是語法糖?

需要注意:單改變函數(shù)名指向不一定保證正常工作,因包裝了舊函數(shù)的新函數(shù)與舊函數(shù)是兩個對象,具有不同的屬性。完整的裝飾器需要用functools模塊中的@functools.wraps(傳入函數(shù))來裝飾返回函數(shù)。好吧,本質(zhì)上wraps裝飾器完成了一堆從舊函數(shù)到新函數(shù)的屬性拷貝讓返回的新函數(shù)“更像”傳入的舊函數(shù)。裝飾器的寫法看起來很像C/C++代碼中的宏,看到的時候就當(dāng)是吧,想像一下腦子里展開宏的崩潰狀態(tài)。。。裝飾器似乎更繞人,知道是干什么的就不求甚解了吧。。。
另外,需要知道裝飾器可以是一個類的方法,而不一定要是一個獨(dú)立函數(shù)。
@裝飾器語法本身可帶參數(shù),帶有參數(shù),則表示該“裝飾器”傳入的不是被裝飾函數(shù),而是該語句指定的參數(shù),而返回值則是一個真正的裝飾器(它的參數(shù)才是@語句后面被裝飾的函數(shù) ),這個真正的裝飾器是一個三層子母函數(shù)的中間層??聪旅娴睦樱?/p>

# 一個用類封裝的不定長參數(shù)裝飾器的例子
from functools import wraps

class MyAuth(object):
    # 此裝飾器是某類的方法,使用時用 @Auth.login_required(參數(shù)) 修飾其下的函數(shù)
    # 需要支持參數(shù)的裝飾需要三層,中間的bridge函數(shù)是一個中介,其中使用@warps裝飾器完成屬性拷貝
    @classmethod
    def login_requried(cls, *_args, **_kwargs):
        def bridge(f):
            @wraps(f)
            def decorated(*args, **kwargs):
                for i in _args: # 打印裝飾器參數(shù)
                    print(i)
                return f(*args, **kwargs)
            return decorated
        return bridge

@MyAuth.login_requried(1,2,3,4)
def func(*args):
    for i in args: # 打印被裝飾函數(shù)參數(shù)
        print(i)

# @MyAuth.login_requried(1,2,3,4)的語法本質(zhì)是以下兩句,b是中介,即上面定義的bridge函數(shù)對象。無參數(shù)的裝飾器無需bridge中介函數(shù)。
# b = MyAuth.login_requried(1,2,3,4) # 構(gòu)建了bridge函數(shù)對象b,此時參數(shù)被記錄在其對應(yīng)作用域中——所謂閉包。
# func = b(func) # b函數(shù)是一個裝飾器,返回了新的decorated函數(shù)對象
# 再簡單粗暴點就是:func = MyAuth.login_requried(1,2,3,4)(func) 

if __name__ == '__main__':
    func(5,6,7) # 結(jié)果是打印 1 - 7
  • 匿名函數(shù):lambda 參數(shù)表:返回表達(dá)式,可作為表達(dá)式調(diào)用,也可作為函數(shù)返回值保留到變量中。
  • 內(nèi)置函數(shù)(from www.runoob.com):
_ _
abs() divmod() input() open() staticmethod()
all() enumerate() int() ord() str()
any() eval() isinstance() pow() sum()
basestring() execfile() issubclass() print() super()
bin() file() iter() property() tuple()
bool() filter() len() range() type()
bytearray() float() list() raw_input() unichr()
callable() format() locals() reduce() unicode()
chr() frozenset() long() reload() vars()
classmethod() getattr() map() repr() xrange()
cmp() globals() max() reverse() zip()
compile() hasattr() memoryview() round() __import__()
complex() hash() min() set()
delattr() help() next() setattr()
dict() hex() object() slice()
dir() id() oct() sorted() exec 內(nèi)置表達(dá)式
  1. 模塊與包
  • 一個.py即為一個模塊,import 模塊名或from 模塊 import 函數(shù)/變量/類,會導(dǎo)致在sys.path中的路徑搜索,可以使用as關(guān)鍵字給導(dǎo)入的模塊或?qū)ο笕e名防止沖突或簡化書寫
  • 一個目錄包含__init__.py即為一個包,__init__.py中提供一個__all__列表即可向from 包.模塊 import *提供要導(dǎo)入的名稱
  • import 模塊,后面要用模塊名.函數(shù)名調(diào)用;from 模塊 import 對象,后面可直接用對象名調(diào)用
  • __init__.py文件中也可以寫代碼,定義變量與方法,并可以用包名.變量/方法名來引用或?qū)耄唤ㄗh這么做,更常見的做法一個組件包是把代碼寫在子包或模塊中,但在它的__init__.py中import所有子包中的對象,然后其他代碼再通過包名.對象名間接引用或?qū)?,因此不用記住對象所在的子包或模塊。
  • 關(guān)于一個包內(nèi)模塊間的相互引用,如果它們是平級目錄的,用import .模塊名,或from .模塊名 import 對象名,注意點號,但這種模塊本身是不能直接通過
if __name__="__main__":
    somecode

來直接運(yùn)行測試的,需要使用另外的方式如用測試框架來測試。這種代碼如要運(yùn)行,要使用import 模塊名來引用同級目錄模塊,即去掉模塊名前面的點號。這將導(dǎo)致模塊測試時的代碼與包被外部代碼使用時的不一致,因此不建議模塊內(nèi)部寫測試代碼(一種不優(yōu)雅的做法是加路徑到sys.path搜索路徑)。
基本原則:
1.在同一級包下的兩個子module之間, 有引用關(guān)系(并采用relative import相對路徑方式導(dǎo)入)時, 應(yīng)當(dāng)在包的上級目錄中運(yùn)行這些代碼, 而不應(yīng)該在子模塊運(yùn)行,而module之間用相對路徑方式引用,如.代表當(dāng)前目錄,..代表上級目錄,...代表上上級目錄,以此類推;
2.因此當(dāng)需要在子模塊中引用這些代碼來作為程序運(yùn)行時, 需要棄用點號相對引用, 改用模塊名或者包名.模塊名的方式引用;

  1. 模塊名方式的引用,通俗就是去掉那個.號; 但是這個只適用于自定義的模塊名與sys.path路徑下模塊不能出現(xiàn)重名;
  2. 包名.模塊名的方式需要在sys.path中添加包的上級目錄路徑; 又因為不推薦在子模塊里面引用同一包中的上層模塊. 所以99.99%的情況使用sys.path.append(os.path.dirname(os.path.dirname(os.pathabspath(__file__)))). 可以滿足需求; 其他修改sys.path的方法當(dāng)然也是可以的.
    總結(jié): 不要直接運(yùn)行導(dǎo)入了同級別模塊的模塊. 而應(yīng)該在包的上層目錄導(dǎo)入這個模塊運(yùn)行, 要注意設(shè)計模式本身. 從而避免代碼雜亂無章.
  • 作用域:讀查找順序:局部變量->nonlocal變量如閉包->全局變量->內(nèi)建變量,修改:局部和內(nèi)建可改,nonlocal和global要先聲明
  • 注意:全局變量是模塊級的,要在多模塊的應(yīng)用中共享全局變量,需要import module,然后用module.variable引用,建議用一個模塊專門管理所有全局變量。from module import variable,會從引用的模塊拷貝出一個本地變量,對本地變量的修改,不會影響原模塊的值,即import之后,兩個變量就無關(guān)了。
  • _開頭的變量約定為模塊內(nèi)私有但不強(qiáng)制
  • 關(guān)于標(biāo)準(zhǔn)庫 https://www.runoob.com/python3/python3-stdlib.html
  • 繼承,支持多重繼承,語法:class subclass(base1,base2,...): ,如多個父類有相同屬性或方法,按MRO順序即前面的優(yōu)先繼承到子類。
  • 方法首參數(shù)必須為self/this
  • 子類可重寫父類方法,并用super()復(fù)用父類方法
  • 訪問權(quán)限:
    • __開頭的成員為私有
    • @property裝飾器,在命名為屬性的方法前加@property,用該方法返回數(shù)據(jù)成員,同時自動創(chuàng)建了一個@屬性名.setter的裝飾器,用來修飾setter方法修改數(shù)據(jù)。沒有setter方法的屬性為只讀。
  • __init__:構(gòu)造方法,其中初始化的self.變量名成為數(shù)據(jù)成員。單獨(dú)寫的數(shù)據(jù)成員為類靜態(tài)成員。
  • __str__:支持對象以字符串輸出顯示
  • __call__:支持對象當(dāng)函數(shù)調(diào)用
  • __contains__:使對象支持in查詢
  • 運(yùn)算符重載:重寫__add__,__sub__,__mul__,__truediv__等方法
  • @classmethod和@staticmethod裝飾器,使方法成為類方法或靜態(tài)方法。靜態(tài)方法不需要第一個self參數(shù),靜態(tài)方法只能訪問靜態(tài)成員。
  • 迭代器:實現(xiàn)__iter__方法初始化并返回自己和__next__方法返回下個元素,用iter(clsname)實例化obj,用next(obj)迭代
  • 能使用with的類:實現(xiàn)__enter__,__exit__方法。
  1. 作用域
    Python 中只有模塊(module),類(class)以及函數(shù)(def、lambda)才會引入新的作用域,其它的代碼塊(如 if/elif/else/、try/except、for/while等)是不會引入新的作用域的,也就是說這些語句內(nèi)定義的變量,外部也可以訪問。
    基本規(guī)則:
  • 外層不能訪問內(nèi)層,無嵌套關(guān)聯(lián)的內(nèi)層之間也不能訪問
  • 內(nèi)層能訪問外層,但不能修改,要修改必須用global(訪問最外層)或nonlocal聲明(訪問嵌套的上層)要訪問的變量。

Last. 吐槽:Python是一種語言層面極靈活極沒有規(guī)則的語言,然后用了一些語義與約定代替其他語言的特性(所謂語法糖?),比如:

  • 沒有代碼塊標(biāo)識,只有用:號跟隨的縮進(jìn)能標(biāo)識為代碼塊:縮進(jìn)是強(qiáng)制的,不要指望從網(wǎng)上復(fù)制粘貼來的混亂代碼能reformat
  • 命名約定代替了關(guān)鍵字,如:
    • __init__.py作為包標(biāo)識,當(dāng)然目錄名為包名,文件名為模塊名的做法Java也一樣
    • 各種特定的__XXX__變量比關(guān)鍵字多,也就是說起個名字,加個前綴就等于其他語言里的關(guān)鍵字定義
    • _前綴與模塊私有變量:約定但不強(qiáng)制
    • 裝飾器的語法,算語法糖,還是語法規(guī)則?如果單純語法上能定義裝飾器,為什么還需要額外的functools.wraps模塊?通過@property裝飾器實現(xiàn)類屬性定義,這個@property裝飾器算是Python語法的一部分么?感覺上裝飾器更像是編碼技巧,編程模式層面的東西。。。
  • OOP編程里組合優(yōu)于繼承,好的編程思想會形成習(xí)慣,但是真的一切都要模式化嗎?好的代碼沒學(xué)過設(shè)計模式的人看了也會覺得“優(yōu)雅”吧,但是像Mixin這種感覺真是為模式而模式了,但是你不得不去學(xué)去用,因為你要看別人的代碼,不得不去接受這種Pythonic風(fēng)格。
  • 太多太多約定和模式,加上標(biāo)準(zhǔn)庫,所以學(xué)Python可以很精要(學(xué)很少的東西就有了一堆零件),又無法很精要(但是要組裝成能上戰(zhàn)場的武器,你得看一大堆“使用手冊”),當(dāng)然,如果做一個數(shù)據(jù)工作者,用Jupyter Notebook就夠了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容