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