課程目錄

毫無疑問,Python如今是野蠻增長,增速非常快。隨著人工智能的崛起,Python會更加的火爆。比爾蓋茨說過,之后的幾十年,人工智能會強大到足以引起人們的重視。Python將有可能沖擊每月編程語言排行榜第一的位置。

Python可以說是一門比較功利的語言,它不復雜,讀和寫都非常易于使用,所以才有了“人生苦短,我用Python”這樣的調侃。

這套教程非常全面而且詳細,從Python入門到Python進階、Django、Flask等Web框架以及爬蟲、數據庫、算法與數據結構等方面均有涉及,幾乎覆蓋了Python 基礎及進階的方方面面。

0引言

微信公眾號終于可以插代碼了,Python 可以走一波了。首先我承認不是硬核搞 IT 的,太高級的玩法也玩不來,講講下面基本的還可以,之后帶點機器學習、金融工程和量化投資的實例也是可以。

Python 入門篇 (上)

Python 入門篇 (下)

數組計算之 NumPy

科學計算之 SciPy

數據結構之 Pandas

基本可視化之 Matplotlib

統(tǒng)計可視化之 Seaborn

交互可視化之 Bokeh

炫酷可視化之 PyEcharts

機器學習之 Sklearn

深度學習之 TensorFlow

深度學習之 Keras

深度學習之 PyTorch

深度學習之 MXnet

整個系列力求精簡和實用 (可能不會完整,但看完此貼舉一反三也不要完整,追求完整的建議去看書),到了「難點處」我一定會畫圖幫助讀者理解。Python 系列的入門篇的目錄如下,本帖是上篇,只涵蓋前三個節(jié),下篇接著后兩節(jié)。

對于任何一種計算機語言,我覺得最重要的就是「數據類型」「條件語句 & 迭代循環(huán)」和「函數」,這三方面一定要打牢基礎。此外 Python 非常簡潔,一行代碼 (one-liner) 就能做很多事情,很多時候都用了各種「解析式」,比如列表、字典和集合解析式。

在學習本貼前感受一下這個問題:如何把以下這個不規(guī)則的列表 a 里的所有元素一個個寫好,專業(yè)術語叫打平 (flatten)?

a = [1, 2, [3, 4], [[5, 6], [7, 8]]]

魔法來了 (這一行代碼有些長,用手機的建議橫屏看)

fn = lambda x: [y for l in x for y in fn(l)] if type(x) is list else [x]

fn(a) 

[1, 2, 3, 4, 5, 6, 7, 8]

這一行代碼,用到了迭代、匿名函數、遞推函數、解析式這些技巧。初學者一看只會說“好酷啊,但看不懂”,看完本帖和下帖后,我保證你會說“我也會這樣用了,真酷!”

1基本數據類型

Python 里面有自己的內置數據類型 (build-in data type),本節(jié)介紹基本的三種,分別是整型 (int),浮點型 (float),和布爾型 (bool)。

1.1

整型

整數 (integer) 是最簡單的數據類型,和下面浮點數的區(qū)別就是前者小數點后沒有值,后者小數點后有值。例子如下:

a = 1031

print( a, type(a) )

1031

通過 print 的可看出 a 的值,以及類 (class) 是 int。Python 里面萬物皆對象(object),「整數」也不例外,只要是對象,就有相應的屬性 (attributes) 和方法 (methods)。

知識點

通過 dir( X ) 和help( X ) 可看出 X 對應的對象里可用的屬性和方法。

X 是 int,那么就是 int 的屬性和方法

X 是 float,那么就是 float 的屬性和方法

等等

dir(int)

['__abs__',

'__add__',

...

'__xor__',

'bit_length',

'conjugate',

...

'real',

'to_bytes']

紅色的是 int 對象的可用方法,藍色的是 int 對象的可用屬性。對他們你有個大概印象就可以了,具體怎么用,需要哪些參數 (argument),你還需要查文檔。看個bit_length的例子

a.bit_length()

11

該函數是找到一個整數的二進制表示,再返回其長度。在本例中 a = 1031, 其二進制表示為 ‘10000000111’ ,長度為 11。

1.2

浮點型

