Python3 - 復(fù)習(xí)(update to Day6)

# 第一優(yōu)先級(jí)規(guī)則聲明:

# 除了夢境,每一個(gè)意識(shí)主進(jìn)程都必須與一個(gè)身體參與的機(jī)械進(jìn)程相匹配,否則結(jié)束意識(shí)主進(jìn)程。如學(xué)習(xí)python同時(shí)必須伴有記筆記、敲代碼等機(jī)械進(jìn)程,學(xué)習(xí)英語必須伴有朗讀、聽說、查字典、查語法書等機(jī)械進(jìn)程跟隨,拆解問題必須在紙上或iPad上實(shí)時(shí)記錄意識(shí)的每一次嘗試。

如果身體狀況或是客觀情況不允許有機(jī)械進(jìn)程存在,請轉(zhuǎn)入其他進(jìn)程,如注意力恢復(fù)(閉目養(yǎng)神、睡覺)或是娛樂進(jìn)程(健身、看電影等)。

# 此優(yōu)先級(jí)將在每一個(gè)意識(shí)進(jìn)程前聲明。


Day1:

Why Python 3.5(意義賦予):?

- Life is short and I need python.?

- 以前沒有編程基礎(chǔ),只有Linux和MySQL的基礎(chǔ)。

- 每天能抽出時(shí)間不多。

- 工作的強(qiáng)烈需求。

- Python大量的第三方庫

- 開源社區(qū)的強(qiáng)力支持

- 3.5總比2.7強(qiáng),長遠(yuǎn)來看

Installation: 略

IDLE: Pycharm

編碼聲明:

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

也可以借助pycharm右下角的編碼來修改,或是notepad++的encoding-轉(zhuǎn)為utf-8無BOM格式

I/O:

print()

print在python3.5中正式成為函數(shù),允許用“,”分隔多個(gè)字符串,也接受數(shù)學(xué)計(jì)算

input()

接受用戶的輸入,同時(shí)也接受()內(nèi)插入內(nèi)容。

如果要規(guī)范輸入的內(nèi)容,可以用這種方法

int(input(...))

代碼風(fēng)格:

python使用縮進(jìn)來組織代碼塊,請移動(dòng)使用4個(gè)空格的縮進(jìn)(pycharm會(huì)對(duì)不規(guī)范的代碼風(fēng)格給出波浪下劃紅線的warning)

數(shù)據(jù)類型和變量:

類型在python中極其重要,最常見的報(bào)錯(cuò)就是“你不能對(duì)xx類型進(jìn)行xx操作”!

整數(shù)integer:正整數(shù),負(fù)整數(shù),0

浮點(diǎn)數(shù)float:小數(shù)(叫浮點(diǎn)數(shù)是因?yàn)橛每茖W(xué)計(jì)數(shù)法表示,一個(gè)浮點(diǎn)數(shù)的小數(shù)點(diǎn)位置可變),存在四舍五入的誤差。

字符串string:單引號(hào)或者雙引號(hào)括起來的任意文本(里邊有特殊符號(hào)請轉(zhuǎn)義)。需要轉(zhuǎn)義的入托太多,用r'string' 來帶來一大堆的\。計(jì)算string多長,用len()

布爾值:True/False 1/0。如果True/False拼錯(cuò)了或者大小寫出錯(cuò),并不會(huì)識(shí)別為布爾值(在pycharm中識(shí)別成為橙色)??杉訙p乘除,可and/or/not。

空值:None

變量賦值符號(hào)是“=”,等于號(hào)是‘==’,所以請正確理解

x = 3

x = x + 3

賦值過程依照語句順序而來。

常量:不能變的變量

Python支持多種數(shù)據(jù)類型,可以把任何數(shù)據(jù)都看成一個(gè)對(duì)象,

- 變量就是在程序中用來指向這些數(shù)據(jù)對(duì)象的。

- 對(duì)變量賦值就是把數(shù)據(jù)和變量給關(guān)聯(lián)起來

字符串和編碼

Python3支持中文

1個(gè)中文字符經(jīng)過utf-8編碼后占用3個(gè)字節(jié),一個(gè)英文字符占用1個(gè)字節(jié)。

格式化:

格式化的使用頻率非常高,其應(yīng)用主要在于占位符的使用

%s 字符串(如果不清楚數(shù)據(jù)類型,可以用%s來接受一切)

%d 整數(shù) (整數(shù)接受%002d這種表達(dá),來填充位數(shù))

%f 浮點(diǎn)數(shù)(浮點(diǎn)數(shù)接受%.3f這種表達(dá),來截取位數(shù))

%s 字符串

%x 十六進(jìn)制整數(shù)

%%來表示正常的百分比

條件判斷和循環(huán)

計(jì)算機(jī)可以自動(dòng)化,其中最重要的原因就是因?yàn)橛袟l件判斷和循環(huán)

條件判斷

(注意冒號(hào)!)

if <條件判斷1>:

<執(zhí)行1>

elif <條件判斷2>:

<執(zhí)行2>

elif <條件判斷3>:

<執(zhí)行3>

else:

<執(zhí)行4>

if 語句從上往下判斷,如果某個(gè)判斷是True,執(zhí)行完畢就不執(zhí)行了。

循環(huán)

1. 遍歷式循環(huán)(for x in ...)

for i in ... :

.......

2. while循環(huán): 只要條件滿足,就不斷循環(huán)(類似scratch里用if和forever在循環(huán)中結(jié)合的用法)

不過代碼會(huì)出現(xiàn)死循環(huán)(如果寫的有問題),就像Human Resource Machine里小人不停地搬箱子。這時(shí)候可用ctrl+c結(jié)束(與linux一致)

List和Tuple:

list: 列表,python內(nèi)置。是一種有序的元素集合(或者說容器),元素是什么數(shù)據(jù)類型都可以可以隨時(shí)添加和刪除其中的元素()。同樣,可以用len()獲取list中的個(gè)數(shù)(string也能進(jìn)行l(wèi)en()操作,因?yàn)閟tring本質(zhì)上也是list)

訪問list中的每個(gè)元素需要通過索引(索引:從0開始的序列號(hào)),格式為list[1],超出索引報(bào)錯(cuò)IndexError。也可以通過負(fù)數(shù)的索引號(hào)來倒取元素

支持list.append(),追加元素到末尾

支持list.insert(index, 'element'),插入元素到指定位置。

支持空List,且len(List)為0

因?yàn)閘ist是可變的,所以才可以list.sort()來排序

Tuple: 不可變的list是tuple, 不能append/insert操作,可以用索引取值,但不能再次賦值了。

