User: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__)

类型注释[编辑 | 编辑源代码]

在类中定义函数时,也可以使用类型注释。