簡單來說,浮點型 (float) 數就是實數, 例子如下:

print( 1, type(1) )

print( 1., type(1.) )

1

1.0

加一個小數點 . 就可以創(chuàng)建 float,不能再簡單。有時候我們想保留浮點型的小數點后 n 位。可以用 decimal 包里的 Decimal 對象和 getcontext() 方法來實現。

import decimal

from decimal import Decimal

Python 里面有很多用途廣泛的包 (package),用什么你就引進 (import) 什么。包也是對象,也可以用上面提到的dir(decimal) 來看其屬性和方法。比如 getcontext() 顯示了 Decimal 對象的默認精度值是 28 位 (prec=28),展示如下:

decimal.getcontext()

Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999,

Emax=999999, capitals=1, clamp=0, flags=[],

traps=[InvalidOperation, DivisionByZero, Overflow])

讓我們看看 1/3 的保留 28 位長什么樣?

d = Decimal(1) / Decimal(3)

d

Decimal('0.3333333333333333333333333333')

那保留 4 位呢?用 getcontext().prec 來調整精度哦。

decimal.getcontext().prec = 4 

e = Decimal(1) / Decimal(3)

e

Decimal('0.3333')

高精度的 float 加上低精度的 float,保持了高精度,沒毛病。

d + e

Decimal('0.6666333333333333333333333333')

1.3

布爾型

布爾 (boolean) 型變量只能取兩個值,True 和 False。當把布爾變量用在數字運算中,用 1 和 0 代表 True 和 False。

T = True

F = False

print( T + 2 )

print( F - 8 )

3

-8

除了直接給變量賦值 True 和 False,還可以用 bool(X) 來創(chuàng)建變量,其中 X 可以是

基本類型:整型、浮點型、布爾型

容器類型:字符、元組、列表、字典和集合

基本類型

print( type(0), bool(0), bool(1) )

print( type(10.31), bool(0.00), bool(10.31) )

print( type(True), bool(False), bool(True) )

False True

False True

False True

bool 作用在基本類型變量的總結:X 只要不是整型 0、浮點型 0.0,bool(X) 就是 True,其余就是 False。

容器類型

print( type(''), bool( '' ), bool( 'python' ) )

print( type(()), bool( () ), bool( (10,) ) )

print( type([]), bool( [] ), bool( [1,2] ) )

print( type({}), bool( {} ), bool( {'a':1, 'b':2} ) )

print( type(set()), bool( set() ), bool( {1,2} ) )

False True

False True

False True

False True

False True

bool 作用在容器類型變量的總結:X 只要不是空的變量,bool(X) 就是 True,其余就是 False。

知識點

確定bool(X) 的值是 True 還是 False,就看 X 是不是空,空的話就是 False,不空的話就是 True。

對于數值變量,0, 0.0 都可認為是空的。

對于容器變量,里面沒元素就是空的。

此外兩個布爾變量 P 和 Q 的邏輯運算的結果總結如下表:

2容器數據類型

上節(jié)介紹的整型、浮點型和布爾型都可以看成是單獨數據,而這些數據都可以放在一個容器里得到一個「容器類型」的數據,比如:

字符 (str) 是一容器的字節(jié) char,注意 Python 里面沒有 char 類型的數據,可以把單字符的 str 當做 char。

元組 (tuple)、列表 (list)、字典 (dict) 和集合 (set) 是一容器的任何類型變量。

2.1

字符

字符用于處理文本 (text) 數據,用「單引號 ’」和「雙引號 “」來定義都可以。

創(chuàng)建字符

t1 = 'i love Python!'

print( t1, type(t1) )

t2 = "I love Python!"

print( t2, type(t2) )

i love Python!

I love Python!

字符中常見的內置方法 (可以用 dir(str) 來查) 有

capitalize():大寫句首的字母

split():把句子分成單詞

find(x):找到給定詞 x 在句中的索引,找不到返回 -1

replace(x, y):把句中 x 替代成 y

strip(x):刪除句首或句末含 x 的部分

t1.capitalize()

'I love python!'

t2.split()

['I', 'love', 'Python!']

print( t1.find('love') )

print( t1.find('like') )

2

-1