tp = ()

tp = (1,) 如果要定義的是tuple, 務(wù)必通過括號(hào)內(nèi)逗號(hào)來消除歧義。


Dict和Set

dict

其他語言中也稱之為map, 使用key-value存儲(chǔ),優(yōu)點(diǎn)是查找速度極快。

d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}

為什么查找dict特別快,比查找list要開快得多呢? list查詢是遍歷查詢,從第一個(gè)翻到最后一個(gè),查詢速度直接取決于list大小。dict直接計(jì)算出對(duì)應(yīng)的位置,直接取出,非???。根據(jù)什么算出來呢?就是key-value。

dict有個(gè)缺點(diǎn):占用內(nèi)存大。正因?yàn)槿绱耍每臻g換時(shí)間,占用空間大,所以查找速度快。

既然是通過Key來查找,那么key一定要是不可變對(duì)象。通過key來計(jì)算位置的算法,就叫做hash算法。

要保證hash正確性,那么key就不可變(如字符串和整數(shù))。但是list這種就是可變的,就不能作為Key。這時(shí)候報(bào)錯(cuò)就是Typeerror: unhasable type

d['barry'] = 90 這個(gè)過程跟給變量賦值沒什么區(qū)別,相當(dāng)于給key這個(gè)變量賦值。

調(diào)用不存在key的,會(huì)返回keyerror。

怎么判斷Key在不在dict里呢?

1. 可以通過key in dict來判斷,會(huì)返回布爾值。

2. 也可以d.get['barry']。如果key不存在,可以返回None, 或者自己制定的value

d.get['key', value]

要?jiǎng)h除一個(gè)Key,就d.pop('key').

既然是一個(gè)字典dict,那么哪一對(duì)key-value在前面是無所謂的。也就是說,無所謂key-value的順序,什么時(shí)候放入的不重要。

set

set和dict唯一的區(qū)別就是,只存儲(chǔ)Key,不存儲(chǔ)value。因?yàn)閐ict內(nèi)部key就不能重復(fù),所以set里邊的元素也不能重復(fù)(即使重復(fù),也會(huì)自動(dòng)會(huì)被過濾)。一樣,單純的key集合也無所謂先后順序。

這樣,才形成了set數(shù)學(xué)意義上的無序+無重復(fù)元素的集合。

s = set(list)

list = [1, 2, 3]

可以通過add(key)來添加元素(key)到set當(dāng)中,重復(fù)添加倒是可以,不過還是會(huì)被過濾掉。

可以通過remove(key)來刪除元素。

可以s1 & s2 取交集,s1 | s2取并集。(跟linux非常相似)

可變和不可變

不可變對(duì)象(如string)調(diào)用對(duì)象自身的任意方法,也不會(huì)改變對(duì)象自身的內(nèi)容。相反這些方法會(huì)創(chuàng)建新的對(duì)象然后返回,這樣就保證了不可變對(duì)象的不便。

函數(shù)

函數(shù)是啥?函數(shù)本質(zhì)上就是把一些現(xiàn)成的功能寫成一個(gè)封裝的包(跟第三方庫非常像),調(diào)用即可。也就是說,函數(shù)可以自己寫,也可以用寫好的現(xiàn)成的。比如不用每次都寫平方或者指數(shù)不需要每次都寫x * x...這種底層寫法。很多函數(shù)內(nèi)置,很多函數(shù)在可調(diào)用庫。(import大法好?。?/p>

抽象

抽象是啥?每次都還原成最底層代碼煩不煩?那你需要抽象!

抽象可以使我們每次都調(diào)用一些聚合過的概念,如求和西格瑪符號(hào)。

有好多內(nèi)置函數(shù)(build-in functions),可以直接調(diào)用。(至少讀一遍,知道都有啥。Python真的是能夠做到,你能想到的函數(shù),99%都有之前人寫過,stack overflow/github/python各種庫,多讀讀)

Built-in functions:

數(shù)學(xué)運(yùn)算類:

abs(x) 取x的絕對(duì)值

divmod(a, b) 返回(商,余數(shù))

float(x) 取浮點(diǎn)數(shù) ;bool() 取布爾值; str()轉(zhuǎn)換成字符; int() 轉(zhuǎn)換成正整數(shù)

int(x, base=n) 取整數(shù),base是可選的,表示進(jìn)制) 也可以long(x, base=n) 轉(zhuǎn)Long

pow(x, y, z) x的y次方(如果z存在,那么再對(duì)結(jié)果取模)

range([start], stop[, step]) 產(chǎn)生一個(gè)序列,規(guī)定結(jié)束,可以規(guī)定開始和步長。

round(x[,n) 四舍五入,可以規(guī)定n位數(shù)

sum(iterable[, start]) 對(duì)可迭代對(duì)象求和

集合操作符

iter(o[, sentinel) 生成一個(gè)對(duì)象的迭代器,第二個(gè)參數(shù)表示分隔符(?)

max() min() 最大最小值

dict() set() list() str() tupe()創(chuàng)建

sorted(iterable, key=None, reverse=True/False) 排序

all(iterable) 集合中的所有 元素都為真時(shí)候?yàn)檎?,空串返回為真?/p>

any(iterable) 任一為真就為真

IO操作

input() 獲取用戶輸入

open(file_name, mode) mode可以是'r', 'w', 'a'

print() 打印函數(shù)

神器

help()

函數(shù)

自己動(dòng)手寫函數(shù)

def my_abs(x):

if x > = 0:

return x

else:

return -x

邏輯是: 執(zhí)行到return就結(jié)束了。沒有return,函數(shù)執(zhí)行完畢,返回None

如果某一個(gè)步驟沒想好,還可以直接pass(放過),占著位置

一個(gè)函數(shù)的功能完善,包括三方面的完善: stdin, stdout, stderror。所以如果我們要自己定義一個(gè)完善的函數(shù),必須包括這三個(gè)方面。要不然調(diào)用函數(shù)錯(cuò)誤,都不知道為什么錯(cuò)誤。

def my_abs(x):

if not isinstace(x, (int, float)):

raise TypeError(‘bad operand')

if x>= 0:

return x

if x < 0:

return -x

(isinstance(x, type)是判斷x是否為type的函數(shù))

很多函數(shù)都return一個(gè)值,那么可以return多個(gè)值么?可以,但是返回的本質(zhì)上是個(gè)tuple

比如剛剛學(xué)到的科學(xué)計(jì)算函數(shù)divmod(x, y), 返回的就是兩個(gè)值(商,余數(shù)),但是如果你去嘗試type(),就會(huì)看到這是一個(gè)tuple

type(divmod(5, 2)

Out: tuple

函數(shù)的參數(shù)

對(duì)于日常使用來說,因?yàn)閜ython大量的build-in functions和變態(tài)的import功能,我們非常少去自己寫一個(gè)函數(shù)。更多的是理解自己調(diào)用的函數(shù)該如何使用——核心就在于,函數(shù)的參數(shù)的了解和使用。日常使用的大量報(bào)錯(cuò)都是因?yàn)?對(duì)于某個(gè)函數(shù)是否能夠接受某種方式傳入的某個(gè)參數(shù)的不確定,導(dǎo)致大量debug時(shí)間(隨機(jī)嘗試不是個(gè)長期解決方案,雖然能夠不斷地返回error信息以供調(diào)試)

1. 位置參數(shù)

簡單理解,位置固定的參數(shù),如pow(x, y)計(jì)算x的y次方。直接寫pow(3, 2)不再需要規(guī)定哪個(gè)是x, 哪個(gè)是y

2. 默認(rèn)參數(shù): 大大減輕了函數(shù)調(diào)用的難度

比如range(5),實(shí)際上start位置的參數(shù)就被忽略了,只傳入了stop。但是仍然能運(yùn)行,因?yàn)閞ange()內(nèi)部規(guī)定了start默認(rèn)為0。

