Skip to content

class basics.py

文件信息

  • 📄 原文件:01_class_basics.py
  • 🔤 语言:python

Python 类基础 本文件介绍 Python 中类的定义、实例化、属性和方法。

Python 是一门面向对象的语言,类是创建对象的蓝图。

完整代码

python
def main01_class_definition():
    """
    ============================================================
                    1. 类的定义与实例化
    ============================================================
    """
    print("=" * 60)
    print("1. 类的定义与实例化")
    print("=" * 60)

    # 【最简单的类】
    class Empty:
        pass

    obj = Empty()
    print(f"空类实例: {obj}")

    # 【带属性的类】
    class Person:
        # 类属性(所有实例共享)
        species = "Homo sapiens"

        # 初始化方法(构造函数)
        def __init__(self, name, age):
            # 实例属性(每个实例独立)
            self.name = name
            self.age = age

        # 实例方法
        def introduce(self):
            return f"我是 {self.name},今年 {self.age} 岁"

    # 创建实例
    alice = Person("Alice", 25)
    bob = Person("Bob", 30)

    print(f"\nalice.name = {alice.name}")
    print(f"bob.age = {bob.age}")
    print(f"alice.introduce() = {alice.introduce()}")

    # 【类属性 vs 实例属性】
    print(f"\n--- 类属性 vs 实例属性 ---")
    print(f"Person.species = {Person.species}")
    print(f"alice.species = {alice.species}")

    # 修改类属性会影响所有实例
    Person.species = "Human"
    print(f"修改后 bob.species = {bob.species}")

    # 但给实例赋值会创建实例属性,遮蔽类属性
    alice.species = "Alien"
    print(f"alice.species = {alice.species}")  # Alien
    print(f"bob.species = {bob.species}")      # Human

    # 【动态添加属性】
    print(f"\n--- 动态添加属性 ---")
    alice.email = "alice@example.com"  # 动态添加
    print(f"alice.email = {alice.email}")
    # print(bob.email)  # AttributeError,bob 没有 email


def main02_methods():
    """
    ============================================================
                    2. 方法类型
    ============================================================
    """
    print("\n" + "=" * 60)
    print("2. 方法类型")
    print("=" * 60)

    class MyClass:
        class_var = "类变量"

        def __init__(self, value):
            self.instance_var = value

        # 【实例方法】第一个参数是 self
        def instance_method(self):
            return f"实例方法,访问实例变量: {self.instance_var}"

        # 【类方法】使用 @classmethod,第一个参数是 cls
        @classmethod
        def class_method(cls):
            return f"类方法,访问类变量: {cls.class_var}"

        # 【静态方法】使用 @staticmethod,不需要 self 或 cls
        @staticmethod
        def static_method(x, y):
            return f"静态方法,计算: {x} + {y} = {x + y}"

    obj = MyClass("实例值")

    print(f"实例方法: {obj.instance_method()}")
    print(f"类方法: MyClass.class_method() = {MyClass.class_method()}")
    print(f"类方法: obj.class_method() = {obj.class_method()}")  # 也可以通过实例调用
    print(f"静态方法: {MyClass.static_method(3, 5)}")

    # 【类方法的常见用途:工厂方法】
    print(f"\n--- 类方法作为工厂方法 ---")

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

        @classmethod
        def from_string(cls, date_string):
            """从字符串创建日期"""
            year, month, day = map(int, date_string.split('-'))
            return cls(year, month, day)

        @classmethod
        def today(cls):
            """创建今天的日期"""
            import datetime
            today = datetime.date.today()
            return cls(today.year, today.month, today.day)

        def __str__(self):
            return f"{self.year}-{self.month:02d}-{self.day:02d}"

    d1 = Date(2024, 1, 15)
    d2 = Date.from_string("2024-06-20")
    d3 = Date.today()

    print(f"直接创建: {d1}")
    print(f"从字符串: {d2}")
    print(f"今天: {d3}")