t2.replace( 'love Python', 'hate R' )

'I hate R!'

print( 'http://www.python.org'.strip('htp:/') )

print( 'http://www.python.org'.strip('.org') )

www.python.org

http://www.python

索引和切片

s = 'Python'

print( s )

print( s[2:4] )

print( s[-5:-2] )

print( s[2] )

print( s[-1] )

Python

th

yth

t

n

知識點

Python 里面索引有三個特點 (經常讓人困惑):

從 0 開始 (和 C 一樣),不像 Matlab 從 1 開始。

切片通常寫成 start:end 這種形式,包括「start 索引」對應的元素,不包括「end索引」對應的元素。因此 s[2:4] 只獲取字符串第 3 個到第 4 個元素。

索引值可正可負,正索引從 0 開始,從左往右;負索引從 -1 開始,從右往左。使用負數索引時,會從最后一個元素開始計數。最后一個元素的位置編號是 -1。

這些特點引起讀者對切片得到什么樣的元素感到困惑。有個小竅門可以幫助大家快速鎖定切片的元素,如下圖。

與其把注意力放在元素對應的索引,不如想象將元素分開的隔欄,顯然 6 個元素需要 7 個隔欄,隔欄索引也是從 0 開始,這樣再看到 start:end 就認為是隔欄索引,那么獲取的元素就是「隔欄 start」和「隔欄 end」之間包含的元素。如上圖:

string[2:4] 就是「隔欄 2」和「隔欄 4」之間包含的元素,即 th

string[-5:-2] 就是「隔欄 -5」和「隔欄 -2」之間包含的元素,即 yth

正則表達式

正則表達式 (regular expression) 主要用于識別字符串中符合某種模式的部分,什么叫模式呢?用下面一個具體例子來講解。

input = """

'06/18/2019 13:00:00', 100, '1st';

'06/18/2019 13:30:00', 110, '2nd';

'06/18/2019 14:00:00', 120, '3rd'

"""

input

"\n'06/18/2019 13:00:00', 100, '1st';

 \n'06/18/2019 13:30:00', 110, '2nd';

 \n'06/18/2019 14:00:00', 120, '3rd'\n"

假如你想把上面字符串中的「時間」的模式來抽象的表示出來,對照著具體表達式 '06/18/2019 13:00:00' 來看,我們發(fā)現該字符串有以下規(guī)則:

開頭和結束都有個單引號 '

里面有多個 0-9 數字

里面有多個正斜線 / 和分號 : 

還有一個空格

因此我們用下面這樣的模式

pattern = re.compile("'[0-9/:\s]+'")

再看這個抽象模式表達式 '[0-9/:\s]+',里面符號的意思如下:

最外面的兩個單引號 ' 代表該模式以它們開始和結束

中括號 [] 用來概括該模式涵蓋的所有類型的字節(jié)

0-9 代表數字類的字節(jié)

/ 代表正斜線

: 代表分號

\s 代表空格

[] 外面的加號 + 代表 [] 里面的字節(jié)出現至少 1 次

有了模式 pattern,我們來看看是否能把字符串中所有符合 pattern 的日期表達式都找出來。

pattern.findall(input)

["'06/18/2019 13:00:00'",

 "'06/18/2019 13:30:00'",

 "'06/18/2019 14:00:00'"]

結果是對的,之后你想怎么盤它就是你自己的事了,比如把 / 換成 -,比如用 datetime 里面的 striptime() 把日期里年、月、日、小時、分鐘和秒都獲取出來。

2.2

元組

創(chuàng)建元組

「元組」定義語法為 

(元素1, 元素2, ..., 元素n)

關鍵點是「小括號 ()」和「逗號 ,」

小括號把所有元素綁在一起

逗號將每個元素一一分開

創(chuàng)建元組的例子如下:

t1 = (1, 10.31, 'python')

t2 = 1, 10.31, 'python'

print( t1, type(t1) )

print( t2, type(t2) )

(1, 10.31, 'python')

(1, 10.31, 'python')

知識點

創(chuàng)建元組可以用小括號 (),也可以什么都不用,為了可讀性,建議還是用 ()。此外對于含單個元素的元組,務必記住要多加一個逗號,舉例如下:

