目录
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)) # False6.__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()) # 29.组合优于继承
"组合优于继承"的意思是:想给一个类加功能时,优先把那个功能做成独立的类,然后让它"拥有"一个(组合),而不是硬去"继承"一堆父类。这样关系更清晰、更灵活、复用性更强,还能避开多继承的菱形混乱。
# ✅ 组合的正确写法 # 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 类,猫也能用