顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

2017-06-03

Java 腦袋學 Python Regular Expression

Python Regular Expression 的套件為 re。

compile(), search() & findall()

#!python3
import re
regex = re.compile(r'\d{4}-?\d{6}') # r 表示使用 Raw string,即不 escape 反斜線 

s = '手機號碼有兩種,第一種是 0912-345678,第二種是 0912345678。'

# search 只會找到第一個符合的
mo = regex.search(s)
if mo != None:
    print(mo.group())
# 0912-345678

# findall 會找到全部符合的    
mo = regex.findall(s)
for mo in mobile_regex.findall(s):
    print(mo)
# 0912-345678
# 0912345678
Raw string 請參考 Java 腦袋學 Python 字串,如果不用 Raw string,那所有反斜線都要改用兩個反斜線,這樣變得很麻煩而且讓原本就難以閱讀的 RE 語法變得更加外星語。

2017-06-02

Python 執行檔

指定 Python 版本

由於可以同時安裝多個版本的 Python,因此 Python 須指名使用的 Python 版本。

在 Windows 上,每個 Python 檔案都要加上以下的檔頭,表示使用 Python 3。
#!python3
而在 Linux 上,則是加上以下的檔頭。
#!/usr/lib/python3
這是從命令提示字元下執行 Python 檔案才需要指定版本的檔頭,如果是從 IDLE 或者直接執行 python.exe,就不需要指名版本,因為已經在特定版本的 Python 環境裡了。

hello.py
#!python3
print('Hello Python!')
之前都是用 python.exe 執行 py 檔,加上檔頭後可以改用 py.exe 執行 py 檔,py.exe 的特色在於會讀取 #! 並使用對應的 Python 版本來執行。

2017-05-31

Java 腦袋學 Python OOP

Python OOP 基本概念與 java 類似,但不需要預先定義 API。
class Point:
    '''This is a doc string'''

# 不需要 new 關鍵字
p = Point()
print(p) # <__main__.Point object at 0x01C5BD70>
print(p.__doc__) # This is a doc string

# 動態建立欄位
p.x = 3
p.y = 4

print('(%d, %d)' % (p.x, p.y)) # (3, 4)
import math
print(math.sqrt(p.x**2 + p.y**2)) # 5.0

__init__() 與 __str__()

當然也可以預先定義屬性(API),這裡的__init__() 就是 Java 的 constructor,並定義 __str__() 回傳的字串,也就是 Java 裡的 toString()。
class Point:
    '''This is a doc string'''
    def __init__(self, x=0, y=0): # 可以給預設值,也可以不要
        self.x = x
        self.y = y
    def __str__(self):
        return 'Point (%d, %d)' % (self.x, self.y)

p = Point() # 使用預設值
print(p) # Point (0, 0)
p.x = 3
p.y = 4
print(p) # Point (3, 4)

print(Point(1, 2)) # Point (1, 2) 使用自訂值

物件特徵

和 Java 一樣,Python 物也是 pass by reference 與 mutable。

2017-05-27

Python Module 模組

任何 Python 檔案都可以作為 module 來 import。

first.py
def a():
    print('This is a from first')
直接 import 後就可以使用。
import first
first.a() # This is a from first
但是一個完整的 module 是需要附上測試程式的,可是測試程式只會在「直接」執行時使用,如果是 import,那就不要執行測試程式。

可以使用全域變數 __name__ 來判斷,到底是直接執行或者是 import。

second.py
def a():
    print('__name__ of a is ' + __name__)

if __name__ == '__main__': # 直接執行時,__name__ 是 __main__
    print('start test...')
    a()
直接執行 second.py。
start test...
__name__ of a is __main__
當作 module 來 import,__name__ 變成是 module 名稱。
import second
second.a() # __name__ of a is second
重複 import 相同的 module,Python 並不會做任何事情,也就是不會重複 impot,即使 module 已經經過修改,但可以用 reload() 來強迫重新 import,但有點棘手,倒不如重新啟動直譯器。
---
---
---

