跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
python:第六章高级oop特性
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第六章 高级OOP特性 ====== ===== 本章概要 ===== 本章将深入探讨Python面向对象编程的高级特性,包括魔术方法、属性描述符、元类等,帮助你编写更Pythonic、更强大的代码。 ===== 6.1 魔术方法(Magic Methods) ===== 魔术方法(也称为特殊方法或dunder方法)以双下划线开头和结尾,在特定情况下自动调用。 ==== 6.1.1 对象表示 ==== <code python> class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): """给用户的友好表示""" return f"Person(name='{self.name}', age={self.age})" def __repr__(self): """给开发者的详细表示,eval(repr(obj))应能重建对象""" return f"Person('{self.name}', {self.age})" def __bytes__(self): """返回bytes表示""" return str(self).encode('utf-8') p = Person("Alice", 25) print(str(p)) # Person(name='Alice', age=25) print(repr(p)) # Person('Alice', 25) print(bytes(p)) # b"Person(name='Alice', age=25)" </code> ==== 6.1.2 比较操作 ==== <code python> class Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def __eq__(self, other): """等于 ==""" if not isinstance(other, Rectangle): return NotImplemented return self.area() == other.area() def __lt__(self, other): """小于 <""" if not isinstance(other, Rectangle): return NotImplemented return self.area() < other.area() def __le__(self, other): """小于等于 <=""" return self < other or self == other # 使用functools.total_ordering可以自动生成其他比较方法 def __hash__(self): """支持作为字典键或集合元素""" return hash((self.width, self.height)) r1 = Rectangle(3, 4) # area = 12 r2 = Rectangle(2, 6) # area = 12 r3 = Rectangle(4, 4) # area = 16 print(r1 == r2) # True(面积相等) print(r1 < r3) # True </code> ==== 6.1.3 算术运算 ==== <code python> class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): """+ 运算符""" return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): """- 运算符""" return Vector(self.x - other.x, self.y - other.y) def __mul__(self, scalar): """* 运算符(向量数乘)""" return Vector(self.x * scalar, self.y * scalar) def __rmul__(self, scalar): """右乘(scalar * vector)""" return self * scalar def __truediv__(self, scalar): """/ 运算符""" return Vector(self.x / scalar, self.y / scalar) def __neg__(self): """一元负号 -vector""" return Vector(-self.x, -self.y) def __abs__(self): """abs()函数""" return (self.x ** 2 + self.y ** 2) ** 0.5 def __str__(self): return f"Vector({self.x}, {self.y})" def __repr__(self): return f"Vector({self.x}, {self.y})" v1 = Vector(3, 4) v2 = Vector(1, 2) print(v1 + v2) # Vector(4, 6) print(v1 * 2) # Vector(6, 8) print(3 * v1) # Vector(9, 12) print(abs(v1)) # 5.0 </code> ==== 6.1.4 容器类型方法 ==== <code python> class Deck: def __init__(self): self._cards = [] def __len__(self): """len()函数""" return len(self._cards) def __getitem__(self, index): """索引访问 deck[index]""" return self._cards[index] def __setitem__(self, index, value): """索引赋值 deck[index] = value""" self._cards[index] = value def __delitem__(self, index): """del deck[index]""" del self._cards[index] def __iter__(self): """迭代""" return iter(self._cards) def __contains__(self, item): """in 运算符""" return item in self._cards def add_card(self, card): self._cards.append(card) # 使用 deck = Deck() for card in ["A♠", "K♥", "Q♦"]: deck.add_card(card) print(len(deck)) # 3 print(deck[0]) # A♠ print("K♥" in deck) # True for card in deck: print(card) </code> ==== 6.1.5 上下文管理器 ==== <code python> class DatabaseConnection: def __init__(self, db_name): self.db_name = db_name self.connection = None def __enter__(self): """进入with语句时调用""" print(f"Connecting to {self.db_name}...") self.connection = f"Connection({self.db_name})" return self.connection def __exit__(self, exc_type, exc_val, exc_tb): """退出with语句时调用""" print(f"Closing connection to {self.db_name}...") self.connection = None # 返回True表示异常已处理,不再传播 return False # 使用 with DatabaseConnection("mydb") as conn: print(f"Using {conn}") # 输出: # Connecting to mydb... # Using Connection(mydb) # Closing connection to mydb... </code> ==== 6.1.6 可调用对象 ==== <code python> class Counter: def __init__(self, start=0): self.value = start def __call__(self, step=1): """使实例可以像函数一样调用""" self.value += step return self.value def __int__(self): """int()转换""" return self.value def __index__(self): """用于索引""" return self.value counter = Counter(10) print(counter()) # 11 print(counter(5)) # 16 print(int(counter)) # 16 </code> ===== 6.2 属性(Property)深入 ===== ==== 6.2.1 属性装饰器详解 ==== <code python> class Temperature: def __init__(self, celsius=0): self._celsius = celsius @property def celsius(self): """Getter""" print("Getting celsius...") return self._celsius @celsius.setter def celsius(self, value): """Setter""" print("Setting celsius...") if value < -273.15: raise ValueError("Temperature below absolute zero!") self._celsius = value @celsius.deleter def celsius(self): """Deleter""" print("Deleting celsius...") del self._celsius @property def fahrenheit(self): """只读属性""" return self._celsius * 9/5 + 32 # 使用 temp = Temperature(25) print(temp.celsius) # 调用getter temp.celsius = 30 # 调用setter print(temp.fahrenheit) # 只读属性 </code> ==== 6.2.2 property() 函数方式 ==== <code python> class Circle: def __init__(self, radius): self._radius = radius def get_radius(self): return self._radius def set_radius(self, value): if value < 0: raise ValueError("Radius cannot be negative") self._radius = value def del_radius(self): del self._radius # 使用property()函数 radius = property( fget=get_radius, fset=set_radius, fdel=del_radius, doc="The radius property" ) @property def area(self): import math return math.pi * self._radius ** 2 </code> ===== 6.3 描述符(Descriptor) ===== 描述符是实现了特定协议的类,用于管理属性访问。 ==== 6.3.1 描述符协议 ==== <code python> class Validator: """基础验证描述符""" def __init__(self, min_value=None, max_value=None): self.min_value = min_value self.max_value = max_value self.name = None def __set_name__(self, owner, name): """Python 3.6+ 自动获取属性名""" self.name = name self.private_name = f"_{name}" def __get__(self, obj, objtype=None): if obj is None: return self return getattr(obj, self.private_name, None) def __set__(self, obj, value): if self.min_value is not None and value < self.min_value: raise ValueError(f"{self.name} must be >= {self.min_value}") if self.max_value is not None and value > self.max_value: raise ValueError(f"{self.name} must be <= {self.max_value}") setattr(obj, self.private_name, value) def __delete__(self, obj): raise AttributeError(f"Cannot delete {self.name}") class Person: age = Validator(min_value=0, max_value=150) salary = Validator(min_value=0) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary # 使用 p = Person("Alice", 25, 5000) print(p.age) # 25 # p.age = 200 # ValueError: age must be <= 150 </code> ==== 6.3.2 类型检查描述符 ==== <code python> class Typed: """类型检查描述符""" def __init__(self, expected_type): self.expected_type = expected_type self.name = None def __set_name__(self, owner, name): self.name = name self.private_name = f"_{name}" def __get__(self, obj, objtype=None): if obj is None: return self return getattr(obj, self.private_name) def __set__(self, obj, value): if not isinstance(value, self.expected_type): raise TypeError(f"{self.name} must be {self.expected_type.__name__}, " f"got {type(value).__name__}") setattr(obj, self.private_name, value) class Stock: name = Typed(str) shares = Typed(int) price = Typed(float) def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price @property def cost(self): return self.shares * self.price # 使用 s = Stock("GOOG", 100, 123.45) print(s.cost) # 12345.0 # s.shares = "100" # TypeError </code> ===== 6.4 元类(Metaclass) ===== 元类是创建类的"类",类是元类的实例。 ==== 6.4.1 type 元类 ==== <code python> # 使用type动态创建类 def init(self, name): self.name = name def greet(self): return f"Hello, I'm {self.name}" # 创建类 Person = type('Person', (), { '__init__': init, 'greet': greet }) p = Person("Alice") print(p.greet()) # Hello, I'm Alice </code> ==== 6.4.2 自定义元类 ==== <code python> class SingletonMeta(type): """单例元类""" _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class Database(metaclass=SingletonMeta): def __init__(self, db_name): self.db_name = db_name def query(self, sql): return f"Querying {self.db_name}: {sql}" # 使用 db1 = Database("mydb") db2 = Database("otherdb") # 实际上还是mydb实例 print(db1 is db2) # True </code> ==== 6.4.3 元类控制类创建 ==== <code python> class AutoReprMeta(type): """自动为类生成__repr__方法的元类""" def __new__(mcs, name, bases, namespace, **kwargs): # 创建类之前修改namespace if '__repr__' not in namespace: namespace['__repr__'] = mcs._make_repr(name, namespace.get('__init__')) cls = super().__new__(mcs, name, bases, namespace) return cls @staticmethod def _make_repr(class_name, init_method): def __repr__(self): attrs = ', '.join(f"{k}={v!r}" for k, v in self.__dict__.items()) return f"{class_name}({attrs})" return __repr__ class Point(metaclass=AutoReprMeta): def __init__(self, x, y): self.x = x self.y = y p = Point(3, 4) print(p) # Point(x=3, y=4) </code> ===== 6.5 抽象基类(ABC) ===== ==== 6.5.1 定义抽象基类 ==== <code python> from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def speak(self): """子类必须实现""" pass @abstractmethod def move(self): pass @property @abstractmethod def species(self): """抽象属性""" pass def introduce(self): """具体方法""" return f"I am a {self.species}" class Dog(Animal): @property def species(self): return "Canis familiaris" def speak(self): return "Woof!" def move(self): return "Running on 4 legs" # animal = Animal() # TypeError: Can't instantiate abstract class dog = Dog() print(dog.introduce()) # I am a Canis familiaris </code> ==== 6.5.2 注册虚拟子类 ==== <code python> from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass class Rectangle: """普通类,没有继承Shape""" def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height # 注册为虚拟子类 Shape.register(Rectangle) print(issubclass(Rectangle, Shape)) # True print(isinstance(Rectangle(3, 4), Shape)) # True </code> ===== 6.6 混入(Mixin) ===== 混入是一种设计模式,通过多重继承为类添加功能。 <code python> class JSONSerializableMixin: """提供JSON序列化功能的混入""" import json def to_json(self): return self.json.dumps(self.__dict__, indent=2) @classmethod def from_json(cls, json_str): data = cls.json.loads(json_str) return cls(**data) class ComparableMixin: """提供比较功能的混入""" def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented return self.__dict__ == other.__dict__ def __ne__(self, other): return not self == other class Person(JSONSerializableMixin, ComparableMixin): def __init__(self, name, age): self.name = name self.age = age # 使用 p1 = Person("Alice", 25) p2 = Person("Alice", 25) print(p1.to_json()) print(p1 == p2) # True </code> ===== 6.7 代码示例 ===== ==== 示例1:实现一个完整的数值类型 ==== <code python> from functools import total_ordering @total_ordering class Rational: """有理数类""" def __init__(self, numerator, denominator=1): if denominator == 0: raise ValueError("Denominator cannot be zero") # 约分 g = self._gcd(abs(numerator), abs(denominator)) self.numerator = numerator // g self.denominator = denominator // g # 确保分母为正 if self.denominator < 0: self.numerator = -self.numerator self.denominator = -self.denominator @staticmethod def _gcd(a, b): while b: a, b = b, a % b return a def __str__(self): if self.denominator == 1: return str(self.numerator) return f"{self.numerator}/{self.denominator}" def __repr__(self): return f"Rational({self.numerator}, {self.denominator})" def __eq__(self, other): if isinstance(other, Rational): return (self.numerator == other.numerator and self.denominator == other.denominator) return NotImplemented def __lt__(self, other): if isinstance(other, Rational): return (self.numerator * other.denominator < other.numerator * self.denominator) return NotImplemented def __add__(self, other): if isinstance(other, Rational): num = (self.numerator * other.denominator + other.numerator * self.denominator) den = self.denominator * other.denominator return Rational(num, den) return NotImplemented def __sub__(self, other): return self + Rational(-other.numerator, other.denominator) def __mul__(self, other): if isinstance(other, Rational): return Rational(self.numerator * other.numerator, self.denominator * other.denominator) return NotImplemented def __truediv__(self, other): return self * Rational(other.denominator, other.numerator) def __float__(self): return self.numerator / self.denominator def __int__(self): return self.numerator // self.denominator # 使用 r1 = Rational(1, 2) r2 = Rational(1, 3) print(r1 + r2) # 5/6 print(r1 * r2) # 1/6 print(r1 > r2) # True print(float(r1)) # 0.5 </code> ==== 示例2:使用描述符实现ORM字段 ==== <code python> class Field: """数据库字段描述符""" def __init__(self, name=None, dtype=str, primary_key=False): self.name = name self.dtype = dtype self.primary_key = primary_key def __set_name__(self, owner, name): if self.name is None: self.name = name self.private_name = f"_{name}" def __get__(self, obj, objtype=None): if obj is None: return self return getattr(obj, self.private_name, None) def __set__(self, obj, value): if not isinstance(value, self.dtype): try: value = self.dtype(value) except (ValueError, TypeError): raise TypeError(f"Expected {self.dtype.__name__}, got {type(value).__name__}") setattr(obj, self.private_name, value) class ModelMeta(type): """模型元类""" def __new__(mcs, name, bases, namespace): fields = {} for key, value in namespace.items(): if isinstance(value, Field): fields[key] = value namespace['_fields'] = fields return super().__new__(mcs, name, bases, namespace) class Model(metaclass=ModelMeta): """ORM基础模型""" def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) def __repr__(self): attrs = ', '.join(f"{k}={getattr(self, k)!r}" for k in self._fields) return f"{self.__class__.__name__}({attrs})" def to_dict(self): return {k: getattr(self, k) for k in self._fields} class User(Model): id = Field(dtype=int, primary_key=True) name = Field(dtype=str) age = Field(dtype=int) email = Field(dtype=str) # 使用 user = User(id=1, name="Alice", age=25, email="alice@example.com") print(user) print(user.to_dict()) </code> ===== 6.8 练习题 ===== ==== 练习1:实现一个可切片、可迭代的序列类 ==== <code python> class MySequence: def __init__(self, data): self._data = list(data) def __len__(self): return len(self._data) def __getitem__(self, index): if isinstance(index, slice): return MySequence(self._data[index]) return self._data[index] def __setitem__(self, index, value): self._data[index] = value def __iter__(self): return iter(self._data) def __contains__(self, item): return item in self._data def __repr__(self): return f"MySequence({self._data})" # 测试 seq = MySequence([1, 2, 3, 4, 5]) print(len(seq)) # 5 print(seq[1:4]) # MySequence([2, 3, 4]) print(3 in seq) # True </code> ==== 练习2:实现属性缓存装饰器 ==== <code python> class cached_property: """缓存属性装饰器,只计算一次""" def __init__(self, func): self.func = func self.name = func.__name__ self.__doc__ = func.__doc__ def __set_name__(self, owner, name): self.name = name def __get__(self, obj, objtype=None): if obj is None: return self if self.name not in obj.__dict__: obj.__dict__[self.name] = self.func(obj) return obj.__dict__[self.name] class Circle: def __init__(self, radius): self.radius = radius @cached_property def area(self): print("Calculating area...") import math return math.pi * self.radius ** 2 # 测试 c = Circle(5) print(c.area) # 计算并缓存 print(c.area) # 直接使用缓存 </code> ===== 本章小结 ===== 本章深入学习了Python的高级OOP特性: * **魔术方法** - 对象表示、比较、算术运算、容器操作、上下文管理 * **属性** - @property装饰器、getter/setter/deleter * **描述符** - __get__、__set__、__delete__协议 * **元类** - type、自定义元类、控制类创建 * **抽象基类** - ABC、@abstractmethod、虚拟子类 * **混入** - 通过多重继承复用代码 这些高级特性让你能够编写更灵活、更强大的面向对象代码。下一章将学习迭代器和生成器。 ===== 进一步阅读 ===== * [[https://docs.python.org/zh-cn/3/reference/datamodel.html|Python数据模型]] * [[https://docs.python.org/zh-cn/3/howto/descriptor.html|描述符指南]]
python/第六章高级oop特性.txt
· 最后更改:
2026/02/03 19:45
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部