Python學習筆記九

迭代器函數的重寫

迭代器:可以用next(it)函數取值的對象就是迭代器
迭代器協議:迭代器協議是指對象能夠使用next函數獲取下一項數據,在沒有下一項數據觸發一個StopIterator來終止迭代的約定
實現方法:
類內需要有__next__(self)方法來實現迭代器協議
語法形式:
class MyIterator:
def next(self):
迭代器協議的實現
return 數據
什麼是可迭代對象:是指能用iter(obj)函數返回迭代器的對象(實例);可迭代對象內部一定要定義__iter__(self)方法來返回迭代器。
可迭代對象的語法形式:
class MyIterable:
def iter(self):
語句塊
return 迭代器
示例:

# 此示例示意可迭代對象和迭代器的定義及使用方法
class MyList:
	def __init__(self, iterator):
		'''自定義列表類的初始化方法,此方法創建一個data實例變量來綁定一個用來存儲數據的列表'''
		self.data = list(iterator)

	def __repr__(self):
		'''此方法爲了打印此列表的數據'''
		return "MyList(%r)" % self.data

	def __iter__(self):
		'''有此方法就是可迭代對象,但要求必須返回迭代器'''
		print("__iter__方法被調用")
		return MyListIterator(self.data)

class MyListIterator:
	'''此類用來創建一個迭代器對象,用此迭代器對象可以訪問MyList類型的數據'''
	def __init__(self, iter_data):	
		self.cur = 0 	# 設置迭代器的初始值爲0代表列表索引
		self.it_data = iter_data 	# it_data綁定要迭代的列表

	def __next__(self):
		'''有此方法的對象才叫迭代器,此方法一定要實現迭代器協議'''
		# 如果self.cur已經超出了列表的索引範圍就報迭代結束
		if self.cur >= len(self.it_data):
			raise StopIteration
		# 否則尚未迭代完成,需要返回數據
		r = self.it_data[self.cur] # 拿到要送回去的數
		self.cur = self.cur + 1 	# 將當期值向後移動一個單位
		return r

myl = MyList([2, 3, 5, 7])
print(myl)

for x in myl:
	print(x)   
異常(with)

異常相關語句:
try-except # 用來捕獲異常通知
try-finally # 用來做一定要做的事情
raise # 用來發生異常通知
assert # 用來根據條件發出AssertionError類型的異常通知
with語句:
語法:
with 表達式1[as 變量1], 表達式2[as 變量2]:
語句塊
作用:使用於對資源進行訪問的場合,確保使用過程中不管是否發生異常,都會執行必須的’清理’操作,並釋放資源。
如:文件使用後自動關閉,線程中鎖的自動獲取和釋放等
示例:

# 此示例示意try-except和try-finally組合來對文件進行操作

def read_from_file(filename='/Users/huoshirui/Desktop/test/code/practice/info.txt'):
	try:
		f = open(filename)
		try:
			print("reading from file")
			n = int(f.read())
			print("n=", n)
		finally:
			f.close()
			print("close file")
	except OSError:
		print("fail to open file")

read_from_file()



# 用with語句可以實現上面同樣的功能
# 此示例示意用try-except和with語句組合來實現文件的操作

def read_from_file(filename='/Users/huoshirui/Desktop/test/code/practice/info.txt'):
	try:
		with open(filename) as f:
			print("reading from file")
			n = int(f.read())
			print("n=", n)
			print("close file")
	except OSError:
		print("fail to open file")

read_from_file()

說明:能夠用於with語句進行管理的對象必須是環境管理器

環境管理器

(1)類內有__enter__和__exit__實例方法的類創建的類被稱爲管理器; (2)能夠用with語句管理的對象必須是環境管理器; (3)__enter__方法將在進入with語句時被調用,並返回由as變量管理的對象;(4)__exit__將在離開with語句時被調用,且可以用參數來判斷在離開with語句時是否有異常發生並做出相應的處理
示例:


class A:
	def __enter__(self):
		print("已進入with語句")
		return self 		# 返回的對象將由as綁定
	
	def __exit__(self, exc_type, exc_val, exc_tb):
		'''此方法會在退出with語句時自動調用 exc_type在沒有異常時爲None,在出現異常時爲異常類型;exc_val在沒有異常時爲None,在出現異常時綁定錯誤對象;exc_tb在沒有異常時爲None,在出現異常時綁定traceback對象'''
		if exc_type is None:
			print("已離開with語句")
		else:
			print("已離開with語句,離開時狀態異常")	
			print("異常類型是:", exc_type)
			print("錯誤對象是:", exc_val)
			print("traceback是:", exc_tb)