2017-05-26

Python 呼叫外部程式

一分鐘結束。
import os

# 一次讀取所有結果
p = os.popen('dir')
print(p.read()) # 回傳全部
print(p.close()); # 回傳 None 表示正常結束

# 逐行讀取
p = os.popen('dir')
line = p.readline()
while line:
    print(line, end = '')
    line = p.readline()
print(p.close()); # 回傳 None 表示正常結束
---
---
---

Python 套件 - 簡易資料庫 dbm 與醃漬工具 pickle

dbm

dbm 和 dict 很像,都是用 key-value pair。
import dbm

# c 表示有則用,沒有則新增
# 在目前工作目錄產生 foods.bak、foods.dat 與 foods.dir 三個檔案
db = dbm.open('foods', 'c')

# 新增一筆資料
db['apple'] = '蘋果' # insert

# value 為 bytes 物件,要 decode 成字串
print(db['apple']) # b'\xe8\x98\x8b\xe6\x9e\x9c',bytes 物件
print(db['apple'].decode('utf-8')) # 蘋果

# 用已存在的 key 表示更新
db['apple'] = '小蘋果' # update

# 用完要關
db.close() 
dbm 的 key 與 value 都必須是字串或是 bytes 物件。

Java 腦袋學 Python File

一分鐘入門。
fout = open('d:/a.txt', 'w') # w 表示新建或覆蓋
print(fout.write('Hello Python' + '\n')) # 13,write() 回傳寫入字元數
print(fout.write('Python 你好' + '\n')) # 10,必須手動加上換行
fout.close() # 否則直到程式結束才會關閉

fout = open('d:/a.txt', 'a') # a 表示 append
print(fout.write('Python 吃飽沒' + '\n')) # 11
fout.close()

fin = open('d:/a.txt')
for line in fin:
    print(line, end='') # 因為內文已有換行,print 不需要再換行
# Hello Python
# Python 你好
# Python 吃飽沒
三分鐘進階。

2017-05-25

Python 字串格式化(套用變數)

Python 字串格式化就像是 Hibernate 的 HQL 語法中,用 ? 或者 :name 表示 place holder,稍後可以帶入變數,HQL 的好處是可以改進效能與防止 SQL Injection,Python 字串格式化則是可以簡化靜態字串與變數的串接,並格式化變數。

來到 3.6 版,Python 已經有三種字串格式化的方法。
  • printf-style:由於對 tuple 與 dict 支援不夠,建議使用另外兩種方法。
  • Formatted string literal:3.6 版新增。
  • str.format():最強的字串格式化。

printf-style

官方文件

整數後加上 % 是求餘數,字串後加上 % 是格式運算子 Format Operator。

% 前是包含 Conversion specifier 的待格式化字串,% 後是用來取代 Conversion specifier 的變數,視情況可以使用單一變數、tuple 與  dict。

2017-05-19

使用 Python Generator Expression 產生器

Python Generator Expression 產生器很像 Python List Comprehensions,只是它是 Lazy 的。

Lazy 指的不是在建立物件時,就馬上執行所有計算並產生所有 item,而是「輪到了才計算」。

什麼叫輪到了?用 next() 或 for 呼叫時。

語法

( 加工 a 與 b for a in t1 if 符合這個條件 for b in t2 if 符合那個條件...)
和 List Comprehensions 只有一個不一樣,用小括號取代中括號。

Generator 會紀錄目前的讀取位置,只能一直往前讀,不能回頭,硬是要超過邊界會報錯。

2017-05-18

Python List Comprehensions - 終於找到 Map 與 Filter

在 Javascript 學過這三個好用的概念:Map、Filter 與 Reduce,終於在 Python 也找到部份對應的功能。

Map 將一個 list 轉換成另一個 list,item 數不變,但每個 item 變了,就像一對一的轉換。