print( type( ('OK') ) )  # 沒有逗號 , 

print( type( ('OK',) ) ) # 有逗號 ,

看看,沒加逗號來創(chuàng)建含單元素的元組,Python 認為它是字符。

當然也可以創(chuàng)建二維元組:

nested = (1, 10.31, 'python'), ('data', 11)

nested

((1, 10.31, 'python'), ('data', 11))

索引和切片

元組中可以用整數來對它進行索引 (indexing) 和切片 (slicing),不嚴謹的講,前者是獲取單個元素,后者是獲取一組元素。接著上面二維元組的例子,先看看索引的代碼:

nested[0]

print( nested[0][0], nested[0][1], nested[0][2] )

(1, 10.31, 'python')

1 10.31 python

再看看切片的代碼:

nested[0][0:2] 

(1, 10.31)

不可更改

元組有不可更改 (immutable) 的性質,因此不能直接給元組的元素賦值,例子如下 (注意「元組不支持元素賦值」的報錯提示)。

t = ('OK', [1, 2], True)

t[2] = False

TypeError: 'tuple' object does not support item assignment

但是只要元組中的元素可更改 (mutable),那么我們可以直接更改其元素,注意這跟賦值其元素不同。如下例 t[1] 是列表,其內容可以更改,因此用 append 在列表后加一個值沒問題。

t[1].append(3)

('OK', [1, 2, 3], True)

內置方法

元組大小和內容都不可更改,因此只有 count 和 index 兩種方法。

t = (1, 10.31, 'python')

print( t.count('python') )

print( t.index(10.31) )

1

1

這兩個方法返回值都是 1,但意思完全不同

count('python') 是記錄在元組 t 中該元素出現幾次,顯然是 1 次

index(10.31) 是找到該元素在元組 t 的索引,顯然是 1

元組拼接

元組拼接 (concatenate) 有兩種方式,用「加號 +」和「乘號 *」,前者首尾拼接,后者復制拼接。

(1, 10.31, 'python') + ('data', 11) + ('OK',)

(1, 10.31, 'python') * 2

(1, 10.31, 'python', 'data', 11, 'OK')

(1, 10.31, 'python', 1, 10.31, 'python')

解壓元組

解壓 (unpack) 一維元組 (有幾個元素左邊括號定義幾個變量)

t = (1, 10.31, 'python')

(a, b, c) = t

print( a, b, c )

1 10.31 python

解壓二維元組 (按照元組里的元組結構來定義變量)

t = (1, 10.31, ('OK','python'))

(a, b, (c,d)) = t

print( a, b, c, d )

1 10.31 OK python

如果你只想要元組其中幾個元素,用通配符「*」,英文叫 wildcard,在計算機語言中代表一個或多個元素。下例就是把多個元素丟給了 rest 變量。

t = 1, 2, 3, 4, 5

a, b, *rest, c = t

print( a, b, c )

print( rest )

1 2 5

[3, 4]

如果你根本不在乎 rest 變量,那么就用通配符「*」加上下劃線「_」,劉例子如下:

a, b, *_ = t

print( a, b )

1 2

優(yōu)點缺點

優(yōu)點:占內存小,安全,創(chuàng)建遍歷速度比列表快,可一賦多值。

缺點:不能添加和更改元素。

等等等,這里有點矛盾,元組的不可更改性即使優(yōu)點 (安全) 有時缺點?確實是這樣的,安全就沒那么靈活,靈活就沒那么安全。看看大佬廖雪峰怎么評價「不可更改性」吧

immutable 的好處實在是太多了:性能優(yōu)化,多線程安全,不需要鎖,不擔心被惡意修改或者不小心修改。

后面那些安全性的東西我也不大懂,性能優(yōu)化這個我可以來測試一下列表和元組。列表雖然沒介紹,但是非常簡單,把元組的「小括號 ()」該成「中括號 []」就是列表了。我們從創(chuàng)建、遍歷和占空間三方面比較。

創(chuàng)建

%timeit [1, 2, 3, 4, 5]

%timeit (1, 2, 3, 4, 5)

62 ns ± 13.2 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

12.9 ns ± 1.94 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

