- 取得連結
- 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
留言
張貼留言