a = A()
with A() as a:
	print("這是with語句內的一條語句")
	int(input("請輸入整數"))
對象的屬性管理函數
# 從一個對象得到對象的屬性;getattr(x, 'y')等同於x.y;當屬性不存在時,如果給出default參數,
# 則返回default,如果沒有給出default,則參數一個AttributeError錯誤
getattr(obj, name[, default]) 		

# 用給定的name返回對象obj是否有此屬性,此種做法可以避免在getattr(obj, name)時引發錯誤
hasattr(obj, name)

# 給對象obj的名爲name的屬性設置相應的值value, set(x, 'y', v)等同於x.y=v
setattr(obj, name, value)

# 刪除對象obj中的name屬性,delattr(x, 'y')等同於del x.y
delattr(obj, name)


class Dog:
	pass

dog1 = Dog()
# dog1.color會出錯
print(getattr(dog1, 'color', 'no color attribute')) # no color

dog1.color = 'white'
print(getattr(dog1, 'color', 'no color attribute')) # white

print(hasattr(dog1, 'color'))		# True

setattr(dog1, 'age', 1)
print(hasattr(dog1, 'age')) 		# True

delattr(dog1, 'age')
print(hasattr(dog1, 'age'))			# False
運算符重載

讓自定義的類生成的對象(實例)能夠使用運算符進行操作
作用:讓自定義的類的實例像內建對象一樣運行運算符操作;讓程序簡潔易讀;對自定義的對象,將運算符賦予新的運算規則
算術運算符的重載:
add(self, rhs) self+rhs 加法
sub(self, rhs) self-rhs 減法
mul(self, rhs) self*rhs 乘法
truediv(self, rhs) self/rhs 除法
floordiv(self, rhs) self//rhs 地板除法
mod(self, rhs) self%rhs 求餘
pow(self, rhs) self**rhs 冪運算
注:rhs(right hands side)
示例:

# 此示例示意運算符重載與實例方法的相同點和不同點

class MyNumber:
	def __init__(self, v):
		self.data = v

	def __repr__(self):
		return "MyNumber(%d)" % self.data

	# def myadd(self, other):
	# 	v = self.data + other.data
	# 	return MyNumber(v)

	def __add__(self, other):
		print("__add__被調用")
		v = self.data + other.data
		return MyNumber(v)

	def __sub__(self, other):
		v = self.data - other.data
		return MyNumber(v)

n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.myadd(n2)
#n3 = n1.__add__(n2)
n3 = n1 + n2
print(n3)

n4 = n3 - n2
print(n4)
反向算術運算符的重載

當左手邊的類型爲內建類型,右手邊爲自定義類型時,要實現運算必須用以下方法重載
反向算術運算符的重載:
radd(self, lhs) lhs+self 加法
rsub(self, lhs) lhs-self 減法
rmul(self, lhs) lhs*self 乘法
rtruediv(self, lhs) lhs/self 除法
rfloordiv(self, lhs) lhs//self 地板除法
rmod(self, lhs) lhs%self 求餘
rpow(self, lhs) lhs**self 冪運算
示例:

# 實現兩個自定義列表相加:
class MyList:
	def __init__(self, iterable):
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __add__(self, rhs):
		lst = self.data + rhs.data
		return MyList(lst)

	def __mul__(self, rhs): # rhs綁定整數
		return MyList(self.data * rhs)

	def __rmul__(self, lhs):
		print("__rmul__被調用")
		return MyList(self.data * lhs)

L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])
L5 = L1 * 2		# L1.__mul__(2)
print(L5)   # MyList([1, 2, 3, 1, 2, 3])

L6 = 2 * L1
print(L6)		# 2.__mul__(L1)

複合賦值算術運算符的重載
iadd(self, rhs) self+=rhs 加法
isub(self, rhs) self-=rhs 減法
imul(self, rhs) self*=rhs 乘法
itruediv(self, rhs) self/=rhs 除法
ifloordiv(self, rhs) self//=rhs 地板除法
imod(self, rhs) self%=rhs 求餘
ipow(self, rhs) self**=rhs 冪運算
示例:

class MyList:
	def __init__(self, iterable):
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __add__(self, rhs):
		return MyList(self.data + rhs.data)

	def __iadd__(self, rhs):
		print("__iadd__被調用")
		self.data.extend(rhs.data)
		return self.data


L1 = MyList([1, 2, 3])
L2 = MyList([4, 5, 6])

