Skip to content

类和对象

python
# 与其他支持面向对象的编程语言一样,
# 定义类使用 class 关键字
class Animal:
    # 普通属性(类似其他编程语言的 public 修饰符)
    name = None

    # 私有属性(以__开头 类似其他编程语言的 private)
    # 与其他面向对象不同的是: 没有 protected 修饰符
    __age = 0

    def __init__(self, name, kind):
        # 构造方法
        self.name = name
        self.kind = kind

    def __str__(self):
        # 魔术方法 类似 js 的 toString,必须返回一个字符串
        # 当对象被当成字符串使用时会自动调用
        return f"{self.name} is a {self.kind}"

    def eat(self, food):
        # 普通方法(实例方法)
        print(f"i am {self.name}, i like to eat {food}")

    @property
    def age(self):
        # 访问器: 定义 getter
        return self.__age

    @age.setter
    def age(self, age):
        # 修改器: 定义 setter
        # 你的 @property 修饰的属性名(age),  那么修改器的
        # 名字就必须是 @age.setter
        if age > 150:
            print("设置失败, 你设置的年龄太大了")
        else:
            self.__age = age

    def show_age(self):
        # 利用普通方法来查看, 访问器设置器是否设置成功
        # __age: 是在类的内部直接访问属性
        # age: 是通过访问器来访问属性
        print(f"查看年龄:__age = {self.__age}, age = {self.age}")

    @classmethod
    def is_animal(cls, obj):
        # 类方法: 有 cls 参数但是没有 self 参数
        # 可以访问到 Animal 这个类, 但是无法访问到实例
        return isinstance(obj, cls)

    @staticmethod
    def breath():
        # 静态方法: 没有 cls 参数也没有 self 参数
        # 虽然是通过类来调用这个方法,
        # 但是他和类并没有关系, 因为他无法访问
        # 类中的任何属性和方法(也就是无法访问 self)
        print("动物都需要呼吸")

# 实例化
tom = Animal("tom", "cat") # 给构造方法传值

# 魔术方法 __str__
print(f"toString: {tom}")

# 访问器(getter) 设置器(setter)
print(f"tom is {tom.age} years old")
tom.age = 22
tom.show_age()

# 普通方法
tom.eat("fish")

# 类方法
print("tom 是 Animal 的实例吗?", Animal.is_animal(tom))
print("123 是 Animal 的实例吗?", Animal.is_animal(123))

# 静态方法
# 注: 静态方法和类方法都是通过类名来调用的
Animal.breath()

装饰器

在 python 中 可以使用装饰器来定义类中不同类型的属性和方法

魔术方法

在 python 中有许多魔术方法来定义对象的行为, 比如对象被当做字符串时会自动调用 __str__, 有的资料也将这些行为称之为 运算符重载

  • __str__
  • __add__
  • __sub__
  • __or__
  • __getitem__
  • __setitem__
  • __len__
  • __repr__
  • __gt__
  • __lt__
  • __le__
  • __ge__
  • __eq__
  • __ne__
  • __contains__

继承

  • 单继承: 子类只继承一个基类
  • 多继承: 子类继承多个基类
py
# 动物类
class Animal:
    def __init__(self, name):
        self.name = name

    def eat(self):
        # 父类方法
        print("动物都需要吃东西")

# 猫类
class Cat(Animal):
    def catchMouse(self):
        # 添加子类自己的方法
        print("猫可以抓老鼠")

    def eat(self):
        # 重载父类的方法, 先调用父类的方法
        super().eat();
        print("猫吃鱼")

# 鱼类
class Fish(Animal):
    def eat(self):
        # 重载父类的方法, 不调用父类方法
        print("鱼吃草")

    def swim(self):
        # 添加子类的方法
        print("鱼会游泳")


tom = Cat("tom")
tom.eat()
tom.catchMouse()

print("="*20)

jerry = Fish("jerry")
jerry.eat()
jerry.swim()
py
class Phone:
    def call(self):
        print("手机可以打电话")

class Camera:
    def take_photo(self):
        print("照相机可以照相")

class RemoteController:
    def control(self):
        print("遥控器可以控制空调")

# 多继承
class XiaoMiPhone(Phone, Camera, RemoteController):
    def ai_assistant(self):
        print("小爱同学 AI 助手")

    def control(self):
        # 重载父类方法
        print("手机可以控制空调")

xiaomi8 = XiaoMiPhone()

xiaomi8.call()
xiaomi8.take_photo()
xiaomi8.control()
xiaomi8.ai_assistant()

类型注解与多态

什么是类型注解? 为什么使用类型注解?

就如同 js 和 ts 的关系, 拥有类型注解可以获得更好的编码体验, 减少出错概率

python
class Animal:
    def move(self):
        print("动物可以移动")

class Cat(Animal):
    def move(self):
        print("猫在地上跑")

class Fish(Animal):
    def move(self):
        print("鱼在水里游")

# 多态: 猫在动,鱼在动 都可以理解为 动物在动
def run(animal: Animal):
    animal.move()

animal = Animal()
cat = Cat()
fish = Fish()

run(animal)
run(cat)
run(fish)

使用枚举类

推荐阅读

使用元类

推荐阅读

Released under the MIT License.