也可以不接受默認(rèn)設(shè)定,自己規(guī)定:range(2, 5)

但是在自己定義函數(shù)的時(shí)候,必選參數(shù)在前,默認(rèn)參數(shù)在后。且默認(rèn)參數(shù)指向不可變對(duì)象(不能指向個(gè)變量什么的!)

3. 可變參數(shù)

并不規(guī)定要傳入幾個(gè)參數(shù),多少個(gè)都行。define的時(shí)候加個(gè)星號(hào)即可

def calc(*numbers):

sum = 0

for n in numbers:

sum = sum + n * n

return sum

這樣numbers里邊有多少個(gè)都沒問題。

如果已經(jīng)有個(gè)numbers集合(list或者tuple)咋辦?

num = [1, 2, 3]

calc(*num)

這種寫法,就是把num這個(gè)list中所有元素都傳入calc()進(jìn)行計(jì)算。如果不加*會(huì)咋樣?

TypeError: can't multiply sequence by non-int of type 'list'

原理上,可變參數(shù)允許你傳入 0 個(gè)或任意個(gè)參數(shù),這些可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè) tuple。

4. 關(guān)鍵字參數(shù)

def person(name, age, **kw):

print('name:', name, 'age:', age, 'other:', kw)

除了規(guī)定的name和age, 還接受擴(kuò)展性的其他參數(shù)。這就被稱為關(guān)鍵字參數(shù)

比如用戶除了必填項(xiàng)之外,還愿意提供其他參數(shù),那么就可以通過關(guān)鍵字參數(shù)來擴(kuò)展。

5. 命名關(guān)鍵字參數(shù)(限制了可擴(kuò)展的關(guān)鍵字)

def person(nama, age, *, city, job)

這里的星號(hào)后邊的city和job就是命名關(guān)鍵字參數(shù),也就是限定了的關(guān)鍵字參數(shù)。(不加星號(hào),就變成了位置參數(shù))

語法風(fēng)格

**args: 可變參數(shù),接受的是一個(gè)tuple

**kw: 關(guān)鍵字參數(shù),kw接收的是一個(gè)dict

可變參數(shù)既可以直接傳入func(1, 2, 3), 又可以先組裝list或tuple,再通過**args傳入func(*(1, 2, 3))

關(guān)鍵字參數(shù)既可以直接傳入 func(a=1, b=2), 又可以先組裝dict, 再通過**kw傳入 func(**{'a': 1, 'b': 2})

切片

list切片 L[1:3]這種方式,包前不包后。也可以L[:3]或者L[2:]。L[:]就是區(qū)這個(gè)List本身

實(shí)際上,切片的規(guī)則是list[start:stop:step]

list的切片結(jié)果是List,tuple的切片結(jié)果是tuple。

string也是一種List

迭代:

通過for循環(huán)來遍歷list或是tuple或是其他可迭代對(duì)象,這邊遍歷我們稱為迭代iteration。

python中,迭代是通過for...in完成的。

像dict這種類型,默認(rèn)迭代的是key。想迭代value, 可以for value in d.values()。同時(shí)要迭代key和value, 可以for k, v in d.items()

只要是可迭代對(duì)象,就可迭代。判斷是否是可迭代對(duì)象,方法是

from collections import Iterable

isinstance('abc', Iterable) 前面我們學(xué)過了isinstance函數(shù)

列表生成式List comprehesions

顧名思義,就是為了生成List的(list幾乎是應(yīng)用最為廣泛的類型) [x * x for x in range(1, 11)]

要生成的元素放在前面,后邊跟for循環(huán)(其實(shí)就是for循環(huán)的一種簡寫)

還可以加上if(但是不接受else)

x * x for x in range(1, 11) if x % 2 ==0

m + n for m in 'ABC' for n in 'XYZ'

利用這個(gè)列表生成式,可以生成非常簡介的代碼,比如生成當(dāng)前目錄下所有的文件名稱

import os

[d for d in os.list('.')]

生成器generator

列表生成式雖然生成方便(一個(gè)規(guī)則+for循環(huán)[+if語句]),但是問題也很明顯。

你生成辣么大的列表,占著內(nèi)存,留著過年么?又不見得全都用得上!

這時(shí)候你就需要個(gè)generator, 也就是 邊生成,邊循環(huán),邊計(jì)算。

符號(hào)上跟列表生成式的區(qū)別只有一個(gè)

List = [x * x for x in range(10)]

Generator = (x * x for x in range(10))

對(duì),沒看錯(cuò),就是把中括號(hào)變成了小括號(hào),就從list變成了generator。(如果你去type()他們,會(huì)看到區(qū)別)。

調(diào)用列表當(dāng)然很簡單,怎么調(diào)用generator呢。怎么個(gè)生成法呢?

用next(generator)來調(diào)用,調(diào)用一次生成一次。也就是每次next(generator)結(jié)果都不一樣,next()到最后一步,拋出Stopiteration錯(cuò)誤。不過你也看出來了,也不能每次都next(),啥時(shí)候是個(gè)頭啊?(實(shí)際上幾乎用不上next())

所幸,一個(gè)generator仍然能被for循環(huán)調(diào)用。

for n in generator:
? ? print(n)