L1 += L2		# 當沒有__iadd__方法時,等同於調用L1 = L1 + L2
print(L1)		# [1, 2, 3, 4, 5, 6]
比較運算符的重載

lt(self, rhs) self < rhs 小於
le(self, rhs) self <= rhs 小於等於
gt(self, rhs) self > rhs 大於
ge(self, rhs) self >= rhs 大於等於
eq(self, rhs) self == rhs 等於
ne(self, rhs) self != rhs 不等於
注:比較運算符通常返回True或False

位運算符重載

invert(self) ~self 取反(一元運算符)
and(self, rhs) self & rhs 位與
or(self, rhs) self | rhs 位或
xor(self, rhs) self ^ rhs 位異或
lshift(self, rhs) self << rhs 左移
rshift(self, rhs) self >> rhs 右移

反向位運算符重載

rand(self, lhs) lhs & self 位與
ror(self, lhs) lhs | self 位或
rxor(self, lhs) lhs ^ self 位異或
rlshift(self, lhs) lhs << self 左移
rrshift(self, lhs) lhs >> self 右移

複合賦值位運算符重載

iand(self, rhs) self &= rhs 位與
ior(self, rhs) self |= rhs 位或
ixor(self, rhs) self ^= rhs 位異或
ilshift(self, rhs) self <<= rhs 左移
irshift(self, rhs) self >>= rhs 右移

一元運算符的重載

neg(self) - self 負號
pos(self) + self 正號
invert(self) ~ self 取反

一元運算符的重載方法

class 類名:
def XXX(self):

示例:

# 此示例示意一元運算符的重載

class MyList:
	def __init__(self, iterable):
		print("__init__被調用")
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __neg__(self):
		'''此方法用來制定-self返回的規則'''
		#L = [-x for x in self.data]
		L = (-x for x in self.data)
		return MyList(L)
	


L1 = MyList([1, 2, 3])
L2 = -L1
print(L2)

運算符重載說明:運算符重載不能改變運算符的優先級
Python類名最好用駝峯命名法:
MyList MyRange 大駝峯(所有單詞首字母大寫,其餘小寫)
getstudentAge 小駝峯(第一個單詞首字母小寫,其他大寫)

in / not in 運算符的重載

重載方法:
contains(self, e): e in self 成員運算
示例:

class MyList:
	def __init__(self, iterable):
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __contains__(self, e):
		'''此方法用來實現in/not in的運算符的重載'''
		for x in self.data:
			if x == e:
				return True
		return False


L1 = MyList([1, 2, 3])
if 2 in L1:
	print("2 在L1中")
else:
	print("2 不在L1中")

if -1 not in L1:
	print("-1 不在L1中")
else:
	print("-1 在L1中")
索引和切片運算符的重載

getitem(self, i) x = self[i] 索引/切片取值
setitem(self, i, v) self[i] = v 索引/切片賦值
delitem(self, i) del self[i] del語句刪除索引等
作用:讓自定義類型的對象能夠支持索引和切片操作
示例:

# 此示例示意[]運算符的重載

class MyList:
	def __init__(self, iterable):
		print("__init__被調用")
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __getitem__(self, i):
		print("__getitem__被調用, i = ", i)
		return self.data[i]

	def __setitem__(self, i, v):
		print("__setitem__被調用, i = ", i, "v = ", v)
		self.data[i] = v	# 修改data綁定的列表


L1 = MyList([1, 2, 3])
v = L1[0]
print(v)

L1[1] = 2 	# 等同於調用L1.__setitem__(1, 2)
print(L1[1])
slice 函數

作用:用於創建一個Slice切片對象,此對象存儲一個切片的起始值,終止值和步長信息
slice(start, stop=None, step=None) 創建一個切片對象
slice的對象的屬性:
s.start 切片起始值,默認爲None
s.stop 切片終止值,默認爲None
s.step 切片步長,默認爲None
示例:

lass MyList:
	def __init__(self, iterable):
		print("__init__被調用")
		self.data = list(iterable)

	def __repr__(self):
		return "MyList(%r)" % self.data

	def __getitem__(self, i):
		print("__getitem__被調用, i = ", i)
		if type(i) is int:
			print("正在做索引操作")
		elif type(i) is slice:
			print("正在做切片操作")
		else:
			raise KeyError
		return self.data[i]

	
L1 = MyList([1, 2, 3, 4, 5, 6])
print(L1[::2])		# 等同於調用L1[slice(None, None, 2)]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章