- python 類變量與對象變量
Class Variable 是共享的,它們可以被屬于該類的所有實例訪問。該類變量只擁有一個副本,當任何一個對象對類變量作出改變時,發生的變動將在其它所有實例中都會得到體現。
Object variable 由類的每一個獨立的對象或實例所擁有。在這種情況下,每個對象都擁有屬于它自己的字段的副本,也就是說,它們不會被共享,也不會以任何方式與其它不同實例中的相同名稱的字段產生關聯。
比如:
class Robot:
# 一個類變量
population = 0
def __init__(self, name):
self.name = name
print("(Initializing {})".format(self.name))
#這個population是通過Robot類名調用
Robot.population += 1
def die(self):
print("{} is being destroyed!".format(self.name))
Robot.population -= 1
if Robot.population == 0:
print("{} was the last one.".format(self.name))
else:
print("There are still {:d} robots working.".format(
Robot.population))
def say_hi(self):
print("Greetings, my masters call me {}.".format(self.name))
#類方法
#how_many 實際上是一個屬于類而非屬于對象的方法。
#這就意味著我們可以將它定義為一個 classmethod(類方法) 或是一個 staticmethod(靜態方法),這取決于我們是否需要知道這一方法屬于哪個類。
#由于我們已經引用了一個類變量,因此我們使用 classmethod
@classmethod
def how_many(cls):
print("We have {:d} robots.".format(cls.population))
- 注意當一個對象變量與一個類變量名稱相同時,類變量將會被隱藏。
- 除了 Robot.popluation,我們還可以使用 self.class.population,因為每個對象都通過 self.class 屬性來引用它的類。
- 只能使用 self 來引用同一對象的變量與方法。這被稱作屬性引用(Attribute Reference)。
- 所有的類成員都是公開的。但有一個例外:如果你使用數據成員并在其名字中使用雙下劃線作為前綴,形成諸如 __privatevar 這樣的形式,Python 會使用名稱調整(Name-mangling)來使其有效地成為一個私有變量。
- Exception handler
with - 在 try 塊中獲取資源,然后在 finally 塊中釋放資源,用with可以更優雅的完成。
f = open("poem.txt")
try:
yield f
finally:
f.close()
with open("poem.txt") as f:
for line in f:
print(line, end='')
- Lambda
lambda 語句可以創建一個新的函數對象。從本質上說,lambda 需要一個參數,后跟一個表達式作為函數體,這一表達式執行的值將作為這個新函數的返回值。
points = [{'x': 2, 'y': 3},
{'x': 4, 'y': 1}]
points.sort(key=lambda i: i['y'])
#按y值排序字典
4.列表推導(List Comprehension)
用于從一份現有的列表中得到一份新列表。
listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)
在本案例中,當滿足了某些條件時(if i > 2),我們進行指定的操作(2*i),以此來獲得一份新的列表。要注意到原始列表依舊保持不變。
- 使用列表推導的優點在于,當我們使用循環來處理列表中的每個元素并將其存儲到新的列表中時時,它能減少樣板(Boilerplate)代碼的數量。
5.裝飾器
裝飾器(Decorators)是應用包裝函數的快捷方式。這有助于將某一功能與一些代碼一遍又一遍地“包裝”。
舉個例子,我為自己創建了一個 retry 裝飾器,這樣我可以將其運用到任何函數之中,如果在一次運行中拋出了任何錯誤,它就會嘗試重新運行,直到最大次數 5 次,并且每次運行期間都會有一定的延遲。
from time import sleep
from functools import wraps
import logging
logging.basicConfig()
log = logging.getLogger("retry")
def retry(f):
@wraps(f)
def wrapped_f(*args, **kwargs):
MAX_ATTEMPTS = 5
for attempt in range(1, MAX_ATTEMPTS + 1):
try:
return f(*args, **kwargs)
except:
log.exception("Attempt %s/%s failed : %s",
attempt,
MAX_ATTEMPTS,
(args, kwargs))
sleep(10 * attempt)
log.critical("All %s attempts failed : %s",
MAX_ATTEMPTS,
(args, kwargs))
return wrapped_f
counter = 0
@retry
def save_to_database(arg):
print("Write to a database or make a network call or etc.")
print("This will be automatically retried if exception is thrown.")
global counter
counter += 1
# 這將在第一次調用時拋出異常
# 在第二次運行時將正常工作(也就是重試)
if counter < 2:
raise ValueError(arg)
if __name__ == '__main__':
save_to_database("Some bad value")
- yield
https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
帶有 yield 的函數在 Python 中被稱之為 generator(生成器)
fibonachi
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
Fab 類通過 next() 不斷返回數列的下一個數,內存占用始終為常數:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
for n in fab(5)
#這里就會用到iterater b
print(n)
這樣用了yield就更加簡潔