那么問題來了:挖掘機(jī)技術(shù)哪家強(qiáng)?如果列表生成式這種簡單的結(jié)構(gòu),描述不了一個(gè)generator的算法怎么辦?(當(dāng)然能看出來,列表生成式雖然入手容易,不過干不了太復(fù)雜的事情——你看它那個(gè)傻樣連else都不接受

好消息!好消息!用定義函數(shù)的方法就可以創(chuàng)建generator啦!不過要把return改成yield。(等用到再來填坑)

迭代器Iterator

前面說到,可直接作用于for循環(huán)的數(shù)據(jù)類型有

1. 集合數(shù)據(jù)類型:list, tuple, dict, set, str等

2. generator,包括生成器和帶yield的generator function

這些可以直接作用于for循環(huán)的對(duì)象,叫Iterable可迭代對(duì)象。判斷類型有兩個(gè)方法:type()和isinstance(obj, type)

切記:判斷Iterable之前,請先from collections import Iterable

可以用next()調(diào)用并不斷返回下一個(gè)值的對(duì)象成為迭代器Iterator。想把Iterable對(duì)象編程iterator,可以使用Iter()函數(shù)。

for循環(huán)本質(zhì)上就是不斷調(diào)用next()實(shí)現(xiàn)的。以下兩個(gè)是等價(jià)的:

for x in [1, 2, 3, 4, 5]:

? ? pass

it = iter([1, 2, 3, 4, 5])

while True:

? ? try:

? ? ? ? x = next(it)

? ? except StopIteration

? ? ? ? break


高階函數(shù)

1. 變量可以指向函數(shù),函數(shù)的參數(shù)能接受變量。

2. 所以,一個(gè)函數(shù)局可以接收另一個(gè)函數(shù)作為參數(shù)。這種函數(shù)就稱為高階函數(shù)。

def add(x, y, f):

? ?return f(x) + f(y)

就是傳入兩個(gè)值,絕對(duì)值后再相加。

map/reduce

map(function, iterable)得到一個(gè)Iterator。map就是把一個(gè)函數(shù),作用于一個(gè)iteratable。

(想要讀取結(jié)果,可以list(iterator))

list(map(str, [1, 2, 3])) # 把列表里的123全部字符串化。

reduce把一個(gè)函數(shù)作用在一個(gè)序列上,這個(gè)函數(shù)必須接受兩個(gè)參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算,其效果就是

from functools import reduce

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

filter函數(shù)用于過濾序列,和map一樣,filter也接受一個(gè)函數(shù)和序列,然后根據(jù)函數(shù)返回值是T/F來決定保留還是丟棄該元素。返回的也是惰性序列,需要list()。一樣,filter也是惰性計(jì)算,不調(diào)用不篩選。

sorted既是可以對(duì)list進(jìn)行排序的函數(shù),也是個(gè)高階函數(shù)。

sorted([36, 5, -12, 9, -21], key=abs)

sorted(['bob', 'about', 'Zoo'], key=str.lower, reverse=True)

高階函數(shù)抽象能力強(qiáng),代碼簡潔

注意,這些高階函數(shù)因?yàn)槭前岩粋€(gè)函數(shù)分配到iterable里邊的每一個(gè)元素里邊了,所以不用再去考慮怎么樣調(diào)用每一個(gè)元素了。比如

L= [('Bob',75),('Adam',92),('Bart',66),('Lisa',88)]

def by_name(t):

return t[0].lower()

L2 = sorted(L, key=by_name)

print(L2)

不用再想怎么去調(diào)用每一個(gè)元素了,比如L[0][1]這種。。。

返回函數(shù)(坑,小特性,待填充)

匿名函數(shù)

很多時(shí)候我們不需要顯式定義函數(shù),直接做一個(gè)匿名函數(shù)更方便,而且函數(shù)名還不會(huì)重復(fù)。

list(map(lambda x: x * x, [1, 2, 3, 4])

要比這么寫方便很多

def f(x):

? ? return x * x

關(guān)鍵字lambda表示匿名函數(shù),冒號(hào)前面x表示函數(shù)參數(shù)。但是只能有一個(gè)表達(dá)式,不用寫return,返回值就是該表達(dá)式的結(jié)果。

也可以把匿名函數(shù)作為返回值返回

def build(x, y):

? ? return lambda: x * x + y * y

python的一些單條表達(dá)式適合用lambda函數(shù),都是一些比較簡單的狀況。

裝飾器Decorator(沒搞懂)

函數(shù)支持通過function_name.__name__來調(diào)用函數(shù)名稱(后面會(huì)詳細(xì)解析)

裝飾器就是在函數(shù)動(dòng)態(tài)運(yùn)行期間,給函數(shù)增加了的功能(其實(shí)就是返回函數(shù))。

@log # 把log函數(shù)通過@方法,放到now()前面,作為裝飾器出現(xiàn)。

def now():

? ? print('2016-10-01')

在面向?qū)ο蟮脑O(shè)計(jì)模式中,decorator被成為裝飾模式。OOP的裝飾模式需要通過繼承和組合來實(shí)現(xiàn),而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。Python的decorator可以用函數(shù)實(shí)現(xiàn),也可以用類實(shí)現(xiàn)。(啥意思?)

偏函數(shù)

借助functools.partial(需要先import functools),可以創(chuàng)建一個(gè)部分參數(shù)被固定的常用函數(shù)。這就稱為偏函數(shù)。

比如int(obj, base=n)。如果進(jìn)制參數(shù)base的n常用(比如轉(zhuǎn)換成為16進(jìn)制),那么可以規(guī)定

int(obj, base=16)作為偏函數(shù)。使用方法如下

import functools

int2 = functools.partial(int, base=8)

但是,調(diào)用的時(shí)候如果主動(dòng)改變規(guī)定好的默認(rèn)參數(shù),比如int2(int, base=16),16進(jìn)制轉(zhuǎn)換仍然有效。

當(dāng)函數(shù)的參數(shù)個(gè)數(shù)太多需要簡化的時(shí)候,固定住某一些參數(shù),從而方便調(diào)用。

模塊

把函數(shù)分組,放到不同的.py文件里,每一個(gè).py文件就叫做模塊。

調(diào)用模塊的最大好處在于,不需要重復(fù)制作輪子,只要調(diào)用就好。

模塊會(huì)組成package(包),所以我們會(huì)說“調(diào)用第三方包/庫,說的就是這個(gè)意思。

包目錄下,必須有__init__.py文件,否則python就不識(shí)別這個(gè)包目錄,而是當(dāng)成普通目錄。

切記:不能與系統(tǒng)自帶模塊重名,比如sys。

使用模塊要先import sys。

模塊的編寫(略)

安裝模塊

