目录

1.基本结构与__init__

2.继承与super()

3.@property装饰器

4.常用的魔法方法

5.@classmethod与@staticmethod

6.__slots__节省内存

7.私有属性

8.__call__让实例可调用

9.组合优于继承

1.基本结构与__init__

class Dog:
    # 类属性(所有实例共享)
    species = "Canis familiaris"

    def __init__(self, name, age):
        # 实例属性(每个实例独有)
        self.name = name
        self.age = age

    def bark(self):
        return f"{self.name} says woof!"

类属性 vs 实例属性——类属性被所有实例共享,实例属性各自独立。

2.继承与super()

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

    def speak(self):
        return "..."

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name)      # 调用父类 __init__
        self.color = color

    def speak(self):                # 重写父类方法
        return f"{self.name} says meow"

super()使用的场景:

class Child(Parent):
    def method(self):
        super().method()     # 扩展父类行为,而非完全覆盖
        # 额外的子类逻辑...

3.@property装饰器

将方法伪装成属性,实现 getter/setter 的优雅写法:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):           # getter
        return self._radius

    @radius.setter
    def radius(self, value):    # setter
        if value < 0:
            raise ValueError("半径不能为负")
        self._radius = value

    @property
    def area(self):             # 只读计算属性
        return 3.14159 * self._radius ** 2

# 使用
c = Circle(5)
print(c.area)       # 78.53975  —— 像属性一样访问
c.radius = 10       # 触发 setter 校验

4.常用的魔法方法

__str__和__repr__

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

    def __str__(self):       # 给用户看的,print()调用
        return f"Point({self.x}, {self.y})"

    def __repr__(self):      # 给开发者看的,调试用
        return f"Point(x={self.x}, y={self.y})"

print(p)   # Point(1, 2)   ← 漂亮!好读!

__eq__、__lt__、__len__、__getitem__

这些魔术方法的作用是:让你自己的对象也能用 Python 的内置操作符和函数,比如:==、<、len()、[]等

class Book:
    def __init__(self, title, pages):
        self.title = title
        self.pages = pages
        self.content = ["第1页内容", "第2页内容", "第3页内容"]

    def __eq__(self, other):          # == 比较
        return self.pages == other.pages

    def __lt__(self, other):          # < 比较(排序用)
        return self.pages < other.pages

    def __len__(self):                # len() 调用
        return self.pages

    def __getitem__(self, index):     # obj[index] 支持索引
        return self.content[index]

b1 = Book("A", 100)
b2 = Book("B", 100)
print(b1 == b2)   # True  ← 因为页数都是 100

print(len(b1))   # 100  ← 你写 len(b),Python 自动调 b.__len__()

print(b[0])   # 第1页内容  ← 你写 b[0],Python 自动调 b.__getitem__(0)
print(b[1])   # 第2页内容

5.@classmethod与@staticmethod

class Date:
    def __init__(self, year, month, day):   # ① 实例方法:操作具体对象
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls, date_str):         # ② 类方法:用类来造对象(工厂)
        year, month, day = date_str.split("-")
        return cls(int(year), int(month), int(day))

    @staticmethod
    def is_valid_date(year, month, day):    # ③ 静态方法:纯工具函数
        return 1 <= month <= 12 and 1 <= day <= 31

# ① 普通创建
d1 = Date(2024, 1, 1)

# ② 类方法:换种方式创建(传字符串)
d2 = Date.from_string("2024-1-1")

# ③ 静态方法:只是个工具,不用创建对象就能调用
print(Date.is_valid_date(2024, 13, 1))   # False

6.__slots__节省内存

class Point:
    __slots__ = ('x', 'y')   # 禁止动态添加属性,省内存

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

在 Python 里,每个普通对象内部都藏着一个"小字典",叫__dict__,专门用来存它的属性。

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

p = Point(1, 2)
print(p.__dict__)   # 输出:{'x': 1, 'y': 2}

不加__slots__的代价:

1.费内存:字典为了"随时能加新东西",会预留很多空间

2.可以随意乱加属性:

p = Point(1, 2)
p.z = 999        # 完全没报错!随便加了个 z
print(p.z)       # 999

适用场景:创建大量实例时(百万级),显著减少内存占用。

7.私有属性

class BankAccount:
    def __init__(self):
        self._protected = 42     # 约定:内部使用,但可以访问
        self.__private = 100     # 名称改写:变成 _BankAccount__private
    
    #方法也一样
    def __secret_method(self):   # 同样被改写_BankAccount__secret_method
        pass


#单下划线
acc = BankAccount()
print(acc._protected)   # 42  ← 完全可以访问,Python 不拦你
acc._protected = 999    # 也能改,一样不拦

#双下划线
#
print(acc.__private)          # ❌ 报错!AttributeError,找不到
print(acc._BankAccount__private)  # ✅ 100  ← 用改写后的真名才能访问


class Father:
    def __init__(self):
        self.__money = 100      # 实际存成 _Father__money

class Son(Father):
    def __init__(self):
        super().__init__()
        self.__money = 5        # 实际存成 _Son__money(名字不一样!)

Python 会偷偷帮你改名字(这就是图里说的"名称改写机制 / name mangling")。

你写的是__private,Python 在背后把它改成了:_BankAccount__private

规则就是:_类名__变量名

8.__call__让实例可调用

class Counter:
    def __init__(self):
        self.count = 0

    def __call__(self):
        self.count += 1
        return self.count

c = Counter()
print(c())  # 1
print(c())  # 2

9.组合优于继承

"组合优于继承"的意思是:想给一个类加功能时,优先把那个功能做成独立的类,然后让它"拥有"一个(组合),而不是硬去"继承"一堆父类。 这样关系更清晰、更灵活、复用性更强,还能避开多继承的菱形混乱。

# ✅ 组合的正确写法

# 1. 把"飞行"这个功能独立成一个类
class Wings:
    def fly(self):
        print("拍打翅膀,飞起来了!")

# 2. 狗"拥有"翅膀(has-a),而不是"是"鸟(is-a)
class Dog:
    def __init__(self):
        self.wings = Wings()      # 组合:狗有一对翅膀

    def bark(self):
        print("汪汪汪")

    def fly(self):
        self.wings.fly()          # 飞的时候,交给翅膀去做

# 3. 猫也想飞?给它也装一对就行,复用超方便
class Cat:
    def __init__(self):
        self.wings = Wings()

    def fly(self):
        self.wings.fly()


d = Dog()
d.bark()   # 汪汪汪
d.fly()    # 拍打翅膀,飞起来了!   ← 狗获得了飞行能力,但它依然是狗,不是鸟

c = Cat()
c.fly()    # 拍打翅膀,飞起来了!   ← 同一个 Wings 类,猫也能用

更多推荐