之前寫的python規格測試用的東西。可以用jupyter丟進去觀察結果。
#!/usr/bin/env python3
# -*- coding: utf8 -*-
# 除了迴圈/if判斷/函式定義/class定義需要冒號":"之外,行尾不需終結符號
# 註解建議使用linux script style : 井號後面加上空格再開始寫
# 可以跳行的長字串: 使用三個雙引號定義(""")
# 第一個沒有被指定變數的長字串會被當成 class的 docstring (可用變數名稱 __doc__ 存取)
# 靠縮排4格來定義下一層的指令(函數,迴圈,判斷式的後續動作等等)
import sys # for console arguments
""" 這是長字串
第二行 """
longStr2 = """ 這是長字串2
2的第二行 """
print("arg0=" + sys.argv[0])
print(longStr2)
print(__doc__)
__doc__ =""" 這是長字串3
3的第二行 """
print(__doc__)
print('unicode -------------------------------------')
strTmp= '一二三四' # 變數不需宣告,也會持續存在。重複使用時的初始值必須考慮。可以用del指令刪除變數。
# 注意,一個變數被assign初始之後,不要再assign不同的資料結構,容易出現不明問題。
i = -1
j = 6
print(strTmp[i:j]) # 多碼字不是以byte計算,以一個文字為單位。
print(strTmp[1])
# 使用陣列index做存取,在超過陣列範圍的情況下,會產生outbound index exception, 但是套用array slice則不會。
# slice可以為負值,不管起終點都是指從陣列尾倒數。
# 字串物件其中的字不可被修改,只能經過處理產生新的
# 序列資料結構: list [obj1, obj2, ...] ,可以單獨置換list元素,可以slice指定置換list元素,可以接合兩個list
# slice的置換可以只給1個元素"z",也可以丟list["y","z"],起點跟終點相同的話,視同插入。
print('list -------------------------------------')
arJ = [3,4]
arI = [0,1,2] + arJ
print(arI)
print(len(arI))
arI[0:0] = "x" #在陣列頭插入
print(arI)
arI[0:1] = "y" #在陣列頭置換
print(arI)
arI[2:4] = ["a", "b"] #在陣列中置換。
print(arI)
arI[2:3] = ["y", "z"] #在陣列中置換。注意:若是slice的起終點的差,小於置入陣列的大小,視為插入。
print(arI)
arI[0:1] = arI #在陣列頭插入自己,結果是會重複內容
print(arI)
# 多層list, 不可使用slice方式置入
arI[2] = arJ
print(arI)
# 迴圈, 條件表示式,需在尾巴加上":"
print('while loop -------------------------------------')
i = 0
j = 0
while (i < 10):
j = j + i
i = i + 1
print(j)
pass # pass: 不做任何事情。 在一定要有命令行的地方可以發揮作用。
# 序列資料結構 touple: 小括號"()"表示。只有一層可以不寫小括號,直接用逗號定義內容,
# 但是第二層之後必須有括號(obj1, int2, ...) ,應該是故意要跟function call相同
# 建立之後不可改變內容,但是裡面的元素可以改變內容。性質與list類似。元素內容有順序,可重複元素。
# 可使用index存取: touple[0]
# 建立0個元素的內容: 固定指令()
# 建立只有一個元素的內容,必須在後面加上逗號。 (obj, ) 原因猜測是會跟function call parameter重複定義
print('touple -------------------------------------')
x = "x"
y = "y"
z = "z"
touple = (x, y, z) # touple packing
a, b, c = touple # 可以拆解。 注意變數數量必須跟touple的元素數量相同, 太多或太少都會出ValueError
print(touple)
print(touple[0])
print(a + b + c)
print('set -------------------------------------')
# 序列資料結構 set: 以大括號"{}"表示。 而且跟list一樣必須寫。
# 元素順序由系統自行決定不可自訂(操作前是固定的,操作後不保證會不會變動)
# 元素內容可變,但不可重複。放入重複元素會以後蓋前的方式運作。
# 無法循序存取,只能遍歷。有基本的add / remove / pop / clear操作
# 建立0個元素的內容: 固定指令set(),不可使用{},會建立另一種資料結構:dict。
# 無刪除元素指令
a = set('abracadabra') # 注意: 以set()初始化字串的話,結果會是一個單字串的set
b = set('alacazam')
print(a)
print(b)
# 序列資料結構 dictionary : 同樣以大括號"{}"表示,但是定義內容以key: value的方式定義。 運作方式類似java的map, objective c也有dictionary。
# key必須為不可變的物件,像是字串,數字,boolean。也可以用touple定義,但是此時的touple不可包含可變元素。
# 元素有順序,內容可變,要列舉可以用list(dic)取得key list,也可以用dict.items()取得key-value iterable
# 無法直接取得value list。使用 in 運算子只能比對key。
# key: value必須同時存在,key值不會重複,跟set一樣,設定重複的值會以後蓋前的方式運作。
# 比對兩個dict相同,不會管key值順序。
print('dict -------------------------------------')
tel = {'jack': 4098, 'sape': 4139, 'sape': 4140}
print(tel)
tel['guido'] = 4127 # 可使用list運算存取。
print(tel)
del tel['sape'] # 可以用del指令刪除key(value也會消失)。刪除不存在的key會出現KeyError。
print(tel)
tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) # 可以靠touple定義key: value值
print(tel)
tel2 = dict(zip(['one', 'two', 'three'], [1, 2, 3])) # zip(): 把兩個同元素數量的序列以順序合併成touple組合
print(tel2)
# for : 只能對陣列型物件操作。 要寫一般的數字跑法的話,可以使用range(起始, 終點, step)產生iterable物件。
# 或是使用此法產生數字陣列: list(range(起始, 終點, step))
# for的list操作,建議使用slice功能產生copy,避免即時操作list導致iterate成為無窮迴圈
# for/while else : 疊代跑完沒被break的話就執行。若是要設計find流程好用。
# 其他技巧: 可以用dict.items()取得key-value iterable
# 可以用enumerate()取得index-value touple(iterable)
# 二階迴圈可以靠zip()實作
print('for loop -------------------------------------')
i = 0
for ar in range(10): # 只會跑0 ~ n-1的部份
i = i + ar
print(i)
print(ar) # 回傳值為9 (也就是n-1)。 參數會持續存在。
for f in enumerate(a): # 印出來會是touple組合。
print('enumerate {0}= {1}'.format(f[0], f[1]))
index = [0, 1, 2]
value = ['a', 'b', 'c']
for i, v in zip(index, value): # 二階迴圈可以靠zip()實作
print('index[{0}]= {1}'.format(i, v))
# function : 不可控制外部變數,除非以global做特別宣告。 參數加上預設值代表option參數(caller給不足參數的話就會使用預設值)
# 沒給預設值的參數,caller必須給值,要不然執行會錯誤。可以不照參數順序給,但是要使用<parameter name>=value的方式指定
# 使用<parameter name>=value的方式指定,不可重複給同一個參數值
# option參數也可以不照順序給,同樣使用<parameter name>=value的方式指定
# option參數的預設值假如是物件的話,操作過的結果會被保留。若是有重複call的動作要注意。解決方案如下面的程式碼的參數z。
# 函式的參數可以帶函式(因為函式本身就是一個物件)。
# 函式物件的物件定義: function.__self__ --- 一個帶著函式方法fucntion()的物件。
# 函式物件的函式定義: function.__func__(self, param1, param2, ...) --- 等同於class method。
# 參數名帶*號,會收集傳進來的所有照順序給的參數(除了已指定的之外)。
# 參數名帶**號,會收集傳進來的所有<parameter name>=value的方式指定的參數(除了已指定的之外)。
# 傳入順序參數時,可以利用list傳入。 但是要在參數名前面加上*號
# lambda function: 單行的無名function可以不需寫def來定義。參數可以參照上層。
print('function -------------------------------------')
def plusplus(n, x=1, y= ["zzzzz"], z = None):
if z is None:
z=[]
n = n + 1 # python沒有累加算符(++)
x= x + 1
print(x)
y.append("a") # 操作的結果會被保留
print(y)
return n # 不指定回傳值(包含只寫了return)的話,caller會接到None這個物件。
print(plusplus(i))
print(plusplus(i))
print(plusplus(*[i, 2]))
print(plusplus(i, y=['yyyyy'])) # lambda function
print(i)
def funcplus(a,b):
return a(b)
print('function parameter -------------------------------------')
print(funcplus(plusplus, 1))
# 判斷式if : 可以用 in (datatype1, objet2, list3, ...) 的方式比對一個個obj。這種touple表示的物件,因為只比對第一層的obj表列,並不會比對陣列內部內容
print('if else elif -------------------------------------')
if (arI) in (45, arI): # in也是比較運算子。其他的比較運算子: == && < > <= >=
print("here")
else:
print("there")
if ([4, 3]) in arI[:]: # in直接丟一個list物件進去的場合,不同的list, 只要順序跟內容相同,就會被找到
print("revarray")
if (arJ) in arI[:]: # 不只是同一個list,不同的list, 只要順序跟內容相同,也會被找到
print("array")
if ([3, 4]) in arI[:]: # 不只是同一個list,不同的list, 只要順序跟內容相同,也會被找到
print("newarray")
print(arI in (45, arI)) # 簡易比較的寫法。其他語言也有
# 資料型態: None (一般語言的null,注意大小寫,是系統預設的物件)
# NaN : 非數字,是系統預設的物件
# boolean : True / False (注意大小寫)
# assign 的動作只能出現在左端,不能出現在比較式內。
# None的比對敘述: if a is None:
# 模組: import 之後會跑一次模組檔案的內容,也就是所謂的初始動作。
# as : 別名
# 模組內參數存取:modname.itemname
# 模組只會初始化一次,而且永久有效。所以要是import過之後改了模組,在不重啟python執行器的狀況下要更新模組,
# 可以 import importlib,再執行 importlib.reload(modulename) 。
# 如何讓模組判斷現在是當成主程式在跑: if __name__ == "__main__" 這樣方便單獨測試。
# 模組路徑: 1. 主模組執行的同一個目錄 2. PYTHONPATH
# 如何增加模組搜尋路徑: sys.path.append('<路徑>')
print('import -------------------------------------')
import requests as http
print(dir()) # 這樣可以印出目前有用到的所有method跟變數。
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4",
"Accept-Encoding": "gzip, deflate",
"User-Agent": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36",
}
url = "https://udn.com/news/story/7338/4091931"
# print(sys.path)
# try:
# r = http.get(
# url, verify=False, headers=headers, timeout=(10, 30)
# ) # ,proxies=proxies)
# except:
# print(r.text)
# 例外處理 : try / except 一個try可以有多個except, 若是except沒指定,會傳到上層的try / except。 都沒捕捉的話就拋出系統錯誤,停止執行
# except可以一次捕捉多個。 格式: except (RuntimeError, TypeError, NameError):
# raise : 丟出例外
# 在例外處理中再丟出例外,就是給上一層處理。
print('try except -------------------------------------')
print('class -------------------------------------')
# class定義方式: class ClassName(Extend from class1, Extend from class2, ...):
# self : 物件本身 (就是java/c++的this)
# class的初始化: 定義函數 __init__(self, arg0, arg1,...)
# new一個class(產生一個class物件): ClassName(arg0, arg1,...)
# 物件函式與class函式的關係: 假設x為MyClass的物件, x.f() 等同於 MyClass.f(x) 。python不分class method或是object method...
# class內定義參數的話,所有從同一個class產生或是繼承的物件共享該參數。
# class method要操作物件的參數,必須以self操作。
# object.__class__ : 判斷該object是哪種class(就是傳回該物件的class定義結構)。
# 預設的class比對方法: isinstance(obj, <classname>)
# 是不是繼承class的比對: issubclass(object.__class__, <classname>)
# class內部參數: __name__ ,會給class的可讀名稱
# 定義一般函式,要給class/object 當作method用的話,第一個參數必須是self。
# 繼承可以指定模組內的某個class。
# 繼承來的class function可以改寫(因為沒有特別的阻擋機制)
# class function改寫後要call baseclass的函式也是可以的。就直接執行class method即可。
# 例:BaseClassName.methodname(self, arguments)
# 要注意,假如是class中的class,就不能這樣做。
# 空的class : 在class定義後加上一行"pass"。 就可以拿來放任何東西,不過這樣做比較難掌握其內容。(是可以靠dir()來列舉...)
class MyClass(int):
def __init__(self):
self.lArray = []
def add(self, x):
self.lArray.append(x)
myClass = MyClass()
print(issubclass(myClass.__class__, int))
print(myClass.__class__ is MyClass)
print(myClass.lArray.__class__.__name__)
print(myClass.add.__self__)
myClass.add.__func__(myClass, "a")
print(myClass.lArray)
print('namespace -------------------------------------')
# Namespace: global --- 此參數定義之後,會影響模組的最上層的區域。
# nonlocal --- 此參數定義之後,會影響下了該定義的階層的上一層。
# 不建議依賴系統的動態變數解析。(乖乖的傳參數的意思)
def scope_test(): # 第二層
def do_local(): # 第三層
spam = "local spam" # do_local 內部的spam
def do_nonlocal():
nonlocal spam # spam 定義在上一層。
spam = "nonlocal spam" # 此例上一層已定義spam = "test spam", 所以執行此動作的話,第二層的spam會被定義為"nonlocal spam"
def do_global():
global spam # spam定義在此模組的第一層
spam = "global spam" # 這時第一層的spam才被賦值
spam = "test spam" # 第二層的spam定義。不會影響第一層
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam) # 第一層
# iterator
# 只要該物件/class有實作__iter__(self), __next__(self),丟出StopIteration的動作的話,就可以被迴圈用來迭代。
# python原生函式: iterator = iter(obj) --- 獲得該物件的迭代器。
# python原生函式: next(iterator) --- 執行一次迭代。通常會回傳迭代物件
# 下面是一個簡單的可迭代class的實作。
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
print('iterator -------------------------------------')
rev = Reverse('spam')
iter(rev)
for char in rev:
print(char)
# generator : 不需定義class就可以產生可迭代物件的方法。
# 只要函式定義裡面使用yield關鍵字(作用是回傳物件),就自動成為可迭代的動作。
def GenReverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
print('generator -------------------------------------')
genReverse = GenReverse('abc')
print(next(genReverse))
print(next(genReverse))
print(next(genReverse))