Filter 將一個 list 過濾成另一個 list,重點是 item 數變少了,一般狀況下 item 不會改變,可以改變是加分。

Reduce 掃過整個 list,得出單一個結果,例如累加。

這功能在 Python 叫做 List Comprehensions。

List Comprehensions

2017-05-17

使用 Python Counter 計數器

Python Counter 為 dict 的 subclass,key 的限制不變,value 固定為 int,用來統計 key 的出現次數,或者說是 key 被放入的次數。
from collections import Counter

c = Counter('Apple')
print(sorted(c.items())) # [('A', 1), ('e', 1), ('l', 1), ('p', 2)]

c['A'] += 1
print(sorted(c.items())) # [('A', 2), ('e', 1), ('l', 1), ('p', 2)]

c['A'] = -5 # 可以使用負數
print(sorted(c.items())) # [('A', -5), ('e', 1), ('l', 1), ('p', 2)]

print(c['X']) # 0,遇到不存在的 key 回傳 0

建立 Counter

有許多方式可以建立 Counter。

用 value 為 int 的 dict。

用 Python defaultdict 解決 Dict key 不存在的問題

每次要取用 dict 時,得先檢查 key 是否存在,否則會得到 KeyError,雖然有 setdefault() 與 getdefault() 可以緩解症狀,但還是不夠直覺且有一點點的效能浪費。

常常忘記要檢查

每次取用前得先用 setdefault() 確認,不夠直覺,容易忘記。
# setdefault with int()
d = dict()

for c in 'Apple':
    d.setdefault(c, 0)
    d[c] += 1

print(d) # {'A': 1, 'p': 2, 'l': 1, 'e': 1}

可能沒必要的呼叫

就算 key 已經存在,還是會執行一次 [] 產生一個空的 list,效能浪費了。
# setdefault with list()
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]

d = dict()

for k, v in s:
    d.setdefault(k, []).append(v)

print(sorted(d.items())) # [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

defaultdict 來簡化

用 defaultdict 來簡化使用的過程,只要在建立 dict 時(事實上是 defaultdict)傳入 key 不存在時,用來建立 key 對應的 value 的函式即可。

defaultdict() 回傳的是 dict 的 subclass,擁有 dict 所有的功能。
# defaultdict with int()
from collections import defaultdict
d = defaultdict(int) # 表示 int(),傳入函式名稱,並未呼叫執行

for c in 'Apple':
    d[c] += 1 # 一旦遇到 key 不存在時,就會呼叫 int() 產生預設值並存入 dict 中

print(d) # defaultdict(<class 'int'>, {'A': 1, 'p': 2, 'l': 1, 'e': 1})

defaultdict 來救效能

只有 key 不存在時才會呼叫 list()。
# defaultdict with list()
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
from collections import defaultdict
d = defaultdict(list) # 表示 list(),傳入函式名稱,並未呼叫執行

for k, v in s:
    d[k].append(v)

print(sorted(d.items())) # [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
dict of sets 也是常用的功能。
# defaultdict with set()
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
from collections import defaultdict
d = defaultdict(set)

for k, v in s:
    d[k].add(v)

print(sorted(d.items())) # [('blue', {2, 4}), ('red', {1, 3})]

官方文件
---
---
---

用 Python namedtuple 快速定義 class

在 Python 定義一個 class,需要一些囉唆的基本工作。
class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
    def __str__(self):
        return 'Book(title=\'' + self.title +'\', author=\'' + self.author + '\')'

b = Book('Python Vol.2', 'Jet')
print(b) # Book(title='Python Vol.2', author='Jet')
print(b.title, b.author) # Python Vol.2 Jet
透過 namedtuple 來定義一個 class 只要一行 code,而且可以用 [N] 取用欄位。
Book = namedtuple('Book', ['title', 'author'])

