# 特殊方法与封装

URL: https://caijiao.org/python/ch08/magic-encapsulation
Source: docs/python/ch08/magic-encapsulation.md
Description: 本章介绍 Python 中的特殊方法和封装概念，讲解如何通过特殊方法实现自定义行为以及如何保护对象的状态。

在 [Python](/python/) 中，特殊方法（也称为魔术方法）允许我们自定义对象的行为，比如对象的比较、表示和算术运算等。封装是面向对象编程中的一种机制，它通过限制对对象内部数据的访问来保护对象的状态。

## 特殊方法

特殊方法是以双下划线开始和结束的方法，用于实现类的特殊行为。常见的特殊方法有 `__init__`（构造函数）、`__str__`（字符串表示）和 `__add__`（加法运算）等。

### `__str__` 和 `__repr__`

`__str__` 用于定义对象的字符串表示，`__repr__` 用于定义对象的开发者友好的字符串表示。

```python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name}, {self.age}岁"

    def __repr__(self):
        return f"Person({self.name}, {self.age})"

p = Person("Alice", 30)
print(str(p))  # 输出：Alice, 30岁
print(repr(p))  # 输出：Person(Alice, 30)
```

### `__add__`

`__add__` 方法允许我们定义对象的加法行为。它通过重载 `+` 运算符来改变其行为。

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2  # 通过重载 __add__ 方法
print(p3.x, p3.y)  # 输出：4 6
```

## 封装

封装是指将对象的内部状态（属性）和行为（方法）封装在类中，外界只能通过公开的接口（方法）来访问和修改对象的状态。通过封装，可以控制对对象数据的访问，保证数据的完整性。

### 私有属性与方法

通过将属性或方法的名称前加双下划线（`__`），可以将其标记为私有的。私有属性和方法只能在类内部访问，外部无法直接访问。

```python
class Car:
    def __init__(self, make, model):
        self.__make = make  # 私有属性
        self.__model = model  # 私有属性

    def __display_info(self):
        print(f"Car: {self.__make} {self.__model}")  # 私有方法

    def show_info(self):
        self.__display_info()  # 通过公有方法访问私有方法

car = Car("Toyota", "Corolla")
car.show_info()  # 输出：Car: Toyota Corolla
# print(car.__make)  # 会报错：AttributeError
```

### 属性访问控制

Python 提供了 `@property` 装饰器来将方法转化为属性，并可以通过 `@<property_name>.setter` 装饰器来设置属性的修改方法。

```python
class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("半径不能为负")
        self._radius = value

c = Circle(10)
print(c.radius)  # 输出：10
c.radius = 5
print(c.radius)  # 输出：5
# c.radius = -1  # 会抛出异常：ValueError: 半径不能为负
```

## 总结

- 特殊方法允许我们自定义对象的行为，如对象的字符串表示、算术运算等；
- 封装通过将属性和方法封装在类内部，限制对对象数据的直接访问，增强数据安全性；
- 通过私有属性、私有方法以及 `@property` 装饰器，Python 提供了有效的封装机制。
