Python奇技淫巧
當釋出python第三方package時, 並不希望程式碼中所有的函式或者class可以被外部import, 在 __init__.py 中新增 __all__ 屬性,
該list中填寫可以import的類或者函式名, 可以起到限制的import的作用, 防止外部import其他函式或者類
#!/usr/bin/env python
# -*- coding: utf-8 -*-
frombaseimportAPIBase
fromclientimportClient
fromdecoratorimportinterface, export, stream
fromserverimportServer
fromstorageimportStorage
fromutilimport(LogFormatter, disable_logging_to_stderr,
enable_logging_to_kids, info)
__all__ = ["APIBase","Client","LogFormatter","Server",
"Storage","disable_logging_to_stderr","enable_logging_to_kids",
"export","info","interface","stream"]
with的魔力
with語句需要支援 上下文管理協議的物件 , 上下文管理協議包含 __enter__ 和 __exit__ 兩個方法. with語句建立執行時上下文需要透過這兩個方法執行 進入和退出 操作.
其中 上下文表達式 是跟在with之後的表示式, 該表示大返回一個上下文管理物件
# 常見with使用場景
withopen("test.txt","r")asmy_file:# 注意, 是__enter__()方法的返回值賦值給了my_file,
forlineinmy_file:
print line
詳細原理可以檢視這篇文章, 淺談 Python 的 with 語句
知道具體原理, 我們可以自定義支援上下文管理協議的類, 類中實現 __enter__ 和 __exit__ 方法
classMyWith(object):
def__init__(self):
print"__init__ method"
def__enter__(self):
print"__enter__ method"
returnself# 返回物件給as後的變數
def__exit__(self, exc_type, exc_value, exc_traceback):
print"__exit__ method"
ifexc_tracebackisNone:
print"Exited without Exception"
returnTrue
else:
print"Exited with Exception"
returnFalse
deftest_with():
withMyWith()asmy_with:
print"running my_with"
print"------分割線-----"
print"running before Exception"
raiseException
print"running after Exception"
if__name__ =="__main__":
test_with()
執行結果如下:
__init__ method
__enter__ method
running my_with
__exit__ method
ExitedwithoutException
------分割線-----
running before Exception
ExitedwithException
Traceback(most recent call last):
File"bin/python", line34,in
exec(compile(__file__f.read(), __file__, "exec"))
File"test_with.py", line33,in
File"test_with.py", line28,intest_with
Exception
證明了會先執行 __enter__ 方法, 然後呼叫with內的邏輯, 最後執行 __exit__ 做退出處理, 並且, 即使出現異常也能正常退出
filter的用法
相對 filter 而言, map和reduce使用的會更頻繁一些, filter 正如其名字, 按照某種規則 過濾 掉一些元素
lst = [1,2,3,4,5,6]
# 所有奇數都會返回True, 偶數會返回False被過濾掉
print filter(lambda x: x % 2!=0, lst)
#輸出結果
[1,3,5]
一行作判斷
當條件滿足時, 返回的為等號後面的變數, 否則返回else後語句
lst = [1,2,3]
new_lst = lst[0]iflstisnotNoneelseNone
printnew_lst
# 列印結果
1
裝飾器之單例
使用裝飾器實現簡單的單例模式
# 單例裝飾器
defsingleton(cls):
instances = dict() # 初始為空
def_singleton(*args, **kwargs):
ifclsnotininstances:#如果不存在, 則建立並放入字典
instances[cls] = cls(*args, **kwargs)
returninstances[cls]
return_singleton
@singleton
classTest(object):
pass
t1 = Test()
t2 = Test()
# 兩者具有相同的地址
printt1, t2
staticmethod裝飾器
類中兩種常用的裝飾, 首先區分一下他們
普通成員函式, 其中第一個隱式引數為 物件
classmethod裝飾器 , 類方法(給人感覺非常類似於OC中的類方法), 其中第一個隱式引數為 類
staticmethod裝飾器 , 沒有任何隱式引數. python中的靜態方法類似與C++中的靜態方法
classA(object):
# 普通成員函式
deffoo(self, x):
print "executing foo(%s, %s)"% (self, x)
@classmethod# 使用classmethod進行裝飾
defclass_foo(cls, x):
print "executing class_foo(%s, %s)"% (cls, x)
@staticmethod# 使用staticmethod進行裝飾
defstatic_foo(x):
print "executing static_foo(%s)"% x
deftest_three_method():
obj = A()
# 直接呼叫噗通的成員方法
obj.foo("para")# 此處obj物件作為成員函式的隱式引數, 就是self
obj.class_foo("para")# 此處類作為隱式引數被傳入, 就是cls
A.class_foo("para")#更直接的類方法呼叫
obj.static_foo("para")# 靜態方法並沒有任何隱式引數, 但是要透過物件或者類進行呼叫
A.static_foo("para")
if__name__=="__main__":
test_three_method()
# 函式輸出
executing foo(
executing class_foo(
executing static_foo(para)
property裝飾器
定義私有類屬性
將 property 與裝飾器結合實現屬性私有化( 更簡單安全的實現get和set方法 )
#python內建函式
property(fget=None, fset=None, fdel=None, doc=None)
property有三個方法 getter() , setter() 和 delete() 來指定fget, fset和fdel。 這表示以下這行
classStudent(object):
@property #相當於property.getter(score) 或者property(score)
defscore(self):
returnself._score
@score.setter #相當於score = property.setter(score)
defscore(self, value):
ifnotisinstance(value, int):
raiseValueError("score must be an integer!")
ifvalue 100:
raiseValueError("score must between 0 ~ 100!")
self._score = value
iter魔法
透過yield和 __iter__ 的結合, 我們可以把一個物件變成可迭代的
透過 __str__ 的重寫, 可以直接透過想要的形式列印物件
classTestIter(object):
self.lst = [1,2,3,4,5]
defread(self):
foreleinxrange(len(self.lst)):
yieldele
def__iter__(self):
returnself.read()
def__str__(self):
return",".join(map(str, self.lst))
__repr__ = __str__
deftest_iter():
obj = TestIter()
fornuminobj:
printnum
printobj
test_iter()
神奇partial
partial使用上很像C++中仿函式(函式物件).
在stackoverflow給出了類似與partial的執行方式
defpartial(func, *part_args):
defwrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
returnfunc(*args)
returnwrapper
利用用閉包的特性繫結預先繫結一些函式引數, 返回一個可呼叫的變數, 直到真正的呼叫執行
fromfunctoolsimportpartial
defsum(a, b):
returna + b
deftest_partial():
fun = partial(sum, 2)# 事先繫結一個引數, fun成為一個只需要一個引數的可呼叫變數
printfun(3)# 實現執行的即是sum(2, 3)
test_partial()
# 執行結果
5
神秘eval
eval我理解為一種內嵌的python直譯器(這種解釋可能會有偏差), 會解釋字串為對應的程式碼並執行, 並且將執行結果返回
看一下下面這個例子
deftest_first():
return3
deftest_second(num):
returnnum
action = { # 可以看做是一個sandbox
"para":5,
"test_first": test_first,
"test_second": test_second
}
deftest_eavl():
condition = "para == 5 and test_second(test_first) > 5"
res = eval(condition, action) # 解釋condition並根據action對應的動作執行
printres
if__name__ =="_
exec
exec在Python中會忽略返回值, 總是返回None, eval會返回執行程式碼或語句的返回值
exec 和 eval 在執行程式碼時, 除了返回值其他行為都相同
在傳入字串時, 會使用 compile(source, "
print"hello"
deftest_second():
test_first()
print"second"
deftest_third():
print"third"
action = {
"test_second": test_second,
"test_third": test_third
deftest_exec():
exec"test_second"inaction
test_exec() # 無法看到執行結果
getattr
getattr(object, name[, default]) Return the value of
the named attribute of object. name must be a string. If the string is
the name of one of the object’s attributes, the result is the value of
that attribute. For example, getattr(x, ‘foobar’) is equivalent to
x.foobar. If the named attribute does not exist, default is returned if
provided, otherwise AttributeError is raised.
透過string型別的name, 返回物件的name屬性(方法)對應的值, 如果屬性不存在, 則返回預設值, 相當於object.name
# 使用範例
classTestGetAttr(object):
test = "test attribute"
defsay(self):
print"test method"
deftest_getattr():
my_test = TestGetAttr()
try:
printgetattr(my_test,"test")
exceptAttributeError:
print"Attribute Error!"
getattr(my_test, "say")()
exceptAttributeError:# 沒有該屬性, 且沒有指定返回值的情況下
print"Method Error!"
test_getattr()
# 輸出結果
test attribute
test method
命令列處理
defprocess_command_line(argv):
"""
Return a 2-tuple: (settings object, args list).
`argv` is a list of arguments, or `None` for ``sys.argv[1:]``.
ifargvisNone:
argv = sys.argv[1:]
# initialize the parser object:
parser = optparse.OptionParser(
formatter=optparse.TitledHelpFormatter(width=78),
add_help_option=None)
# define options here:
parser.add_option( # customized description; put --help last
"-h","--help", action="help",
help="Show this help message and exit.")
settings, args = parser.parse_args(argv)
# check number of arguments, verify values, etc.:
ifargs:
parser.error("program takes no command-line arguments; "
""%s" ignored."% (args,))
# further process settings & args if necessary
returnsettings, args
defmain(argv=None):
settings, args = process_command_line(argv)
# application code here, like:
# run(settings, args)
return0# success
status = main()
sys.exit(status)
讀寫csv檔案
# 從csv中讀取檔案, 基本和傳統檔案讀取類似
importcsv
withopen("data.csv","rb")asf:
reader = csv.reader(f)
forrowinreader:
printrow
# 向csv檔案寫入
withopen("data.csv","wb")asf:
writer = csv.writer(f)
writer.writerow(["name","address","age"])# 單行寫入
data = [
( "xiaoming ","china","10"),
( "Lily","USA","12")]
writer.writerows(data) # 多行寫入
各種時間形式轉換
只發一張網上的圖, 然後差文件就好了, 這個是記不住的
字串格式化
一個非常好用, 很多人又不知道的功能
>>>name ="andrew"
>>>"my name is {name}".format(name=name)
"my name is andrew"
Python奇技淫巧
當釋出python第三方package時, 並不希望程式碼中所有的函式或者class可以被外部import, 在 __init__.py 中新增 __all__ 屬性,
該list中填寫可以import的類或者函式名, 可以起到限制的import的作用, 防止外部import其他函式或者類
#!/usr/bin/env python
# -*- coding: utf-8 -*-
frombaseimportAPIBase
fromclientimportClient
fromdecoratorimportinterface, export, stream
fromserverimportServer
fromstorageimportStorage
fromutilimport(LogFormatter, disable_logging_to_stderr,
enable_logging_to_kids, info)
__all__ = ["APIBase","Client","LogFormatter","Server",
"Storage","disable_logging_to_stderr","enable_logging_to_kids",
"export","info","interface","stream"]
with的魔力
with語句需要支援 上下文管理協議的物件 , 上下文管理協議包含 __enter__ 和 __exit__ 兩個方法. with語句建立執行時上下文需要透過這兩個方法執行 進入和退出 操作.
其中 上下文表達式 是跟在with之後的表示式, 該表示大返回一個上下文管理物件
# 常見with使用場景
withopen("test.txt","r")asmy_file:# 注意, 是__enter__()方法的返回值賦值給了my_file,
forlineinmy_file:
print line
詳細原理可以檢視這篇文章, 淺談 Python 的 with 語句
知道具體原理, 我們可以自定義支援上下文管理協議的類, 類中實現 __enter__ 和 __exit__ 方法
#!/usr/bin/env python
# -*- coding: utf-8 -*-
classMyWith(object):
def__init__(self):
print"__init__ method"
def__enter__(self):
print"__enter__ method"
returnself# 返回物件給as後的變數
def__exit__(self, exc_type, exc_value, exc_traceback):
print"__exit__ method"
ifexc_tracebackisNone:
print"Exited without Exception"
returnTrue
else:
print"Exited with Exception"
returnFalse
deftest_with():
withMyWith()asmy_with:
print"running my_with"
print"------分割線-----"
withMyWith()asmy_with:
print"running before Exception"
raiseException
print"running after Exception"
if__name__ =="__main__":
test_with()
執行結果如下:
__init__ method
__enter__ method
running my_with
__exit__ method
ExitedwithoutException
------分割線-----
__init__ method
__enter__ method
running before Exception
__exit__ method
ExitedwithException
Traceback(most recent call last):
File"bin/python", line34,in
exec(compile(__file__f.read(), __file__, "exec"))
File"test_with.py", line33,in
test_with()
File"test_with.py", line28,intest_with
raiseException
Exception
證明了會先執行 __enter__ 方法, 然後呼叫with內的邏輯, 最後執行 __exit__ 做退出處理, 並且, 即使出現異常也能正常退出
filter的用法
相對 filter 而言, map和reduce使用的會更頻繁一些, filter 正如其名字, 按照某種規則 過濾 掉一些元素
#!/usr/bin/env python
# -*- coding: utf-8 -*-
lst = [1,2,3,4,5,6]
# 所有奇數都會返回True, 偶數會返回False被過濾掉
print filter(lambda x: x % 2!=0, lst)
#輸出結果
[1,3,5]
一行作判斷
當條件滿足時, 返回的為等號後面的變數, 否則返回else後語句
lst = [1,2,3]
new_lst = lst[0]iflstisnotNoneelseNone
printnew_lst
# 列印結果
1
裝飾器之單例
使用裝飾器實現簡單的單例模式
# 單例裝飾器
defsingleton(cls):
instances = dict() # 初始為空
def_singleton(*args, **kwargs):
ifclsnotininstances:#如果不存在, 則建立並放入字典
instances[cls] = cls(*args, **kwargs)
returninstances[cls]
return_singleton
@singleton
classTest(object):
pass
if__name__ =="__main__":
t1 = Test()
t2 = Test()
# 兩者具有相同的地址
printt1, t2
staticmethod裝飾器
類中兩種常用的裝飾, 首先區分一下他們
普通成員函式, 其中第一個隱式引數為 物件
classmethod裝飾器 , 類方法(給人感覺非常類似於OC中的類方法), 其中第一個隱式引數為 類
staticmethod裝飾器 , 沒有任何隱式引數. python中的靜態方法類似與C++中的靜態方法
#!/usr/bin/env python
# -*- coding: utf-8 -*-
classA(object):
# 普通成員函式
deffoo(self, x):
print "executing foo(%s, %s)"% (self, x)
@classmethod# 使用classmethod進行裝飾
defclass_foo(cls, x):
print "executing class_foo(%s, %s)"% (cls, x)
@staticmethod# 使用staticmethod進行裝飾
defstatic_foo(x):
print "executing static_foo(%s)"% x
deftest_three_method():
obj = A()
# 直接呼叫噗通的成員方法
obj.foo("para")# 此處obj物件作為成員函式的隱式引數, 就是self
obj.class_foo("para")# 此處類作為隱式引數被傳入, 就是cls
A.class_foo("para")#更直接的類方法呼叫
obj.static_foo("para")# 靜態方法並沒有任何隱式引數, 但是要透過物件或者類進行呼叫
A.static_foo("para")
if__name__=="__main__":
test_three_method()
# 函式輸出
executing foo(
executing class_foo(
executing class_foo(
executing static_foo(para)
executing static_foo(para)
property裝飾器
定義私有類屬性
將 property 與裝飾器結合實現屬性私有化( 更簡單安全的實現get和set方法 )
#python內建函式
property(fget=None, fset=None, fdel=None, doc=None)
property有三個方法 getter() , setter() 和 delete() 來指定fget, fset和fdel。 這表示以下這行
classStudent(object):
@property #相當於property.getter(score) 或者property(score)
defscore(self):
returnself._score
@score.setter #相當於score = property.setter(score)
defscore(self, value):
ifnotisinstance(value, int):
raiseValueError("score must be an integer!")
ifvalue 100:
raiseValueError("score must between 0 ~ 100!")
self._score = value
iter魔法
透過yield和 __iter__ 的結合, 我們可以把一個物件變成可迭代的
透過 __str__ 的重寫, 可以直接透過想要的形式列印物件
#!/usr/bin/env python
# -*- coding: utf-8 -*-
classTestIter(object):
def__init__(self):
self.lst = [1,2,3,4,5]
defread(self):
foreleinxrange(len(self.lst)):
yieldele
def__iter__(self):
returnself.read()
def__str__(self):
return",".join(map(str, self.lst))
__repr__ = __str__
deftest_iter():
obj = TestIter()
fornuminobj:
printnum
printobj
if__name__ =="__main__":
test_iter()
神奇partial
partial使用上很像C++中仿函式(函式物件).
在stackoverflow給出了類似與partial的執行方式
defpartial(func, *part_args):
defwrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
returnfunc(*args)
returnwrapper
利用用閉包的特性繫結預先繫結一些函式引數, 返回一個可呼叫的變數, 直到真正的呼叫執行
#!/usr/bin/env python
# -*- coding: utf-8 -*-
fromfunctoolsimportpartial
defsum(a, b):
returna + b
deftest_partial():
fun = partial(sum, 2)# 事先繫結一個引數, fun成為一個只需要一個引數的可呼叫變數
printfun(3)# 實現執行的即是sum(2, 3)
if__name__ =="__main__":
test_partial()
# 執行結果
5
神秘eval
eval我理解為一種內嵌的python直譯器(這種解釋可能會有偏差), 會解釋字串為對應的程式碼並執行, 並且將執行結果返回
看一下下面這個例子
#!/usr/bin/env python
# -*- coding: utf-8 -*-
deftest_first():
return3
deftest_second(num):
returnnum
action = { # 可以看做是一個sandbox
"para":5,
"test_first": test_first,
"test_second": test_second
}
deftest_eavl():
condition = "para == 5 and test_second(test_first) > 5"
res = eval(condition, action) # 解釋condition並根據action對應的動作執行
printres
if__name__ =="_
exec
exec在Python中會忽略返回值, 總是返回None, eval會返回執行程式碼或語句的返回值
exec 和 eval 在執行程式碼時, 除了返回值其他行為都相同
在傳入字串時, 會使用 compile(source, "
#!/usr/bin/env python
# -*- coding: utf-8 -*-
deftest_first():
print"hello"
deftest_second():
test_first()
print"second"
deftest_third():
print"third"
action = {
"test_second": test_second,
"test_third": test_third
}
deftest_exec():
exec"test_second"inaction
if__name__ =="__main__":
test_exec() # 無法看到執行結果
getattr
getattr(object, name[, default]) Return the value of
the named attribute of object. name must be a string. If the string is
the name of one of the object’s attributes, the result is the value of
that attribute. For example, getattr(x, ‘foobar’) is equivalent to
x.foobar. If the named attribute does not exist, default is returned if
provided, otherwise AttributeError is raised.
透過string型別的name, 返回物件的name屬性(方法)對應的值, 如果屬性不存在, 則返回預設值, 相當於object.name
# 使用範例
classTestGetAttr(object):
test = "test attribute"
defsay(self):
print"test method"
deftest_getattr():
my_test = TestGetAttr()
try:
printgetattr(my_test,"test")
exceptAttributeError:
print"Attribute Error!"
try:
getattr(my_test, "say")()
exceptAttributeError:# 沒有該屬性, 且沒有指定返回值的情況下
print"Method Error!"
if__name__ =="__main__":
test_getattr()
# 輸出結果
test attribute
test method
命令列處理
defprocess_command_line(argv):
"""
Return a 2-tuple: (settings object, args list).
`argv` is a list of arguments, or `None` for ``sys.argv[1:]``.
"""
ifargvisNone:
argv = sys.argv[1:]
# initialize the parser object:
parser = optparse.OptionParser(
formatter=optparse.TitledHelpFormatter(width=78),
add_help_option=None)
# define options here:
parser.add_option( # customized description; put --help last
"-h","--help", action="help",
help="Show this help message and exit.")
settings, args = parser.parse_args(argv)
# check number of arguments, verify values, etc.:
ifargs:
parser.error("program takes no command-line arguments; "
""%s" ignored."% (args,))
# further process settings & args if necessary
returnsettings, args
defmain(argv=None):
settings, args = process_command_line(argv)
# application code here, like:
# run(settings, args)
return0# success
if__name__ =="__main__":
status = main()
sys.exit(status)
讀寫csv檔案
# 從csv中讀取檔案, 基本和傳統檔案讀取類似
importcsv
withopen("data.csv","rb")asf:
reader = csv.reader(f)
forrowinreader:
printrow
# 向csv檔案寫入
importcsv
withopen("data.csv","wb")asf:
writer = csv.writer(f)
writer.writerow(["name","address","age"])# 單行寫入
data = [
( "xiaoming ","china","10"),
( "Lily","USA","12")]
writer.writerows(data) # 多行寫入
各種時間形式轉換
只發一張網上的圖, 然後差文件就好了, 這個是記不住的
字串格式化
一個非常好用, 很多人又不知道的功能
>>>name ="andrew"
>>>"my name is {name}".format(name=name)
"my name is andrew"