前言
相對源文檔的一些python2實作,轉成了python3.
相關連結
Python 進階
英文版: Python Tips
The Python Debugger
學習二: python 推導式 Mutation/Immutation virtualenv Collections
Learning Code
# Python 進階
# 1 可選參數
# 使用:函數裝飾器,猴子更新檔(程式運作時(runtime)修改某些代碼)
# *name 必須在 **name 之前出現
# 可選參數列印出來的參數的順序是未定義
# 可選參數應該是是參數清單中的最後一個,因為它們将把所有的剩餘輸入參數傳遞給函數
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
keys = sorted(keywords.keys())
for kw in keys:
print(kw, ":", keywords[kw])
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
# 元組參數 *args
def test_asterisk(f_arg, *arg_vars):
print('f_arg', f_arg)
for arg in arg_vars:
print('arg in arg_vars', arg)
test_asterisk('yasoob', 'python', 'eggs', 'test')
# 字典參數 **dargs
def test_kvps(**arg_vars):
for (key, v) in arg_vars.items():
print("{0} == {1}".format(key, v))
test_kvps(**{'name': 'yasoob'})
# 使用時的順序不能改變
def test_args(arg1, *arg2, **arg3):
print('f_arg', arg1)
for arg in arg2:
print('arg in arg_vars', arg)
for (key, v) in arg3.items():
print("{0} == {1}".format(key, v))
test_args('yasoob', 'python', 'eggs', 'test', 123123, name = 'yasoob')
# * 操作符來自動把參數清單拆開
# ** 操作符分拆關鍵字參數為字典
args = [3, 6]
list(range(*args)) # 等價于list(range(3,6))
def parrot(voltage, state='a stiff', action='voom'):
print('voltage, state, action: ',voltage, state, action, end=' ')
d = {"voltage": "four million", "state": "bleedin' demised"}
parrot(**d) #voltage, state, action: four million bleedin' demised voom
"""
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
"""
# 2 Debugging
'''
python -m pdb my_script.py
c:continue 繼續執行
w:where 顯示目前正在執行的代碼行的上下文資訊
a:args 列印目前函數的參數清單
s:step 執行目前代碼行,并停在第一個能停的地方(相當于單步進入)
n:next 繼續執行到目前函數的下一行,或者目前行直接傳回(單步跳過)
p:print p expression
'''
# 3 生成器(Generators)
'''
疊代(Iteration):當我們使用一個循環來周遊某個東西的過程
疊代器(Iterator): 周遊一個容器(特别是清單)的對象,
定義了next(Python2) 或者__next__方法的對象
可疊代對象(Iterable): 能提供疊代器的任意對象,
定義了可以傳回一個疊代器的__iter__方法,或者可以支援下标索引的__getitem__方法
生成器(Generators): 生成器是隻疊代一次的疊代器.這是因為它們并沒有把所有的值存在記憶體中,而是在運作時生成值.
通過yield每次傳回一個單次運作的值, 而不是直接傳回占用大量空間的一個值
調用:用for循環,或可進行疊代的函數或結構
next(): 它允許我們擷取一個序列的下一個元素. yield所有值後會觸發 StopIteration exception
生成器是資料的生産者 協程則是資料的消費者. yield可獲得一個協程。協程會消費掉發送給它的值,
詳見 學習二:協程(Coroutines)
'''
def fibon(n):
a = b = 1
for i in range(n):
yield a
(a, b) = (b, a+b)
i = 0
for x in fibon(10):
i += 1
print('fibon({0})'.format(i), x)
test_string = 'te'
test = iter(test_string)
print(next(test))
print(next(test))
# print(next(test) ) # 因為 'te'隻有兩個字元, 是以第三次會觸發 StopIteration
# iter and next implement
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]
# 4 Map:n個輸入源傳回n個結果 将函數映射到集合的每個元素,多與lambda連用
# map(function_to_apply, list_of_inputs)
# lambda:匿名函數
# 參數:操作(參數)
items = [1, 2, 3, 4, 5]
squard = list(map(lambda x: x**2, items))
print(squard)
# 将多個函數映射到集合
def multiply(x): return (x**2)
def add(x): return (x*2)
funcs = [multiply, add]
for i in range(5):
# 函數作為lambda的操作對象
value = map(lambda x: x(i), funcs)
print(list(value))
# Filter: 過濾表中的元素, 傳回所有符合要求的元素
# filter(function, iterable)
# 可用推導式替換,推導式的可讀性更好
pr = filter(lambda x: 1==1, range(-5,5))
print(list(pr))
# Reduce 多個輸入源傳回一個結果,對一個清單計算傳回結果:第一個元素與第二個計算,其結果與第三個元素運算
# reduce(function, iterable[, initializer])
from functools import reduce
pro = reduce(lambda x,y:x*y, range(1, 5))
print(pro)
# 5 資料結構
# strings, list, tuple, dictionary
# number:int float bool
# string 'name' 不可變,不可以對其中的字元指派; 多用list替代 可切片
# list [1, 2, 3] 可變,key必須是數字,可以對其組成元素進行增删改 可切片
# tuple (0, 1, 2) 不可變,常用于return傳回的結果,形參,字典鍵, 可切片
# dict {'name':'zhangsan', 'age':20} 可變,key可以是string等非數字 {}
# set {1,2,3} 元素不可以重複,不能切片, 運算的機關是集合
# set 集合:不能包含重複的值 不能切片
some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n']
dup = set([x for x in some_list if some_list.count(x) > 1])
print(dup)
# set intersection 交集
valid = set(['yellow', 'red', 'blue', 'green', 'black'])
input_set = set(['red', 'brown'])
print(input_set.intersection(valid))
# set difference 差集
print(input_set.difference(valid))
# 6 三元運算符
# 如果條件為真,傳回真 否則傳回假
# condition_is_true if condition else condition_is_false
is_fat = True
print('fat' if is_fat else 'not fat')
# 結合元組使用 true means 1, 因為元組要先建資料,是以兩個表達式都會執行
print(('skinny','fat')[is_fat])
# 7 裝飾器
# 一切皆對象:對象可以作為指派給變量或是作為參數傳遞給函數(類似js)
# 不同語言對對象的定義不同,python中的對象隻要有屬性或方法就可以,不要求可子類化,
def hi(name='benji'):
return 'hi '+name
print(hi())
greet = hi #greet不是調用hi函數,而是配置設定到新的記憶體
print(greet())
del hi
#print(hi()) #NameError: name 'hi' is not defined
print(greet())
# 嵌套函數
def hi2(name='benji'):
print('context is in hi()')
def greet2():
print('context is in greet()')
greet2()
print('context is in hi() again')
hi2()
# greet2() #NameError: name 'greet2' is not defined
# 傳回函數
def hi3(name='benji'):
def greet3(): return 'greet3 ' + name
def welcome3(): return 'welcome3'
if name == 'benji':
return welcome3
else:
return greet3
a = hi3()
print(a) #<function hi3.<locals>.greet3 at 0x00DAD7C8>
print(a())
# 函數作為參數
def fun_as_var(func):
print('fun_as_var')
func()
fun_as_var(hi2)
# Python 裝飾器: 封裝一個函數, 圍繞函數,做一些操作
# @decorator: 以單個函數作為參數的一個包裹函數
from functools import wraps
def new_decorator(a_func):
@wraps(a_func) #恢複被裝飾函數的名字和注釋文檔
def wrap_func():
print('before para function in new_decoration ')
a_func()
print('after para function in new_decoration ')
return wrap_func
def a_func():
print('in function needed to be decorated')
new_decorator(a_func)()
@new_decorator
def a_func_with_deco():
print('in a_func_with_deco, function needed to be decorated')
a_func_with_deco()
print(a_func_with_deco.__name__)#wrap_func restore by functools.wraps
# decorator sample
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
print('run in decorator_name')
if not can_run:
return 'function will not run'
return f(*args, **kwargs)
return decorated
@decorator_name
def func(*arg2, **arg3):
for arg in arg2:
print('arg in arg_vars', arg)
for (key, v) in arg3.items():
print("{0} == {1}".format(key, v))
return 'function is running'
can_run = True
print(func(12,'test','asdf'))
# 使用場景
'''# 授權
def require_auth(f):
@warps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
'''
# 日志
def logit_easy(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + ' was called')
return func(*args, **kwargs)
return with_logging
@logit_easy
def addition_func(x):
return x+x
print(addition_func(4))
# 帶參數的裝飾器
# 裝飾器方法本身需要接收函數作為入參,為避免形參沖突,再嵌套一層函數用來接收其他入參
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def warp_function(*args, **kwargs):
log_string = func.__name__ + ' was called.'
print(log_string)
with open(logfile, 'a') as opened_file:
opened_file.write(log_string+'\n')
return func(*args, **kwargs)
return warp_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Decorate Class
# 裝飾類代碼比裝飾函數簡潔,易于拓展,包裹函數可以通過類屬性擷取新功能的參數,不需要嵌套函數
# __call__()方法能夠讓類的執行個體對象,像函數一樣被調用
class logitClass(object):
def __init__(self, logfile='out2.log'):
self.logfile = logfile
def __call__(self, func):
@wraps(func)
def warp_function(*args, **kwargs):
log_string = func.__name__ + ' was called'
print(log_string, self.logfile)
with open(self.logfile, 'a') as opened_file:
opened_file.write(log_string+'\n')
self.notify()
return func(*args, **kwargs)
return warp_function
def notify(self):
print('super notify')
# 包裹函數的文法與之前一緻
@logitClass()
def myclass1func():
pass
myclass1func()
class email_logit(logitClass):
def __init__(self, email='[email protected]', *args, **kwargs):
self.email = email
print('email_logit',args)
for i in args:
print('email_logit',i)
logitClass.__init__(self, *args, **kwargs)
def notify(self):
print('this is in child class email logit')
# ??? 子類如何設定log檔案名稱
# invalid @email_logit('email.log')
@email_logit()
def myclassEmail():
pass
myclassEmail()