創(chuàng)建速度,元組 (12.9ns) 碾壓列表 (62ns)。

遍歷

lst = [i for i in range(65535)]

tup = tuple(i for i in range(65535))

%timeit for each in lst: pass

%timeit for each in tup: pass

507 μs ± 61.1 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

498 μs ± 18.7 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

遍歷速度兩者相當,元組 (498 μs) 險勝列表 (507 μs)。

占空間

from sys import getsizeof

print( getsizeof(lst) )

print( getsizeof(tup) )

578936

524328

列表比元組稍微廢點內存空間。

2.3

列表

創(chuàng)建列表

「列表」定義語法為 

[元素1, 元素2, ..., 元素n]

關鍵點是「中括號 []」和「逗號 ,」

中括號把所有元素綁在一起

逗號將每個元素一一分開

創(chuàng)建列表的例子如下:

l = [1, 10.31,'python']

print(l, type(l))

[1, 10.31, 'python']

內置方法

不像元組,列表內容可更改 (mutable),因此附加 (append, extend)、插入 (insert)、刪除 (remove, pop) 這些操作都可以用在它身上。

附加

l.append([4, 3])

print( l )

l.extend([1.5, 2.0, 'OK'])

print( l )

[1, 10.31, 'python', [4, 3]]

[1, 10.31, 'python', [4, 3], 1.5, 2.0, 'OK']

嚴格來說 append 是追加,把一個東西整體添加在列表后,而 extend 是擴展,把一個東西里的所有元素添加在列表后。對著上面結果感受一下區(qū)別。

插入

l.insert(1, 'abc') # insert object before the index position

l

[1, 'abc', 10.31, 'python', [4, 3], 1.5, 2.0, 'OK']

insert(i, x) 在編號 i 位置前插入 x。對著上面結果感受一下。

刪除

l.remove('python') # remove first occurrence of object

l

[1, 'abc', 10.31, [4, 3], 1.5, 2.0, 'OK']

p = l.pop(3) # removes and returns object at index.  Only only pop 1 index position at any time.

print( p )

print( l ) 

[4, 3]

[1, 'abc', 10.31, 1.5, 2.0, 'OK']

remove 和 pop 都可以刪除元素

前者是指定具體要刪除的元素,比如 'python'

后者是指定一個編號位置,比如 3,刪除 l[3] 并返回出來

對著上面結果感受一下,具體用哪個看你需求。

切片索引

索引 (indexing) 和切片 (slicing) 語法在元組那節(jié)都講了,而且怎么判斷切片出來的元素在字符那節(jié)也講了,規(guī)則如下圖:

對照上圖看下面兩個例子 (順著數和倒著數編號):

l = [7, 2, 9, 10, 1, 3, 7, 2, 0, 1]

l[1:5]

[2, 9, 10, 1]

l[-4:]

[7, 2, 0, 1]

列表可更改,因此可以用切片來賦值。

l[2:4] = [999, 1000]

l

[7, 2, 999, 1000, 1, 3, 7, 2, 0, 1]

切片的通用寫法是

start : stop : step

這三個在特定情況下都可以省去,我們來看看四種情況:

情況 1 - start : 

print( l )

print( l[3:] )

print( l[-4:] )

[7, 2, 999, 1000, 1, 3, 7, 2, 0, 1]

[1000, 1, 3, 7, 2, 0, 1]

[7, 2, 0, 1]

以 step 為 1 (默認) 從編號 start 往列表尾部切片。

郵箱
huangbenjincv@163.com

邻水| 达州市| 长沙县| 德庆县| 九龙城区| 定襄县| 合水县| 九龙县| 辽宁省| 揭阳市| 淄博市| 镇安县| 无锡市| 化隆| 阜宁县| 玉溪市| 葵青区| 阿瓦提县| 策勒县| 册亨县| 华亭县| 游戏| 迁西县| 谢通门县| 喀喇沁旗| 舞钢市| 蓬溪县| 长汀县| 安康市| 安丘市| 维西| 搜索| 信阳市| 南安市| 仁布县| 嘉鱼县| 赤峰市| 琼结县| 永新县| 沙坪坝区| 梁河县|