def main03_special_methods():
    """
    ============================================================
                3. 特殊方法(魔法方法)
    ============================================================
    特殊方法以双下划线开头和结尾,用于自定义类的行为
    """
    print("\n" + "=" * 60)
    print("3. 特殊方法(魔法方法)")
    print("=" * 60)

    class Vector:
        """二维向量类"""

        def __init__(self, x, y):
            self.x = x
            self.y = y

        # 【字符串表示】
        def __str__(self):
            """用户友好的字符串表示(print 时调用)"""
            return f"Vector({self.x}, {self.y})"

        def __repr__(self):
            """开发者友好的字符串表示(调试时使用)"""
            return f"Vector(x={self.x}, y={self.y})"

        # 【算术运算】
        def __add__(self, other):
            """加法: v1 + v2"""
            return Vector(self.x + other.x, self.y + other.y)

        def __sub__(self, other):
            """减法: v1 - v2"""
            return Vector(self.x - other.x, self.y - other.y)

        def __mul__(self, scalar):
            """标量乘法: v * n"""
            return Vector(self.x * scalar, self.y * scalar)

        def __rmul__(self, scalar):
            """反向乘法: n * v"""
            return self.__mul__(scalar)

        def __neg__(self):
            """取负: -v"""
            return Vector(-self.x, -self.y)

        # 【比较运算】
        def __eq__(self, other):
            """相等: v1 == v2"""
            return self.x == other.x and self.y == other.y

        def __lt__(self, other):
            """小于: v1 < v2(按长度比较)"""
            return self.length() < other.length()

        # 【其他】
        def __abs__(self):
            """绝对值/长度: abs(v)"""
            return self.length()

        def __bool__(self):
            """布尔值: bool(v)"""
            return self.x != 0 or self.y != 0

        def __len__(self):
            """长度: len(v)"""
            return 2  # 向量有两个分量

        def length(self):
            """计算向量长度"""
            return (self.x ** 2 + self.y ** 2) ** 0.5

    v1 = Vector(3, 4)
    v2 = Vector(1, 2)

    print(f"v1 = {v1}")
    print(f"v2 = {v2}")
    print(f"v1 + v2 = {v1 + v2}")
    print(f"v1 - v2 = {v1 - v2}")
    print(f"v1 * 2 = {v1 * 2}")
    print(f"3 * v2 = {3 * v2}")
    print(f"-v1 = {-v1}")
    print(f"v1 == Vector(3, 4): {v1 == Vector(3, 4)}")
    print(f"abs(v1) = {abs(v1)}")
    print(f"bool(Vector(0, 0)) = {bool(Vector(0, 0))}")

    # 【容器类特殊方法】
    print(f"\n--- 容器类特殊方法 ---")

    class MyList:
        """自定义列表类"""

        def __init__(self, items=None):
            self._items = list(items) if items else []

        def __len__(self):
            """len(obj)"""
            return len(self._items)

        def __getitem__(self, index):
            """obj[index]"""
            return self._items[index]

        def __setitem__(self, index, value):
            """obj[index] = value"""
            self._items[index] = value

        def __delitem__(self, index):
            """del obj[index]"""
            del self._items[index]

        def __contains__(self, item):
            """item in obj"""
            return item in self._items

        def __iter__(self):
            """for item in obj"""
            return iter(self._items)

        def __repr__(self):
            return f"MyList({self._items})"

    ml = MyList([1, 2, 3, 4, 5])
    print(f"MyList: {ml}")
    print(f"len(ml) = {len(ml)}")
    print(f"ml[2] = {ml[2]}")
    print(f"3 in ml: {3 in ml}")
    ml[0] = 10
    print(f"修改后: {ml}")


def main04_property():
    """
    ============================================================
                4. 属性访问控制
    ============================================================
    """
    print("\n" + "=" * 60)
    print("4. 属性访问控制")
    print("=" * 60)

    # 【使用 @property】
    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

        @radius.deleter
        def radius(self):
            """删除半径"""
            print("删除半径")
            del self._radius

        @property
        def diameter(self):
            """直径(只读属性)"""
            return self._radius * 2

        @property
        def area(self):
            """面积(只读属性)"""
            return 3.14159 * self._radius ** 2

    c = Circle(5)
    print(f"radius = {c.radius}")
    print(f"diameter = {c.diameter}")
    print(f"area = {c.area:.2f}")

    c.radius = 10
    print(f"新 radius = {c.radius}")
    print(f"新 area = {c.area:.2f}")

    try:
        c.radius = -5
    except ValueError as e:
        print(f"设置负半径: {e}")

    # 【__slots__】限制实例属性
    print(f"\n--- __slots__ ---")

    class Point:
        __slots__ = ['x', 'y']  # 只允许这些属性

        def __init__(self, x, y):
            self.x = x
            self.y = y

    p = Point(3, 4)
    print(f"Point: ({p.x}, {p.y})")
    # p.z = 5  # AttributeError: 'Point' object has no attribute 'z'

    # __slots__ 的好处:
    # 1. 节省内存(不创建 __dict__)
    # 2. 访问属性更快
    # 3. 防止意外添加属性

    # 【私有属性】双下划线触发名称改写
    print(f"\n--- 私有属性(名称改写)---")

    class Secret:
        def __init__(self):
            self.__private = "私有"
            self._protected = "受保护"

        def get_private(self):
            return self.__private

    s = Secret()
    print(f"_protected = {s._protected}")  # 可以访问(但不推荐)
    # print(s.__private)  # AttributeError
    print(f"get_private() = {s.get_private()}")
    print(f"名称改写后: _Secret__private = {s._Secret__private}")  # 实际上改名了


