使用者:Xyy23330121/Python/類

來自維基學院


定義類[編輯 | 編輯原始碼]

使用 class 語句,我們可以定義一個類。

class ClassName: pass

這就定義了一個名為 ClassName 的類。與函數相似,「類」自身也是一個對象,支持一切一般對象的操作。

類的屬性[編輯 | 編輯原始碼]

類的屬性可以理解為是定義在類中的、特殊的變量。

定義了「類」之後,我們可以在class子句給類添加屬性。也可以在定義後再添加屬性,比如:

class MyClass:
    attr1 = 1
    attr2 = "Two"

print(MyClass.attr1)  #调用了 MyClass 的属性 attr1。输出:1
print(MyClass.attr2)  #调用了 MyClass 的属性 attr2。输出:Two
MyClass.attr3 = "Third"
print(MyClass.attr3)  #调用了 MyClass 的属性 attr3。输出:Third

如上述例子所述。我們可以通過 ClassName.AttrName 的方式調用類的屬性。其中 ClassName 指的是類的名稱,AttrName 指的是屬性的名稱

類似,我們可以在類中定義函數。類中的函數和其它函數在表現上毫無區別,只是在使用時需要在前面添加類的名稱罷了。

實例[編輯 | 編輯原始碼]

實例是類的一個重要組成部分。比如 1 是類型 int 的一個實例對象。我們創建的類型也可以有實例。

創建實例對象[編輯 | 編輯原始碼]

我們可以用 ClassName() 的方法創建實例。

class MyClass1:
    a = 0
    def Method1(self):
        print(self.a, "调用了方法")

a = MyClass1()
print(a.a)   #输出:0
a.Method1()  #输出:0 调用了方法

__init__方法[編輯 | 編輯原始碼]

如果在類中定義了一個特殊的方法 __init__ 我們就可以更靈活地創建實例。我們看以下示例:

class MyClass2:
    def __init__(self, arg):
        self.arg = arg

a = MyClass3("实例属性")
print(a.arg)  #输出:实例属性

在調用 MyClass2() 的時候,我們創建了一個實例,然後把傳入 MyClass2() 的參數傳入到實例的 __init__ 方法中。這個實例是 MyClass2 的實例,它在初始化時具有屬性 arg = "实例属性"

實例屬性與其作用域[編輯 | 編輯原始碼]

在類中定義的屬性或方法,在實例中也可以使用。我們看以下示例:

class attr:
    n = 0
    number = 0
    array = []
    def __init__(self,arg):
        number = 1
        array.append(arg)

a = attr("First")
b = attr("Second")
print(attr.n, attr.number, attr.array) #输出:0 0 ['First', 'Second']
print(a.n, a.number, a.array)          #输出:0 1 ['First', 'Second']
print(b.n, b.number, b.array)          #输出:0 1 ['First', 'Second']

可以看出,實例和函數類似。如果在實例中對可變對象的屬性作「直接賦值以外的更改操作」,則更改操作會影響到類的屬性。但對不可變對象的屬性,唯一的更改方式是賦值。此時,該屬性在實例作用域裡,而非類作用域裡。

實例的方法[編輯 | 編輯原始碼]

在類中定義的函數,在實例中也可以使用。此時稱該函數是一個「方法」。類中的函數在使用時和其它函數沒有區別,但是實例的方法不同。在調用實例的方法時,自動傳入的第一個參數的會是實例自身。比如:

class attr:
    n = 0
    number = 0
    array = []
    def __init__(self,arg):
        number = 1
        array.append(arg)
    def prt(s):
        print(s.n, s.number, s.array)

a = attr("First")
b = attr("Second")
attr.prt()   #输出:0 0 ['First', 'Second']
a.prt()      #输出:0 1 ['First', 'Second']
b.prt()      #输出:0 1 ['First', 'Second']

可以看出,它正確傳入了實例,並在可能的條件下使用了實例的屬性。而沒有使用類的屬性。

裝飾器[編輯 | 編輯原始碼]

我們在之前學習函數時,學習過裝飾器相關的知識。到了本章節,有兩個好用的裝飾器可以使用。

classmethod[編輯 | 編輯原始碼]

該裝飾器用於類方法。與一般的方法傳入的是實例本身不同,類方法自動傳入的第一個參數是實例所屬的「類」。我們可以從以下示例中看出這一點:

class C:
    isCls = True
    def __init__(self):
        self.isCls = False
    def f(s):
        print(s.isCls)
    @classmethod
    def g(s):
        print(s.isCls)

a = C()
a.f() #输出:False
a.g() #输出:True

如同在裝飾器中提到的一樣,以上類等同於:

class C:
    isCls = True
    def __init__(self): self.isCls = False
    def f(s): print(s.isCls)
    g = classmethod(lambda s: print(s.isCls))

staticmethod[編輯 | 編輯原始碼]

該裝飾器用於靜態方法。靜態方法不會受類或實例改動的影響,它和函數的表現完全一致。

class C:
    @staticmethod
    def f(arg1, arg2):
        print(arg1, arg2)

a = C()
a.f(0,1) #输出:0 1
C.f(0,1) #输出:0 1

可以看出,此時使用的方法「不會」自動傳入實例自身。這是因為調用裝飾器後,裝飾器返回的結果,會跳過自動傳入的第一個參數,從第二個參數開始處理。

同樣,以上的類等同於:

class C:
    f = staticmethod(lambda x,y: print(x,y))

類相關的注釋[編輯 | 編輯原始碼]

文檔字符串[編輯 | 編輯原始碼]

類似函數注釋。對於類,或實例的方法,我們也可以使用文檔字符串。

class ClassWithDoc:
    '''文档字符串'''
    def MethodWithDoc():
        '''文档字符串'''
        pass

print(ClassWithDoc.__doc__)
a = ClassWithDoc()
print(a.MethodWithDoc.__doc__)

類型注釋[編輯 | 編輯原始碼]

在類中定義函數時,也可以使用類型注釋。