- 取得連結
- X
- 以電子郵件傳送
- 其他應用程式
程式語言:Python
官方文件
簡介:class 宣告與使用
要避免這個命名的衝突 (這常常是許多 bug 的由來)
建議的命名規則,如下
變數
宣告變數,在任意地方賦值即成立
函式(function) & 方法(method)
宣告函式,在任意地方賦於即成立
instancemethod
classmethod
staticmethod
dict 範例
二維 list 範例
property() 函式 Special method names
官方文件
簡介:class 宣告與使用
class ClassName: # name mangling "_ClassName__dis" __dis = 0 _r = 10 # 初始化 def __init__(self, x, y): self.x = x self.y = y c = ClassName(1, 2) # 類別或實例本身會擁有一個__dict__特性參考至一個字典物件,其中記錄著類別或實例所擁有的特性 # 如果實例的__dict__中沒有,則到產生實例的類別__dict__中尋找 # 所以 c.__dict__ 看不到 _r print(c.__dict__) print(ClassName.__dict__)
宣告 attribute
如果 data attributes 和 method attributes 有相同名稱的話,會導致最先宣告的被覆蓋要避免這個命名的衝突 (這常常是許多 bug 的由來)
建議的命名規則,如下
- method 都是大寫的
- data attribute 的前面加上一些小字串 (或者是底線)
- method 都用動詞,data attribute 都用名詞
變數
宣告變數,在任意地方賦值即成立
class ClassName: # private # 例:__spam 會被重命名為 _ClassName__spam # 最前面至少要有兩個底線,最後面最多只能有一個底線 __private = 'private' __private_ = '123' __private_t = [1, 2, 3] # public __public__ = 10 # 利用 __init__ 宣告變數 def __init__(self, x): self.x = x # 呼叫其他變數 self.__private = 'privateChange' ClassName.y = 'y' # 在 class 等級加入變數 ClassName.__y = 'y' # 無效,仍是 public c = ClassName('x') c.z = 'z' # 在 instance 等級加入變數,不影響 class 後續的宣告 c.__z = 'y' # 無效,仍是 public # 類別或實例本身會擁有一個__dict__特性參考至一個字典物件,其中記錄著類別或實例所擁有的特性 # 如果實例的__dict__中沒有,則到產生實例的類別__dict__中尋找 # 所以 c.__dict__ 看不到 _r print(c.__dict__) print(ClassName.__dict__) # 可強制呼叫 private variable 甚至賦值,但這並不安全 print(c._ClassName__private)
函式(function) & 方法(method)
宣告函式,在任意地方賦於即成立
def beforeF(self): print('beforeF') def afterF(self): print('afterF') class ClassName: # 利用 __init__ 宣告變數 def __init__(self, x): self.x = x # private # 例:__spam 會被重命名為 _ClassName__spam # 最前面至少要有兩個底線,最後面最多只能有一個底線 __private = beforeF def __private_(self): print('__private_') # 習慣上,我們把一個method的第一個參數叫做 self 。這只是一個習慣 # self 這個名字對 Python 來說完全沒有什麼特殊的意義 # 但建議 follow,這可增加可讀性 # self 改為 ttself 仍可正常執行 def __public__(ttself): print('__public__') # 呼叫其他 function ttself.__private_() ClassName.F = afterF c = ClassName('x') c.f = afterF # 在 instance 等級加入變數,不影響 class 後續的宣告 # 類別或實例本身會擁有一個__dict__特性參考至一個字典物件,其中記錄著類別或實例所擁有的特性 # 如果實例的__dict__中沒有,則到產生實例的類別__dict__中尋找 # 所以 c.__dict__ 看不到 _r print(c.__dict__) print(ClassName.__dict__) c.__public__() # __public__ # __private_ c.F() # afterF # 可強制呼叫 private method 甚至重新賦於 function,但這並不安全 c._ClassName__private() # beforeF # TypeError: afterF() missing 1 required positional argument: 'self' # 主要是因為 instance method 是 class function 與 instance 的結合 # 調用一個方法的時候,隱含 method 所處的 instance 會被當作 function 傳入的第一個參數 c.f()
Function & Method 詳解
- Function 即是在 class 中的函式
- Method 即是在 instance 中的方法,是 function 與 instance 的結合
調用時,instance 會被當作第一個參數傳遞過去
instancemethod
class C: def f(self): print('f') print(C.f) # <function C.f at 0x0000000002FC7840> # 因未被綁定,所以需要提供 instance,才正常執行 C.f(C()) c = C() print(c) print(c.f) # <__main__.C object at 0x0000000002FCDB38> # <bound method C.f of <__main__.C object at 0x0000000002FCDB38>> # 已被綁定,所以會自行將 method 的 instance 當作第一個參數傳入 c.f()
classmethod
class C: @classmethod def f(cls): print('f') print(C.f) # <bound method C.f of <class '__main__.C'>> # 被綁定在 class C 上,所以會自行將 class C 當作第一個參數傳入 # 無需傳入參數 C.f() c = C() print(c) print(c.f) # <__main__.C object at 0x00000000029ADB70> # <bound method C.f of <class '__main__.C'>> # 被綁定在 class C 上,所以會自行將 class C 當作第一個參數傳入 # 與原本的 instance 已無關 c.f()
staticmethod
class C: @staticmethod def f(): print('f') print(C.f) # <function C.f at 0x0000000002FE7840> # 普通的 function # 無需傳入參數 C.f() c = C() print(c) print(c.f) # <__main__.C object at 0x0000000002FEDB70> # <function C.f at 0x0000000002FE7840> # 普通的 function # 與原本的 instance & class 已無關 c.f()
繼承
支援多重繼承形式class ParentA: __private = 'private' def pF(self): print('parentA') def pFA(self): print('parentA part 2') class ParentB: public = 'public' def pF(self): print('parentB') def pFB(self): print('parentB part 2') class Child(ParentB, ParentA): def cF(self): print('child') # override def pFA(self): # 呼叫 ParentA 的 PFA super().pFA() # 呼叫 ParentB 的 PFB # 不建議使用此方法 ParentB.pFB(self) print('child part 2') child = Child() # 顯示可用變數 & method 含 private 變數 print(dir(child)) child.cF() # child # 同樣的名字時,規則是先深,而後由左至右(depth-first, left-to-right) child.pF() # parentB child.pFA() # parentA part 2 # parentB part 2 # child part 2 print(child.public) # public # AttributeError: 'Child' object has no attribute '__private' # 但有 _ParentA__private,可強制得到並賦值 print(child._ParentA__private) print(child.__private)
小技巧
@property
自定屬性
自定屬性
class Ball: def __init__(self, radius): if radius <= 0: raise ValueError('必須是正數') self.__radius = radius @property def radius(self): return self.__radius @radius.setter def radius(self, radius): if radius <= 0: print('必須是正數') else: self.__radius = radius @radius.deleter def radius(self): del self.__radius ball = Ball(10) print(ball.radius) # 10 ball.radius = -15 # 必須是正數 print(ball.radius) # 10 ball.radius = 15 print(ball.radius) # 15 del ball.radius print(ball.radius) # AttributeError: 'Ball' object has no attribute '_Ball__radius'
__call__
設定直接呼叫的方法
設定直接呼叫的方法
class Ball: def __init__(self, radius): if radius <= 0: raise ValueError('必須是正數') self.radius = radius def __call__(self, radius): if radius <= 0: print('必須是正數') else: self.radius = radius ball = Ball(10) print(ball.radius) # 10 ball(15) print(ball.radius) # 15
__getitem__
__setitem__
__delitem__
__len__
自定 list, dic 等類似 object,numpy 便是以此建立 array 的
而 x[i] 等同於呼叫 type(x).__getitem__(x, i)
__setitem__
__delitem__
__len__
自定 list, dic 等類似 object,numpy 便是以此建立 array 的
而 x[i] 等同於呼叫 type(x).__getitem__(x, i)
dict 範例
class DictDemo: def __init__(self, key, value): self.dict = {} self.dict[key] = value def __getitem__(self, key): return self.dict.get(key) def __setitem__(self, key, value): self.dict[key] = value def __delitem__(self, key): del self.dict[key] def __len__(self): return len(self.dict) dictDemo = DictDemo('k0','v0') print(dictDemo['k0']) # v0 dictDemo['k1'] = 'v1' print(dictDemo['k1']) # v1 print(len(dictDemo)) # 2 del dictDemo['k1'] print(dictDemo['k1']) # None print(len(dictDemo)) # 1
二維 list 範例
class ListDemo: def __init__(self, data): self.list = data def __getitem__(self, index): # index 會是 tuple return self.list[index[0]][index[1]] def __setitem__(self, index, value): self.list[index[0]][index[1]] = value def __delitem__(self, index): del self.list[index[0]][index[1]] def __len__(self): return len(self.list) listDemo = ListDemo([[1,2], [3,4]]) print(listDemo[1,0]) # 3 listDemo[1,1] = 'abc' print(listDemo[1,1]) # abc print(len(listDemo)) # 2 del listDemo[1,1] print(listDemo[1,1]) # IndexError: list index out of range
參考
Python 教學文件property() 函式 Special method names
留言
張貼留言