Skip to content

类型与实例

什么是面相对象?

在阅读下面的教程前,你需要首先了解什么是,以及为什么我们需要面向对象
如果没有的话,可以看看这里o.O

Python使用class关键字来定义类型。类型是Python中很常见的东西,这也符合Python万物皆对象的设计理念。

python
class Cat:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    def miaow(self):
        print(f"{self.name}: Miaow Miaow!!")

cat = Cat("XiaoFan", 1)
cat.miaow()

这一段代码定义了一个Cat类型,实例化了一个名为catCat类型对象,并且让cat喵了两声。上面的代码中使用了类型注释和f-string,如果你对他们没有印象了,回头去看前面的教程哦。

self

self指代的是「对象」本身,可能类似于其他语言中的this或类似关键字。下面用一些演示来说明self的特性。

python
class Cat:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    def miaow(self):
        print(f"{self.name}: Miaow Miaow!!")

tom = Cat("Tom", 3)
fan = Cat("Fan", 2)
tom.miaow()
fan.miaow()

上面的对Cat类的定义中,self.nameself.age定义了Cat的属性,这些属性是跟随由Cat实例化得到的对象走的。

输出如下:

text
Tom: Miaow Miaow!!
Fan: Miaow Miaow!!

与之相对的,还有一种东西与self相似,但是是跟随Cat类型本身走的:

python
class Cat:
    count = 0
    def __init__(self, name: str, age: int):
        Cat.count += 1
        self.name = name
        self.age = age
    def miaow(self):
        print(f"{self.name}: Miaow Miaow!!")

tom = Cat("Tom", 3)
print(Cat.count)  
fan = Cat("Fan", 2)
print(Cat.count)  
tom.miaow()
fan.miaow()

输出如下:

text
1
2
Tom: Miaow Miaow!!
Fan: Miaow Miaow!!

你应该可以看出他们之间的区别,使用self.xxx定义的属性在实例化之后跟随实例,这些属性是对象的属性;而诸如Cat.xxx这类属性是跟随类型Cat的,是类型的属性。比如,上面的Cat.count实际统计了代码中一共有多少只实例化的猫,这是猫这个类型的属性而非某一只猫的属性。

你知道咩

打印Cat.counttom.countfan.count的结果是一样的,这说明通过类的实例化对象访问类型的属性也是合法的,尽管由于语义上可能存在的误解,我们依然推荐通过第一种方式访问类型的属性。

方法

你可以通过self.xxx()的方式调用实例的方法,或通过Cat.xxx()调用类型的方法。这些方法需要在类型中定义,就像你先前定义函数时一样,唯需注意以下事项:

首个形参

正如我们给Cat定义的miaow()方法一样,实例方法的首个参数需要是self

准确地说,如果你希望代码中的每一只猫都能使用miaow()方法叫两声,那么你就至少需要传入一个参数。 这个必须传入的参数在语法上可以是任意名称,只是我们约定俗成地将其命名为self。函数需要接收的其他参数必须跟在其后,即 self必须是第一个形参

也如同我们刚才了解到的一样,这个self实际上是对象本身。你的IDE会为self渲染不同的颜色,正是因为其特殊性。

从函数传参的原理上理解的话,依然沿用猫猫的例子,如果你不小心调用了Cat.miaow(),没有传参,那么会收到报错:

python
TypeError: Cat.miaow() missing 1 required positional argument: 'self'

当我们从类型调用这种函数时,会收获缺少参数的错误;当我们从实例调用这种函数时,实例本身会被作为第一个参数,所以在我们调用tom.miaow()时,self形参接收到的是tom,从而在f-string中插入了tom.name的值。

换言之,以下两行写法是等价的:

python
tom.miaow()
Cat.miaow(tom)

不需传入self的静态方法

你可以使用staticmethod装饰器来让一个方法成为静态方法。

python
class Cat:
    count = 0
    def __init__(self, name: str, age: int):
        Cat.count += 1
        self.name = name
        self.age = age
    def miaow(self):
        print(f"{self.name}: Miaow Miaow!!")
    @staticmethod
    def printCount():  
        print(f"Total cats: {Cat.count}")  

tom = Cat("Tom", 3)
fan = Cat("Fan", 2)

Cat.printCount()  

静态方法从类型调用且无需传入self,这也意味着静态方法不能访问self.name等对象的属性,而只能访问Cat.count等类型的属性。上方的代码将在运行时打印2

装饰器将在后面介绍。

init() 函数

__init__()是Python中,类的初始化方法或构造函数。在猫猫的例子中,__init__()函数除self之外,还接收nameage两个形参,因此我们在实例化每一只猫的时候都需要传入两个参数。

__init__()同普通函数一样,签名中也支持类型注释与默认值。

贡献者

页面历史