Python-面向对象入门

来看一个简单的定义类的案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Dog:
# 类属性
species = '犬科动物'

# 方法:返回种类
def whatspecies(self):
return species

# 构造函数:创建小狗时必须提供名字和年龄
def __init__(self, name, age):
self.name = name # 小狗的名字(属性)
self.age = age # 小狗的年龄(属性)

# 方法:小狗坐下
def sit(self):
print(f"{self.name} 乖乖坐下了!")

可以理解为,因为许多对象都有共同点,可以根据共同点对它们分类,所以有了“类”。不过,实践中往往是定义好类后,才以定义好的类为标准,“创造”出许多同一类的对象。这些被“创造”出来的对象,称为实例。用定义好的类“创造”对象的过程,称为实例化。

属性与方法,实例化

在类中可以定义属性和方法。如上面的代码段在类 Dog 中定义了属性 species 和方法 whatspecies__init__sit 等。

要调用某个类的属性和方法,可以直接通过 类名.属性/方法 这样的方式,也可以通过实例化。

类名.属性/方法

1
2
print(Dog().species) # 共输出2次“犬科动物”
print(Dog().whatspecies()) # 即使定义时省略了括号,Dog()在此处也不能省略括号,否则不会被当成类名

实例化
实例化是指用定义好的类“创造”对象,让不同的对象(实例)来自同一类,共享类中的属性与方法。

1
2
3
4
5
6
dog1 = Dog()
dog2 = Dog()
print(dog1.species)
print(dog1.whatspecies())
print(dog2.species)
print(dog2.whatspecies()) # 共输出4次“犬科动物”

另外,属性的定义与变量的定义一致,不过要调用时需要类名.属性或实例化的方式;但方法与函数的定义有一点不同:必须有一个额外的第一个参数名称, 按照惯例它的名称是 self (后面会细讲)。

__init__ 方法

上面的实例化是直接进行实例化,也可以通过 __init__() 方法实例化类。如上面案例中的:

1
2
3
4
5
6
7
8
9
class Dog:
# 构造函数:创建小狗时必须提供名字和年龄
def __init__(self, name, age):
self.name = name # 小狗的名字(属性)
self.age = age # 小狗的年龄(属性)

# 方法:小狗坐下
def sit(self):
print(f"{self.name} 乖乖坐下了!")

功能:在创建一个类的实例(对象)时,__init__ 方法会被自动调用,用于为对象设置初始属性。

对比一下有无 __init__ 方法的两种情况:

1
dog1 = Dog("大黄", 10)  # 创建对象时直接传入属性值
1
2
3
dog1 = Dog()
dog1.name = "大黄" # 手动添加属性
dog1.age = 10

上面的 Dog("大黄", 10) 分别传参给 name age 两个属性,再在 __init__ 方法中成为实例 dog1 的实例属性( self 表示实例本身)。

关于实例属性与类属性:类属性可被所有属于该类的对象调用(类似 dog1.species ,所有该类实例的 species 属性都是“犬科动物”),实例属性则只能通过该实例调用(dog1.name)。

关于 self
self 代表类的实例,而非类本身。类的方法相比普通函数只有一个特别的区别:它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self

1
2
3
4
5
6
7
class Test:
def prt(self):
print(self)
print(self.__class__)

t = Test()
t.prt()

以上实例执行结果为:

1
2
<__main__.Test instance at 0x100771878>
__main__.Test

从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
由于 self 并非关键字,所以可以将 self 替换成其他的关键字,也不会出现问题。
在 Python中,self 是一个惯用的名称,用于表示类的实例(对象)自身。它是一个指向实例的引用,使得类的方法能够访问和操作实例的属性。
当你定义一个类,并在类中定义方法时,第一个参数通常被命名为 self,尽管你可以使用其他名称,但强烈建议使用 self,以保持代码的一致性和可读性

核心概念解析

  1. 封装:把数据(属性)和操作(方法)打包在一起

    1
    2
    my_dog.age += 1  # 直接修改属性
    my_dog.sit() # 调用方法
  2. 继承:子类继承父类的特性(比如导盲犬是特殊的小狗)

    1
    2
    3
    4
    5
    6
    7
    class GuideDog(Dog):  # 继承自Dog类
    def guide(self):
    print(f"{self.name} 正在引导主人!")

    guide_dog = GuideDog("大黄", 4)
    guide_dog.sit() # 继承父类方法
    guide_dog.guide() # 子类新增方法
  3. 多态:不同对象对同一方法有不同的响应(比如猫狗的叫法不同)