Skip to main content

类和对象 Class & Object

在 Python 中,面向对象编程(OOP)是一种程序设计范式,它使用“对象”和“类”的概念来组织代码。

基本概念

下面是类和对象的基本概念:

类 Class

类是一种用于创建对象的蓝图或模板。它定义了一组属性(数据)和方法(操作这些数据的函数)。可以将类视为创建特定类型对象的说明书。

class Dog:
def __init__(self, name, age):
self.name = name
self.age = age

def bark(self):
print("woof!")

特点

  • 属性 (Attributes): 类中定义的变量。它描述了对象的状态或特征。
  • 方法 (Methods): 类中定义的函数。它描述了对象可以执行的操作。

对象 Object

对象是根据类定义创建的实体。每个对象都拥有类中定义的属性和方法。对象是类的实例化。

roger = Dog("Roger", 8)
type(roger) # <class '__main__.Dog'>

roger.name # "Roger"
roger.age # 8
roger.bark() # "woof!"

特点

  • 实例化: 创建一个类的实例(对象)。
  • 状态: 对象通过其属性维护状态。
  • 行为: 对象通过其方法展示行为。

继承与多态 Inherit & Polymorphism

通过结合使用继承和多态,你可以创建灵活且易于扩展的代码结构,其中子类只需定义或修改特定的行为,而共通的行为则可以在父类中定义。这种方式使得添加新的子类或修改现有类变得更加容易,且对现有代码的影响更小。

继承 Inherit

继承是一种机制,允许我们定义一个类(子类)来继承另一个类(父类)的属性和方法。子类除了继承父类的功能外,还可以添加新的功能或重写某些方法。

# 父类
class Animal:
def speak(self):
pass

# 子类
class Dog(Animal):
def speak(self):
return "Woof!"

class Cat(Animal):
def speak(self):
return "Meow!"

在这个示例中,Animal 是一个父类,DogCat 是继承自 Animal 的子类。每个子类有自己的 speak 方法实现。

特点

  • 代码重用: 子类可以使用父类的代码,减少重复代码。
  • 扩展性: 可以在父类的基础上扩展新的功能。
  • 层次结构: 通过继承创建一种自然的层次结构。

多态 Polymorphism

多态性是指不同类的对象可以对同一消息做出不同的响应。换句话说,多态允许我们用一个共同的接口来操作不同的基础数据类型或类。

def animal_speak(animal):
print(animal.speak())

my_dog = Dog()
my_cat = Cat()

animal_speak(my_dog) # 输出 "Woof!"
animal_speak(my_cat) # 输出 "Meow!"

在这个示例中,animal_speak 函数接受一个 Animal 类型的对象,并调用其 speak 方法。由于 DogCat 类重写了 speak 方法,所以它们对 speak 的响应是不同的。这就是多态性的体现。

特点

多态性的特点:

  • 接口统一: 不同对象可以通过同一接口被处理。
  • 灵活性: 代码可以对新增的子类类型保持透明。
  • 扩展性: 增加新的子类不会影响到既有的类结构。

封装和私有成员

通过使用封装和私有成员,可以确保对象的状态只能通过定义好的接口改变,这有助于维护数据的完整性和减少 bug。同时,这也使得类的实现和使用分离,有利于代码的维护和扩展。

封装 Encapsulation

封装是一种限制对类成员的直接访问的方式,同时提供对这些成员的控制方法。这有助于防止外部代码意外修改内部状态,保持对象的完整性和一致性。

银行账户类示例: 假设我们要创建一个类来表示银行账户,我们将封装账户的余额,只允许通过特定的方法(如存款、取款和查询余额)来操作它。
class BankAccount:
def __init__(self, initial_balance=0):
self.__balance = initial_balance # 私有属性,代表账户余额

def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"存入{amount}元。")
else:
print("存入金额必须大于0。")

def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"取出{amount}元。")
else:
print("取款金额必须大于0且不能超过账户余额。")

def get_balance(self):
return self.__balance

# 使用示例
account = BankAccount(1000) # 初始余额1000元
account.deposit(500) # 存入500元
account.withdraw(200) # 取出200元
print(f"当前账户余额:{account.get_balance()}元。")

这个类的设计体现了封装原则:通过公共方法控制对私有属性的访问,保证了账户余额的正确性和安全性。

特点

  • 数据隐藏: 将类的内部状态(数据)隐藏起来,只允许通过定义好的接口访问。
  • 接口提供: 提供方法(接口)来操作内部数据,而不是直接暴露数据。
  • 增强安全性: 防止外部代码意外改变对象的内部状态。

私有成员 Private Members

在 Python 中,私有成员通常通过命名约定实现(名称前加双下划线 __)。这样命名的属性或方法不会被外部直接访问,只能在类内部使用。

class Car:
def __init__(self, color):
self.__color = color # 私有属性

def get_color(self):
return self.__color # 公共方法访问私有属性

def __private_method(self):
print("This is a private method")

my_car = Car("red")
print(my_car.get_color()) # 正确: 输出 "red"
# print(my_car.__color) # 错误: 抛出 AttributeError
# my_car.__private_method()# 错误: 抛出 AttributeError

在这个示例中,__color 和 __private_method 是私有的,只能在 Car 类的内部访问。get_color 是一个公共方法,它提供了访问私有属性的安全方式。