安裝第三方模塊,是通過pip工具

$ pip install pandas

調(diào)用的時(shí)候, 只import就只會(huì)在1. 當(dāng)前目錄 2. 所有已經(jīng)安裝的內(nèi)置模塊 3.第三方模塊 進(jìn)行搜索,實(shí)際上遍歷了sys.path變量下的文件內(nèi)容

import sys

sys.path

如果要暫時(shí)添加,用append()

sys.path.append('the directory you want to add')?

第二種方法設(shè)置環(huán)境變量PYTHONPATH,該環(huán)境變量的內(nèi)容會(huì)被自動(dòng)添加到模塊搜索路徑

(待填坑)

面向?qū)ο缶幊蘋bject Orient Programming(OOP)

OOP把對(duì)象作為程序設(shè)計(jì)的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和(操作數(shù)據(jù)的)函數(shù)。把計(jì)算機(jī)程序程序視為一組對(duì)象的集合,而每個(gè)對(duì)象都可以接收其他對(duì)象發(fā)過來的消息,并處理這些消息。執(zhí)行程序就是在對(duì)象之間傳遞信息。

面向過程的程序設(shè)計(jì)把計(jì)算機(jī)程序視為一系列的命令集合,就是一組函數(shù)的順序執(zhí)行。具體,就是把函數(shù)切分成為子函數(shù)。

python中所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。自定義的對(duì)象數(shù)據(jù)類型就是面向?qū)ο笾械念?class)的概念。

比如class是student, 是泛指學(xué)生這個(gè)概念,instance則是一個(gè)個(gè)具體的student, 張三李四。

所以,面向?qū)ο蟮脑O(shè)計(jì)思想是抽象出class,根據(jù)class創(chuàng)建instance。

面向?qū)ο蟮某橄蟪啥加直群瘮?shù)要高,因?yàn)橐粋€(gè)class既包含數(shù)據(jù),又包含操作數(shù)據(jù)的方法。

面向?qū)ο笕筇攸c(diǎn):數(shù)據(jù)封裝、繼承和多態(tài)

是時(shí)候祭出這張圖了!當(dāng)當(dāng)當(dāng)當(dāng)!

類和實(shí)例

類是抽象的模板,比如student類。實(shí)例是根據(jù)類創(chuàng)建出來的一個(gè)個(gè)具體的對(duì)象,每個(gè)對(duì)象只是數(shù)據(jù)不一樣而已,方法是相同的。

定義一個(gè)class

class Student(object):

? ? pass

注意:類名通常是首字母大寫的單詞,接下來是(object),表示該類是從哪個(gè)類繼承下來的。如果沒有,就繼承自object類,這是所有類最終都會(huì)繼承的類。

定義好了Student類,就可以根據(jù)Student類創(chuàng)建出Student的實(shí)例,創(chuàng)建實(shí)例是

barry = Student()

barry

<__main__.Student at 0x103d40d68>

后邊的0x103d40d6是內(nèi)存地址,每個(gè)object地址都不一樣。

每個(gè)實(shí)例都可以自由綁定屬性,比如

barry.name = 'barry li'

這種方法對(duì)于實(shí)例雖然自由,但是沒有讓class起到模板的作用。我們要把class更加規(guī)范化,從而讓instance更加規(guī)范化,這個(gè)方法就是定義__init__

class Student(object):

? ? def __init__(self, name, score):

? ? ? ? self.name = name

? ? ? ? self.score = score

__init__方法的第一個(gè)參數(shù)永遠(yuǎn)是self,表示創(chuàng)建的實(shí)例本身。因此,在__init__方法內(nèi)部,就可以把各種屬性(name, score這種)綁定到self,因?yàn)閟elf就指向創(chuàng)建的實(shí)例本身。

這樣定義完畢了,就不能再barry = Studeng()了,比如傳入

barry = Student('barry li', '100') 來定義

barry.name輸出barry li

barry.score輸出100

def __init__的過程,跟普通函數(shù)的定義只有一點(diǎn)不同,就是第一個(gè)參數(shù)永遠(yuǎn)是實(shí)例變量self,并且在調(diào)用時(shí)不用傳遞該參數(shù)。所以,默認(rèn)參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù)仍然是存在的。

數(shù)據(jù)封裝

可以直接在class的內(nèi)部定義訪問數(shù)據(jù)的函數(shù),而不必在外部定義,這樣就把數(shù)據(jù)進(jìn)行了封裝。封裝數(shù)據(jù)的函數(shù)和class本身是關(guān)聯(lián)起來的,我們稱之為類的方法(所以會(huì)經(jīng)??吹健斑@個(gè)類沒有這個(gè)方法”)

class Student(object):

? ? def __init__(self, name, score):

? ? ? ? self.name = name

? ? ? ? ?self.score = score

? ? ?def print_score(self):

? ? ? ? ?print('%s: %s' % (self.name, self.score))

想要調(diào)用

barry.print_score() 得到barry li: 100

(注意, 這個(gè)時(shí)候print_score(barry)) 就不好用,想想為什么)

這樣,封裝的巨大意義就出現(xiàn)了:創(chuàng)建實(shí)例只需要給出score, name這些,而打印只需要調(diào)用print_score,這些都是在Student類內(nèi)部定義的,這些數(shù)據(jù)和邏輯封裝起來了,調(diào)用很容易,但卻不用知道內(nèi)部實(shí)現(xiàn)的細(xì)節(jié)。

(注意print_score仍然是函數(shù),只不過是class內(nèi)部的函數(shù),稱為Method(?), 所以return)

封裝的另一個(gè)巨大好處是,可以給一個(gè)定義好的class增加新的方法,比如get_grade

總結(jié)下,類是創(chuàng)建實(shí)例的模板,實(shí)例是一個(gè)個(gè)具體的對(duì)象,比如你要批量創(chuàng)造鍵盤,那么要先規(guī)定好,鍵盤(作為class)的特征是什么,(要傳入的參數(shù)是什么,比如尺寸,顏色,軸體,品牌等),然后創(chuàng)造出來的具體的鍵盤比如filco圣手二代(實(shí)例)。但其實(shí)跟創(chuàng)建的第二個(gè)鍵盤Cherry MX2.0沒啥關(guān)系,但是他們都是鍵盤呀(攤手)。

class Keyboard(object):

? ? def __init__(self, size, color, switch, barry)

? ? ? ? self.switch = switch

...

? ? def print_switch(self):

? ? ? ? ?print('%s' % self.switch)