def main05_descriptors():
    """
    ============================================================
                    5. 描述符
    ============================================================
    描述符是实现了特定协议的类,用于控制属性访问
    """
    print("\n" + "=" * 60)
    print("5. 描述符")
    print("=" * 60)

    # 【数据描述符】实现 __get__ 和 __set__
    class TypedField:
        """类型检查描述符"""

        def __init__(self, name, expected_type):
            self.name = name
            self.expected_type = expected_type

        def __get__(self, obj, objtype=None):
            if obj is None:
                return self
            return obj.__dict__.get(self.name)

        def __set__(self, obj, value):
            if not isinstance(value, self.expected_type):
                raise TypeError(
                    f"{self.name} 必须是 {self.expected_type.__name__},"
                    f"收到 {type(value).__name__}"
                )
            obj.__dict__[self.name] = value

    class Person:
        name = TypedField('name', str)
        age = TypedField('age', int)

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

    p = Person("Alice", 25)
    print(f"Person: {p.name}, {p.age}")

    try:
        p.age = "二十五"
    except TypeError as e:
        print(f"类型错误: {e}")

    # 【范围检查描述符】
    class RangeField:
        """范围检查描述符"""

        def __init__(self, name, min_val, max_val):
            self.name = name
            self.min_val = min_val
            self.max_val = max_val

        def __get__(self, obj, objtype=None):
            if obj is None:
                return self
            return obj.__dict__.get(self.name)

        def __set__(self, obj, value):
            if not self.min_val <= value <= self.max_val:
                raise ValueError(
                    f"{self.name} 必须在 [{self.min_val}, {self.max_val}] 范围内"
                )
            obj.__dict__[self.name] = value

    class Student:
        score = RangeField('score', 0, 100)

        def __init__(self, name, score):
            self.name = name
            self.score = score

    print(f"\n范围检查描述符:")
    s = Student("Bob", 85)
    print(f"Student: {s.name}, 分数: {s.score}")

    try:
        s.score = 120
    except ValueError as e:
        print(f"范围错误: {e}")


def main06_callable_objects():
    """
    ============================================================
                    6. 可调用对象
    ============================================================
    """
    print("\n" + "=" * 60)
    print("6. 可调用对象")
    print("=" * 60)

    # 实现 __call__ 使对象可以像函数一样调用
    class Adder:
        """累加器"""

        def __init__(self, start=0):
            self.total = start

        def __call__(self, value):
            self.total += value
            return self.total

    adder = Adder(100)
    print(f"adder(10) = {adder(10)}")
    print(f"adder(20) = {adder(20)}")
    print(f"adder(30) = {adder(30)}")

    # 【带状态的函数】
    class Counter:
        """调用计数器"""

        def __init__(self, func):
            self.func = func
            self.count = 0

        def __call__(self, *args, **kwargs):
            self.count += 1
            return self.func(*args, **kwargs)

    @Counter
    def greet(name):
        return f"Hello, {name}!"

    print(f"\n{greet('Alice')}")
    print(f"{greet('Bob')}")
    print(f"调用次数: {greet.count}")

    # 【策略模式】
    print(f"\n--- 策略模式 ---")

    class Discount:
        """折扣策略基类"""

        def __call__(self, price):
            raise NotImplementedError

    class NoDiscount(Discount):
        def __call__(self, price):
            return price

    class PercentDiscount(Discount):
        def __init__(self, percent):
            self.percent = percent

        def __call__(self, price):
            return price * (1 - self.percent / 100)

    class FixedDiscount(Discount):
        def __init__(self, amount):
            self.amount = amount

        def __call__(self, price):
            return max(0, price - self.amount)

    # 使用
    discounts = [
        ("无折扣", NoDiscount()),
        ("8折", PercentDiscount(20)),
        ("减50", FixedDiscount(50)),
    ]

    price = 200
    print(f"原价: {price}")
    for name, discount in discounts:
        print(f"  {name}: {discount(price)}")


if __name__ == "__main__":
    main01_class_definition()
    main02_methods()
    main03_special_methods()
    main04_property()
    main05_descriptors()
    main06_callable_objects()

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布