Python面向对象

时游大约 4 分钟

面向对象

类提供了把数据和功能绑定在一起的方法,类的实例化会创建一个新的对象,每个对象都有自己的属性和方法。

名称与对象

对象之间相互独立,多个名称(甚至是多个作用域内的多个名称)可以绑定到同一对象。

# 赋值不会拷贝对象,只是让多个名称指向同一个对象
a = [1, 2, 3]
b = a  # b和a绑定的是同一个列表
b.append(4)
print(a)        # [1, 2, 3, 4],通过b修改,a也"变"了
print(a is b)   # True,is判断两个名称是否指向同一个对象

# 想要独立的副本,需创建新对象(切片是浅拷贝)
c = a[:]
c.append(5)
print(a)        # [1, 2, 3, 4],不受c影响
print(c)        # [1, 2, 3, 4, 5]

Python 作用域和命名空间

命名空间是一个从名称到对象的映射。在 Python 中,每个模块、类或函数都有自己的命名空间。命名空间的作用是避免名称冲突,使代码更加清晰和可维护。

类的定义

class MyClass:
    """一个简单的类示例"""
    i = 12345

    def f(self):
        return 'hello world'

类属性与方法

# 类:类提供了把数据和功能绑定在一起的方法

# 作用域
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam  # nonlocal:声明为最近外层的局部变量
        spam = "nonlocal spam"

    def do_global():
        global spam  # global:声明为全局变量
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)  # test spam
    do_nonlocal()
    print("After nonlocal assignment:", spam)  # nonlocal spam
    do_global()
    print("After global assignment:", spam)  # nonlocal spam


scope_test()
print("In global scope:", spam)  # global spam


# 类
class Animal:
    # 颜色:公共属性,会被所有子对象共用
    colors = []

    # 赋初始值,类似于js中的constructor
    def __init__(self, name):
        self.name = name
        self.skills = []  # 每个实例独有属性

    def set_name(self, name):
        self.name = name

    def get_name(self):
        return self.name

    # 添加颜色
    def set_color(self, color):
        self.colors.append(color)

    # 添加能力
    def set_skill(self, skill):
        self.skills.append(skill)

    # 间隔符号
    def add_logs(self):
        print("-------------")

    # 调用自身函数
    def classTest(self):
        self.add_logs()


# 创建dog实例
dog = Animal("Dog")
dog.set_name("旺财")
dog.set_skill("汪汪汪")
print(dog.get_name())  # 旺财
print(dog.skills)  # ['汪汪汪']

# 创建cat实例
cat = Animal("Cat")
cat.set_name("Tom")
cat.set_color("orange")
print(dog.colors)  # ['orange']
print(cat.colors)  # ['orange']
cat.set_skill("喵喵喵")
print(cat.skills)  # ['喵喵喵']
cat.classTest()

类继承

# 继承
class Device:
    def __init__(self, device_name, device_code):
        self.device_name = device_name
        self.device_code = device_code

    def get_device_info(self):
        return {
            "device_name": self.device_name,
            "device_code": self.device_code
        }


class EMS(Device):  # 继承Device类
    def __init__(self, device_name, device_code):
        super().__init__(device_name, device_code)

    def set_ems_power(self, power):
        self.ems_power = power


ems = EMS('EMS', 'EMS-0001')
device_info = ems.get_device_info()
print(device_info)

多继承:class Son(Father1, Father2),按括号中的顺序查找属性和方法(MRO 顺序);子类重写父类方法后,仍可通过 super() 调用父类的原实现。

类方法与静态方法

class DateTools:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    # 实例方法:第一个参数是实例self,可以访问实例属性
    def show(self):
        print(f"{self.year}-{self.month}-{self.day}")

    # 类方法:第一个参数是类cls,常用作替代构造函数
    @classmethod
    def from_string(cls, date_str):
        year, month, day = map(int, date_str.split('-'))
        return cls(year, month, day)  # cls()等价于DateTools()

    # 静态方法:既不接收实例也不接收类,就是一个放在类命名空间下的普通函数
    @staticmethod
    def is_valid(date_str):
        parts = date_str.split('-')
        return len(parts) == 3 and all(p.isdigit() for p in parts)


d = DateTools.from_string('2026-09-16')  # 类方法创建实例
d.show()  # 2026-9-16
print(DateTools.is_valid('2026-09-16'))  # True

常用魔术方法

魔术方法(双下划线方法)由 Python 在特定时机自动调用,用于自定义对象的行为。

class Book:
    def __init__(self, title, price):
        self.title = title
        self.price = price

    # print(对象) 时的显示内容
    def __str__(self):
        return f"《{self.title}》¥{self.price}"

    # 面向开发者的调试显示,str不存在时的兜底
    def __repr__(self):
        return f"Book(title={self.title!r}, price={self.price})"

    # 两个对象使用 == 比较时调用
    def __eq__(self, other):
        return isinstance(other, Book) and self.title == other.title

    # len(对象) 时调用
    def __len__(self):
        return len(self.title)


book1 = Book("Python从入门到实践", 89)
book2 = Book("Python从入门到实践", 65)
print(book1)          # 《Python从入门到实践》¥89
print(repr(book2))    # Book(title='Python从入门到实践', price=65)
print(book1 == book2)  # True,只比较了书名
print(len(book1))     # 12

私有变量

python中不存在私有属性,但是可以通过约定来定义。

# 私有属性:仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是非公有部分
class Bird:

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._colors = []  # 遵守约定,_colors为私有属性,同理,函数也一致

    def set_color(self, color):
        self._colors.append(color)


bird1 = Bird("Bird1", "Bird-0001")
bird1.set_color("blue")
print(bird1._colors)

bord2 = Bird("Bord2", "Bord-0002")
bord2.set_color("red")
print(bord2._colors)

双下划线开头的属性(例如 __name)会触发「名称改写」(name mangling),实际存储为 _类名__name,子类不易直接访问,但依然不是真正的私有。

property:把方法伪装成属性

@property 让方法像属性一样访问,可以在设置值时做校验,调用方无感知。

class Account:
    def __init__(self):
        self._balance = 0

    @property
    def balance(self):
        return self._balance

    # 设置balance时自动校验
    @balance.setter
    def balance(self, value):
        if value < 0:
            raise ValueError("余额不能为负数")
        self._balance = value


account = Account()
account.balance = 100  # 像属性一样赋值,实际走setter校验
print(account.balance)  # 100,像属性一样读取
上次编辑于:
贡献者: 15327360835
Loading...