如果我們要知道,某個(gè)鍵盤是什么軸體的,那么可以直接在class內(nèi)部定義好,怎樣從外部獲?。褐苯佣x訪問軸體get_switch訪問switch這個(gè)參數(shù)的內(nèi)容就好。

通過實(shí)例調(diào)用方法,我們就直接操作了對(duì)象內(nèi)部的數(shù)據(jù),但無需知道方法內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)。

同樣的,對(duì)一個(gè)實(shí)例的操作,并不影響其他實(shí)例。比如指著A說“你除了一個(gè)鼻子,兩個(gè)眼睛,是‘人’這個(gè)類之外,你還有有個(gè)特性:A.feature = '傻逼') 定義了A的feature是個(gè)傻逼,但是你如果嘗試調(diào)用B.feature,就會(huì)報(bào)錯(cuò):B連feature這個(gè)屬性都沒有,更別提B是不是傻逼了。

訪問限制

外部代碼還是可以自由修改一個(gè)實(shí)例的name, score屬性。如果要讓內(nèi)部屬性不被外部訪問,可以把屬性的名稱前加上兩個(gè)下劃線__,在python中,實(shí)例的變量如果以__開頭,就變成了一個(gè)私有變量(private),外部不能訪問,只能通過內(nèi)部定義的方法來訪問,這樣就保證了代碼的robust。

class定義好了規(guī)則,只能通過指定規(guī)則來訪問指定數(shù)據(jù),這種直接從底層拿的方法就被ban掉了。

一樣,修改也是可以開放的, 可以在內(nèi)部定義set_score這種。換句話說,修改這個(gè)權(quán)限也是在內(nèi)部通過方法實(shí)現(xiàn)的。


繼承和多態(tài)

在OOP中,當(dāng)我們定義一個(gè)class的時(shí)候,可以從某個(gè)現(xiàn)有的class繼承,新的class稱為subclass。而被繼承的class被稱為基類、父類和超類(base class, super class)。

還說機(jī)械鍵盤的例子,Cherry這個(gè)subclass只pass了下,就獲得了來自base class Keyboard的clean_keyboard方法。


當(dāng)然,subclass也不是什么都要跟著base class走。完全可以定義自己的方法。當(dāng)然,如果subclass創(chuàng)建了跟base class同名的方法,以subclass為主導(dǎo)(這和父母和孩子的關(guān)系很像:孩子的后天行為會(huì)覆蓋掉先天影響,但是孩子來源于父母)

這時(shí)候得到的輸出結(jié)果一定是your cherry is being cleaned

比如這個(gè)clean_keyboard方法,父類子類都有,以子類為主。代碼運(yùn)行,總是調(diào)用子類的。

這時(shí)候,就是繼承的另一個(gè)好處:多態(tài)。啥是多態(tài)?

我們定義了一個(gè)class,我們就定義了一個(gè)數(shù)據(jù)類型,跟內(nèi)置的tuple/list/dict/set/string/int沒啥兩樣。如果我們用常規(guī)測類型的方法isinstance(obj, type)來測,就會(huì)發(fā)現(xiàn)cherry(作為實(shí)例,不是class) 確實(shí)是屬于Cherry類型,同時(shí)也是Keyboard類型,當(dāng)然更是object類型(這是根父類)。

所以這三個(gè)結(jié)果都是True

print(isinstance(cherry,Cherry))

print(isinstance(cherry,Keyboard))

print(isinstance(cherry,object))

理解多態(tài)的好處:

實(shí)際上,任何依賴Animal作為參數(shù)的函數(shù)或者方法不加修改地正常運(yùn)行。

新增一個(gè)Animal的子類,不必對(duì)run_twice進(jìn)行修改。也就是說不管傳入的是貓是狗,我們只需要接收Animal類型就好。因?yàn)樨埞范际茿nimal類型,然后按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此傳入的任意數(shù)據(jù)類型,只要是Animal的類或子類,就會(huì)自動(dòng)調(diào)用實(shí)際類型的run()方法,這就是多態(tài)的意思:

對(duì)于一個(gè)變量,我們只需要知道它是Animal類型,無需確切知道它的子類型,就可以放心地調(diào)用run()方法,而具體調(diào)用的run()方法是作用在Animal、Dog還是cat對(duì)象上,由運(yùn)行時(shí)該對(duì)象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用只管調(diào)用,不管細(xì)節(jié)。當(dāng)我們新增一種Animal子類的時(shí)候,只要確保子類的run()編寫正確(前提是run()還是要寫到子類里邊的),不用管原來的代碼是如何調(diào)用的。這就是著名的”開閉“原則:

對(duì)擴(kuò)展開放:允許新增Animal子類;

對(duì)修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。

繼承還還可以一級(jí)一級(jí)地繼承狹隘,就好比從爺爺?shù)桨职?、再到兒子這樣的關(guān)系。而任何類,最終都可以追溯到根類object,這些繼承關(guān)系看上去就像一顆倒著的樹。

從這個(gè)意義上講,在任何一個(gè)更根的類里定義的方法,都可以被這個(gè)分支上的所有子類繼承。

看到這里,一定有人像我一樣暈了

dog.run()

run_twice(Dog())

為什么一個(gè)dog在前面

一個(gè)Dog()在里面?

經(jīng)過測試,這兩個(gè)寫法居然不是通用的,那是怎么回事?

dog.run() 是方法的使用范例

run_twice(Dog()) 是函數(shù)的使用范例

方法和函數(shù)的關(guān)系是,

函數(shù)(function)就相當(dāng)于一個(gè)數(shù)學(xué)公式,它理論上不與其它東西關(guān)系,它只需要相關(guān)的參數(shù)就可以

方法(method)是與某個(gè)對(duì)象相互關(guān)聯(lián)的,也就是說它的實(shí)現(xiàn)與某個(gè)對(duì)象有關(guān)聯(lián)關(guān)系.也就是說,在Class定義的函數(shù)就是方法.

簡而言之,方法和對(duì)象相關(guān),函數(shù)和對(duì)象無關(guān)。

靜態(tài)語言 vs 動(dòng)態(tài)語言

對(duì)于靜態(tài)語言(如Java),如果需要傳入Animal類型,則傳入的對(duì)象必須是Animal類型或者它的子類,否則將無法調(diào)用run()方法。

對(duì)于Python這樣的動(dòng)態(tài)語言來說,不一定需要傳入Animal類型。我們保證傳入的對(duì)象有一個(gè)run()方法就可以了。鴨子類型和多態(tài)詳解

http://blog.csdn.net/shangzhihaohao/article/details/7065675

以前寫過一篇文章講了一下python中的多態(tài),最后得出結(jié)論python不支持多態(tài),隨著對(duì)python理解得加深,對(duì)python中得多態(tài)又有了一些看法。