特点

  • 名称改写: Python 通过名称改写(name mangling)来实现私有。例如,__private_attr 会被改写成 _ClassName__private_attr。
  • 类内访问: 私有成员只能在类的内部访问,子类也无法访问父类的私有成员。
  • 避免意外覆盖: 使用私有成员可以避免子类意外覆盖基类的方法或属性。

类方法、静态方法和实例方法

在 Python 中的面向对象编程(OOP)里,有三种主要的方法类型:实例方法、静态方法和类方法。它们的区别主要在于它们如何访问类的属性和其他方法,以及它们是如何被调用的。

实例方法 Instance Methods

  • 定义: 实例方法是类的普通方法,它们的第一个参数通常是 self,它指向类的实例。
  • 访问: 实例方法可以访问类中的属性(字段)和其他方法。
  • 用途: 通常用于需要访问或修改实例的属性的操作。
class MyClass:
def __init__(self, value):
self.value = value

def instance_method(self):
return f'实例方法被调用, value = {self.value}'

静态方法 Static Methods

  • 定义: 通过装饰器 @staticmethod 定义,它们不接受 self 或 cls 参数。
  • 访问: 静态方法不能访问类的属性或其他方法,它们基本上是类内部的普通函数。
  • 用途: 用于执行不依赖于类属性的功能。
class MyClass:
@staticmethod
def static_method():
return '静态方法被调用'

类方法 Class Methods

  • 定义: 通过装饰器 @classmethod 定义,它们的第一个参数是 cls,它指向类本身,而不是类的实例。
  • 访问: 类方法可以访问类属性(字段)和其他方法。
  • 用途: 通常用于那些需要访问类属性或者需要创建类实例的方法。

类方法在 Python 中是一种特殊的方法,它在定义时使用 @classmethod 装饰器。这种方法的一个显著特点是,它的第一个参数是 cls,它代表着类本身,而不是类的一个实例。这意味着你可以在没有创建类实例的情况下调用这个方法。

class MyClass:
value = 5

@classmethod
def class_method(cls):
return f'类方法被调用, value = {cls.value}'

使用场景

1. 工厂方法(Factory Methods)

类方法常被用作工厂方法。工厂方法是一种根据不同参数创建类实例的方法。这种方法特别有用,因为它可以返回类的对象,同时提供不同的初始化方式。

class Person:
def __init__(self, name):
self.name = name

@classmethod
def from_birth_year(cls, name, birth_year):
age = 2021 - birth_year
return cls(f"{name}, 年龄 {age}")

# 使用常规构造器
person1 = Person("Alice")

# 使用类方法构造器
person2 = Person.from_birth_year("Bob", 1990)

print(person2.name) # 输出: Bob, 年龄 31
2. 访问和修改类属性

类方法还可以用于访问或修改一个类的属性。由于类方法作用于整个类,而不仅仅是类的一个实例,所以它们常用于操作那些在所有实例之间共享的数据。

class MyClass:
counter = 0

@classmethod
def increment_counter(cls):
cls.counter += 1

@classmethod
def get_counter(cls):
return cls.counter

MyClass.increment_counter()
print(MyClass.get_counter()) # 输出: 1
3. 提供替代构造器

有时,你可能需要提供多种方式来构造类的实例。类方法使得你可以提供多个构造器。

class Data:
def __init__(self, data):
self.data = data

@classmethod
def from_string(cls, data_str):
data = data_str.split('-')
return cls(data)

@classmethod
def from_list(cls, data_list):
return cls(data_list)

# 使用不同的构造方法
data1 = Data.from_string("1-2-3")
data2 = Data.from_list([1, 2, 3])

总结

类方法的灵活性在于它们可以与类本身互动,而不是类的某个特定实例。它们提供了一种方式来封装针对整个类的功能,而不仅仅是对其单个实例的操作。这使得类方法成为实现如工厂方法模式、构造器重载等设计模式的理想选择。

使用和调用

  • 实例方法需要通过类的实例来调用。
  • 静态方法和类方法可以通过类名直接调用,也可以通过类的实例调用。

特殊方法和运算符重载

特殊方法

这里有一些常见的特殊方法示例

  • __init__(self, ...): 构造函数,在创建新实例时调用。
  • __str__(self): 当使用 str() 被调用或打印一个对象时的行为。
  • __repr__(self): 官方字符串表示,方便开发者理解对象。通常在 Python 的交互式解释器中被调用。
  • __len__(self): 当使用 len() 方法时调用。
  • __getitem__(self, key): 使用索引操作符(如 obj[key])时调用。
  • __setitem__(self, key, value): 对索引操作符的赋值(如 obj[key] = value)。
  • __iter__(self): 迭代对象(如在 for 循环中)时调用。
  • __next__(self): 迭代器的下一个元素。

运算符重载 Operator Overloading

运算符重载允许为运算符定义自定义的行为。以下是一些常用的运算符重载方法:

  • __add__() respond to the + operator
  • __sub__() respond to the - operator
  • __mul__() respond to the * operator
  • __truediv__() respond to the / operator
  • __floordiv__() respond to the // operator
  • __mod__() respond to the % operator
  • __pow__() respond to the ** operator
  • __rshift__() respond to the >> operator
  • __lshift__() respond to the << operator
  • __and__() respond to the & operator
  • __or__() respond to the | operator
  • __xor__() respond to the ^ operator
class Dog:
# the Dog class
def __init__(self, name, age):
self.name = name
self.age = age
def __gt__(self, other):
return True if self.age > other.age else False

roger = Dog("Roger", 8)
syd = Dog("Syd", 7)

print(roger > syd) # True