b = Book('Python Vol.3', 'Swan')
print(b) # Book(title='Python Vol.3', author='Swan')
print(b.title == b[0]) # True
print(b.author == b[1]) # True
t, a = b
print(t, 'by', a) # Python Vol.3 by Swan
也可以透過繼承來增加自訂的 method。
class Ebook(Book):        
    def format(self):
        return self.title + ', ' + self.author

b = Ebook('Python Vol.4', 'Queen')
print(b) # Ebook(title='Python Vol.4', author='Queen')
print(b.format()) # Python Vol.4, Queen
但有一些限制。
  • 最大的一點是 immutable,因為 namedtuple 是建立一個 tuple 的 subclass,所以在建立後不能改值。
  • 就算是透過繼承,也不能再增加新的欄位定義。

官方文件
---
---
---

Java 腦袋學 Python Set

Python Set 概念上和 Java Set 一樣。
  • 無序
  • 唯一(去重複)
  • Hashable
Hashable 保證唯一,同時讓 set 和 list 比起來,新增快,查找快,常用 set 來去除 sequence 中重複的 item,或者檢查 item 是否存在。

Set 的 item 必須是 Hashable,像 dict 的 key 一樣,也就表示 set 的 item 必須是 immutable,所以不可以把 set 裝到 set 裡,目前知道 immutable 的集合物件只有 tuple 一個,很快就會出現另一個了,像 tuple 是 immutable 的 list 一樣,set 也有 immutable 的版本。

set() & {}

語法類似半套的 dict,用大括號,但只有 key,沒有 value。

2017-05-15

Java 腦袋學 Python Zip(與 enumerate())

Zip 又是一個對 Java 陌生的概念。

Zip 可以接受兩個以上的  sequence,然後回傳一個 iterator of tuple,像拉鍊一樣把 sequence 裡每個 item 鍊在一起變成一個 tuple,以最短的 sequence 為準。
z = zip('Python', range(3))
print(z) # <zip object at 0x03D47AD0>
for t in z:
    print(t)
# ('P', 0)
# ('y', 1)
# ('t', 2)
zip 回傳的 zip 物件是一個 iterator 物件,可以用 for-in 讀取每個 item(tuple),不同於 list-like 的地方在於不能用中括號 [N] 讀取指定的 item,也不可以用 list() 轉成 list物件,list() 吃的是 iterable 物件,不是 iterator 物件。

可以搭配多重指定(Tuple assignment)與 for-in 來讀取 Zip 物件。
z = zip('Python', range(9))
for a, b in z:
    print(a, b)
# P 0
# y 1
# t 2
# h 3
# o 4
# n 5

enumerate()

Python 還有一個便捷的函式可以同時取得 sequence 裡的 item 與 index。
for index, item in enumerate('Python'):
    print(index, item)
# 0 P
# 1 y
# 2 t
# 3 h
# 4 o
# 5 n
---
---
---

2017-05-12

Python - 真值判斷(Truth Value Testing)、布林運算(Boolean Operation)與相等運算(Comparison Operation)

在 Python,除了布林型別的值以外,任何物件都可以用來作為真值判斷(Truth Value Testing),而真值判斷(Truth Value Testing)可以用在於 if、while 與布林運算(Boolean Operation)中,這很重要,因為也只有這三個地方可以進行真值判斷(Truth Value Testing),最常誤用的地方是相等運算(Comparison Operation)。

真值判斷(Truth Value Testing)

以下的值在上述三個地方(if、while 與布林運算(Boolean Operation)),會被認為是 False。
  • None
  • False
  • 整數 0 與浮點數 0.0
  • 空的 sequence,例如空字串、空 list 與空 tuple
  • 空的 dict
  • 自訂 class,且__bool__() 回傳 False
  • 自訂 class,且__len__() 回傳 0
上述以外的值則視為 True。

2017-05-05

Python 內建函式庫與標準函式庫

內建函式庫與標準函式庫