首先Python不支持多態(tài),也不用支持多態(tài),python是一種多態(tài)語言,崇尚鴨子類型。以下是維基百科中對(duì)鴨子類型得論述:

在程序設(shè)計(jì)中,鴨子類型(英語:duck typing)是動(dòng)態(tài)類型的一種風(fēng)格。在這種風(fēng)格中,一個(gè)對(duì)象有效的語義,不是由繼承自特定的類或?qū)崿F(xiàn)特定的接口,而是由當(dāng)前方法和屬性的集合決定。這個(gè)概念的名字來源于由James Whitcomb Riley提出的鴨子測試,“鴨子測試”可以這樣表述:

“當(dāng)看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子?!?/p>

在鴨子類型中,關(guān)注的不是對(duì)象的類型本身,而是它是如何使用的。例如,在不使用鴨子類型的語言中,我們可以編寫一個(gè)函數(shù),它接受一個(gè)類型為鴨的對(duì)象,并調(diào)用它的走和叫方法。在使用鴨子類型的語言中,這樣的一個(gè)函數(shù)可以接受一個(gè)任意類型的對(duì)象,并調(diào)用它的走和叫方法。如果這些需要被調(diào)用的方法不存在,那么將引發(fā)一個(gè)運(yùn)行時(shí)錯(cuò)誤。任何擁有這樣的正確的走和叫方法的對(duì)象都可被函數(shù)接受的這種行為引出了以上表述,這種決定類型的方式因此得名。

鴨子類型通常得益于不測試方法和函數(shù)中參數(shù)的類型,而是依賴文檔、清晰的代碼和測試來確保正確使用。從靜態(tài)類型語言轉(zhuǎn)向動(dòng)態(tài)類型語言的用戶通常試圖添加一些靜態(tài)的(在運(yùn)行之前的)類型檢查,從而影響了鴨子類型的益處和可伸縮性,并約束了語言的動(dòng)態(tài)特性。

毫無疑問在python中對(duì)象也是一塊內(nèi)存,內(nèi)存中除了包含屬性、方法之外,還包含了對(duì)象得類型,我們通過引用來訪問對(duì)象,比如a=A(),首先python創(chuàng)建一個(gè)對(duì)象A,然后聲明一個(gè)變量a,再將變量a與對(duì)象A聯(lián)系起來。變量a是沒有類型得,它的類型取決于其關(guān)聯(lián)的對(duì)象。a=A()時(shí),a是一個(gè)A類型的引用,我們可以說a是A類型的,如果再將a賦值3,a=3,此時(shí)a就是一個(gè)整型的引用,但python并不是弱類型語言,在python中'2'+3會(huì)報(bào)錯(cuò),而在PHP中'2'+3會(huì)得到5??梢赃@么理解,在python中變量類似與c中的指針,和c不同的是python中的變量可以指向任何類型,雖然這么說不太準(zhǔn)確,但是理解起來容易點(diǎn)。

因此,在python運(yùn)行過程中,參數(shù)被傳遞過來之前并不知道參數(shù)的類型,雖然python中的方法也是后期綁定,但是和Java中多態(tài)的后期綁定卻是不同的,java中的后期綁定至少知道對(duì)象的類型,而python中就不知道參數(shù)的類型。

還引用上次的例子:

[python]view plaincopy

classA:

defprt(self):

print"A"

classB(A):

defprt(self):

print"B"

classC(A):

defprt(self):

print"C"

classD(A):

pass

classE:

defprt(self):

print"E"

classF:

pass

deftest(arg):

arg.prt()

a?=?A()

b?=?B()

c?=?C()

d?=?D()

e?=?E()

f?=?F()

test(a)

test(b)

test(c)

test(d)

test(e)

test(f)

輸出結(jié)果:

[python]view plaincopy

A

B

C

A

E

Traceback?(most?recent?call?last):

File"/Users/shikefu678/Documents/Aptana?Studio?3?Workspace/demo/demo.py",?line33,in

test(a),test(b),test(c),test(d),test(e),test(f)

File"/Users/shikefu678/Documents/Aptana?Studio?3?Workspace/demo/demo.py",?line24,intest

arg.prt()

AttributeError:?F?instance?has?no?attribute'prt'

a,b,c,d都是A類型的變量,所以可以得到預(yù)期的效果(從java角度的預(yù)期),e并不是A類型的變量但是根據(jù)鴨子類型,走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子,e有prt方法,所以在test方法中e就是一個(gè)A類型的變量,f沒有prt方法,所以f不是A類型的變量。

以上是從java的角度分析的,其實(shí)上邊都是一派胡言,只是為了說明python中的運(yùn)行方法。沒有誰規(guī)定test方法是接收的參數(shù)是什么類型的。test方法只規(guī)定,接收一個(gè)參數(shù),調(diào)用這個(gè)參數(shù)的prt方法。在運(yùn)行的時(shí)候如果這個(gè)參數(shù)有prt方法,python就執(zhí)行,如果沒有,python就報(bào)錯(cuò),因?yàn)閍bcde都有prt方法,而f沒有,所以得到了上邊得結(jié)果,這就是python的運(yùn)行方式。

獲取對(duì)象信息

當(dāng)我們拿到一個(gè)對(duì)象的引用時(shí),如何知道這個(gè)對(duì)象是什么類型,有哪些方法可以調(diào)用?

type()

判斷對(duì)象類型,基本類型肯定都可以判斷,變量或者類也能判斷。

In[7]: type(Cat())

Out[7]: __main__.Cat

In[5]: type(abs)

Out[5]: builtin_function_or_method

可見,type()返回的是對(duì)應(yīng)的class類型。也可以通過if語句來生成布爾值

type('abc') == str

type('abc') == type(123)