Python 內建許多必要的函式,像是 input()、print() 與 len() 等,除此之外還有一些常用的函式庫,視需要再 import 即可,稱為標準函式庫,像是 math 或者 random。
import math
import math,random

from import

類似 Java 的 static import,一般使用 import 語法,在呼叫外部函式時,得加上函式庫名稱,但是改用 from import 後,就可以之接呼叫外部函式庫的函式,不用再加上函式庫名稱。

但實務上容易搞混,分不清這個函式是內建的或者來自某個函式庫,所以很少使用,或者只用在函式庫「路徑非常長」時。
from random import *
for i in range(10):
    print(randint(1, 5))

input()

與使用者互動的函式,等待 user 輸入並按下 Enter 後,可以取得使用者輸入的內容。

Python 小烏龜(Turtle)

我的老天啊,怎麼又會遇到這隻可愛的小烏龜!

Python 提供 turtle 繪圖功能來建立影像。
import turtle
turtle.forward(50)
turtle.left(120)
turtle.forward(50)
turtle.left(120)
turtle.forward(50)

turtle.penup()
turtle.forward(50)

turtle.pendown()
turtle.forward(50)
turtle.left(120)
turtle.forward(50)
turtle.left(120)
turtle.forward(50)
turtle.right(120)

turtle.penup()
turtle.forward(100)
turtle.right(60)

turtle.pendown()
turtle.forward(50)
turtle.right(120)
turtle.forward(50)
turtle.right(120)
turtle.forward(50)
想像在烏龜尾巴綁一枝筆,然後可以控制烏龜前進(forward)、後退(back)、右轉(right)、左轉(left)、抬起尾巴(penup,不會劃線)、放下尾巴(pendown,劃線)、、、等許多動作。

2017-05-03

有點複雜的 Python Scope

Python  的變數 scope 和 Java 的 scope 還蠻不一樣的,要特別注意。

函式的傳入參數只存在於 local scope(也可以叫做 function scope),有別於 global scope。

在函式內指定的變數為 local scope,在函式外指定的變數為 global scope,這裡的指定就是 =。
global_var = 'Neil'
def aFunction(local_var):
    another_local_var = 'Egg'
    print(global_var) # Neil
    print(local_var) # Emma
    print(another_local_var) # Egg
print(global_var) # Neil
aFunction('Emma')
print(local_var) # NameError: name 'local_var' is not defined
print(another_local_var) # NameError: name 'another_local_var' is not defined
local scope 變數在函式結束後就消失了,不能再呼叫。

在函式裡(local scope)可以使用 global scope 變數,但不能對 global scope 變數改值(使用 = ),除非使用 global 語句。
global_var = 'Neil'
def aFunction():
    print(global_var) # Neil
    global_var = 'Egg' # UnboundLocalError: local variable 'global_var' referenced before assignment
aFunction()
在函式裡直接修改 global scope 變數的值會報錯,這個錯誤(UnboundLocalError: local variable 'global_var' referenced before assignment)很奇怪,呆會再解釋。

無極限的 Python Slice 語法

Python Slice 就像是刀子,可以「任意切出」想要的部份,這把刀可以用在字串、list 與 tuple 這類「有序」的集合。

有序的集合

簡單舉例就是排隊,可以用第一位、第二位、、、一路指出每一個 item 的 index。
str = 'SLICE'
print(str[0]) # S
print(str[1]) # L
print(str[2]) # I

li = ['S', 'L', 'I', 'C', 'E']
print(li[0]) # S
print(li[1]) # L
print(li[2]) # I

Slice 語法

[start : stop : step]
以中括號組成,最多可以放入三個參數,每個參數都是 optional。
  • start:起始 index,預設為 0,包含
  • stop:結束 index,預設為總長度,不包含
  • step:進位,預設為 1
step 看似很陌生的概念,其實已經用到爛了,就是以下 Java 迴圈裡的 2,一次進 2 位的意思。