也可以判斷一個(gè)對(duì)象是否為函數(shù),但是需要調(diào)用types(別忘了s?。。。?/p>

import types

def fn():

? ?pass

type(fn) == types.FunctionType

type(abs) == types.BuiltinFunctionType

type((x for x in range(10)) == types.GeneratorType

isinstance()

type()直接判斷沒問題,判斷繼承就很麻煩——我們想知道的是Dog是否屬于Animal,type()只能告訴我Dog()(實(shí)例)屬于Dog

一句話:isinstance可以幫你判斷一個(gè)對(duì)象是否是該類型本身,或是位于該類型的父繼承鏈上。

也可以判斷多個(gè),關(guān)系是any(或)

isinstance([1, 2, 3], (list, tupe))
>>>True

使用dir() (重頭戲來了)

如果要獲得一個(gè)對(duì)象的所有屬性和方法,可以使用dir()函數(shù),它返回一個(gè)包含字符串的list。(這也是針對(duì)”某對(duì)象沒有這個(gè)方法“報(bào)錯(cuò)的最有效方法——而不是盲目嘗試或是貿(mào)然百度,需要學(xué)會(huì)調(diào)試錯(cuò)誤)

比如dir('ABC') # 查看一個(gè)string所有的屬性和方法,以“__"開頭的暫且不提

'capitalize','casefold','center','count','encode','endswith','index','isdecimal','isdigit','isidentifier','islower',isnumeric','isprintable','isspace','lower','lstrip',maketrans','partition','replace','rindex','just','rpartition','rsplit','rstrip','splitlines', ?(復(fù)制的不全)

要清楚一件事情,len('ABC') 也是通過'ABC'.__len__()實(shí)現(xiàn)的

(想想為啥一個(gè)寫'ABC'.len()不行。因?yàn)橐粋€(gè)字符串并沒有內(nèi)部的方法叫l(wèi)en(),不信可以自己去看。只有內(nèi)部確有這個(gè)方法可以用object.method()

剩下的都是普通屬性方法,比如lower()返回小寫的字符串:'ABC'.lower()

?進(jìn)階:

可以使用hasattr(object, name) 判斷object是否有這個(gè)屬性

可以用setattr(object, name, value) 給object加上name這個(gè)屬性,value是xxx

也可以用getattr(object, name)來獲取name的value 等價(jià)于obj.name

報(bào)錯(cuò)提醒:如果試圖獲取不存在的屬性,會(huì)拋出AttributeError(最常見的錯(cuò)誤之一)

可以通過限制getattr(obj, name, 404) 這種方法來限定錯(cuò)誤返回——即不返回AttriuteError,而返回指定的value, 比如404

所以,通過內(nèi)置的type(), isintance(),dir(),我們可以對(duì)任意一個(gè)python對(duì)象進(jìn)行解析,拿到其內(nèi)部的數(shù)據(jù)。只有不知道不確定對(duì)象內(nèi)部信息的時(shí)候,我們才會(huì)嘗試去獲取對(duì)象信息。如果你知道可以

sum = obj.x + obj.y沒問題,就不要sum = getattr(obj, 'x') + getattr(obj, 'y')

但是話說回來,根據(jù)鴨子類型原理,只要有x方法,就可以用調(diào)用。有x方法的不一定是同一類對(duì)象——但是鴨子根本不在乎。

實(shí)例屬性和類屬性

就一點(diǎn):在寫程序的時(shí)候,千萬不要把實(shí)例屬性和類屬性使用相同的名字,因?yàn)橄嗤Q的實(shí)例屬性將屏蔽掉類屬性。(如果刪除類型屬性,但是當(dāng)你刪除實(shí)例屬性后,再使用相同的名稱,訪問到的將是類屬性)


我覺得好像從現(xiàn)在開始,知識(shí)的抽象程度就直接升了一個(gè)檔次。每一塊花的時(shí)間都要比前面的幾塊加起來還要多——但這也正是意義所在,簡單的東西稍微下功夫就學(xué)得會(huì),但終究價(jià)值不大。

面向?qū)ο蟾呒?jí)編程

數(shù)據(jù)封裝、繼承和多態(tài)只是面向?qū)ο蟪绦蛟O(shè)計(jì)中的基礎(chǔ)三概念。高級(jí)功能還有很多。

使用__slots__

先說一個(gè)小技巧,可以直接給一個(gè)實(shí)例綁定一個(gè)方法,通過

from types import MethodType

instance.function = MethodType(function, instance)

但是一般我們不給instance綁定方法,我們都直接給class綁。有兩個(gè)方法,要么直接在class內(nèi)綁定,要么通過instance.function = MethodType(function, instance)來綁定方法

內(nèi)部綁定的方法是常規(guī)方法,基本上所有語言都能實(shí)現(xiàn);

外部綁定因?yàn)槭呛蠼壎ㄉ先サ?,或者說隨時(shí)想綁就綁的,稱之為動(dòng)態(tài)綁定,只有動(dòng)態(tài)語言才能實(shí)現(xiàn)。

靜態(tài)綁定:內(nèi)部綁定
動(dòng)態(tài)綁定:MethodType綁定

針對(duì)instance和class, 如果用這種方法來綁定屬性的話,基本上想綁啥就綁啥。其實(shí)是很多時(shí)候需要限制的,這時(shí)候就需要在class內(nèi)部定義的__slots__。

class Student(object):

? ? __slot__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱

這時(shí)候嘗試去綁定其他屬性就會(huì)返回錯(cuò)誤

但是!這僅僅限于這個(gè)class, 繼承class的其他subclass并不受__slot__限制,除非subclass自己也定義上__slot__。

使用@property(和裝飾器相連,實(shí)在是沒看懂)

多重繼承

只有通過多重繼承,一個(gè)子類就可以同時(shí)獲得多個(gè)父類的所有功能。

這樣,就避免了繼承的過分的復(fù)雜性。

在設(shè)計(jì)class的繼承關(guān)系時(shí),通常都是“一脈相承”。如果需要額外混入其他功能,通過多重繼承就可以實(shí)現(xiàn)。就如同Dog繼承Mammal,同時(shí)也繼承Runnable。這種設(shè)計(jì)通常稱之為MixIn。MixIn的目的就是給一個(gè)類增加多個(gè)功能。這樣我們會(huì)優(yōu)先考慮通過多重繼承來組合多個(gè)MixIn功能,而不是設(shè)計(jì)多層次的復(fù)雜的繼承關(guān)系。(JAVA這種只允許單一繼承的語言不能使用MixIn的設(shè)計(jì))

定制類、枚舉類、元類(略,等待填坑)

6天時(shí)間復(fù)習(xí)到這。元?jiǎng)恿ο耐戤?,任?wù)掛起,切換至pandas。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • http://python.jobbole.com/85231/ 關(guān)于專業(yè)技能寫完項(xiàng)目接著寫寫一名3年工作經(jīng)驗(yàn)的J...
    燕京博士閱讀 7,786評(píng)論 1 118
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 4,021評(píng)論 0 7
  • 前言 人生苦多,快來 Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,669評(píng)論 9 118
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評(píng)論 19 139
  • 有一天大啊躍問佛:“佛啊佛,世人皆跪你、拜你、有求于你,你累嗎?”佛說:“我本西山之竹,東山之泥。被人們挖了伐了塑...
    大啊躍閱讀 215評(píng)論 0 0

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