首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第 13章 性能测量和大O算法分析
13.1 timeit模块
13.2 cProfile分析器
13.3 大O算法分析
13.4 大O阶
13.4.1 使用书架打比方描述大O阶
13.4.2 大O 测量的是最坏情况
13.5 确定代码的大O 阶
13.5.1 为什么低阶项和系数不重要
13.5.2 大O 分析实例
13.5.3 常见函数调用的大O 阶
13.5.4 一眼看出大O 阶
13.5.5 当n 很小时,大O并不重要,而n通常都很小
第 14章 项目实战
14.1 汉诺塔
14.1.1 汉诺塔输出
14.1.2 汉诺塔源代码
14.1.3 汉诺塔编写代码
14.2 四子棋
14.2.1 四子棋输出
14.2.2 四子棋源代码
14.2.3 四子棋编写代码
第 15章 面向对象编程和类
15.1 拿现实世界打比方:填写表格
15.2 基于类创建对象
15.3 创建一个简单的类——WizCoin
15.3.1 方法__init__()和self
15.3.2 特性
15.3.3 私有特性和私有方法
15.4 函数type()和特性__qualname__
15.5 非OOP 和OOP 的例子:井字棋
15.6 为现实世界设计类是一件难事儿
第 16章 面向对象编程和继承
16.1 继承的原理
16.1.1 重写方法
16.1.2 super()函数
16.1.3 倾向于组合而非继承
16.1.4 继承的缺点
16.2 函数isinstance()和issubclass()
16.3 类方法
16.4 类特性
16.5 静态方法
16.6 何时应该使用类和静态的面向对象特性
16.7 面向对象的行话
16.7.1 封装
16.7.2 多态性
16.8 何时不应该使用继承
16.9 多重继承
16.10 方法解析顺序
第 17章 Python 风格的面向对象编程:属性和魔术方法
17.1 属性
17.1.1 将特性转换为属性
17.1.2 使用setter 验证数据
17.1.3 只读属性
17.1.4 什么时候应该使用属性
17.2 Python 的魔术方法
17.2.1 字符串表示魔术方法
17.2.2 数值魔术方法
17.2.3 反射数值魔术方法
17.2.4 原地魔术方法
17.2.5 比较魔术方法
当前位置:
首页>>
技术小册>>
Python编程轻松进阶(五)
小册名称:Python编程轻松进阶(五)
### 17.2 Python 的魔术方法 在Python中,魔术方法(Magic Methods)或称为特殊方法(Special Methods)是一系列双下划线(`__`)开头和结尾的方法。这些方法在Python的类定义中扮演着特殊角色,它们为Python对象提供了丰富的内建功能,如数值运算、对象比较、属性访问控制等。掌握这些魔术方法,能够让你更深入地理解Python的对象模型,进而编写出更加灵活、强大的代码。 #### 17.2.1 构造与析构 **1. `__init__(self, ...)`** 这是类的构造函数,用于在创建对象时初始化对象的状态。当创建类的新实例时,`__init__` 方法会自动被调用。 ```python class MyClass: def __init__(self, value): self.value = value obj = MyClass(10) print(obj.value) # 输出: 10 ``` **2. `__new__(cls, ...)`** `__new__` 是一个静态方法,用于创建类的实例。在创建对象时,`__new__` 方法首先被调用,然后才是 `__init__` 方法。`__new__` 必须返回一个类的实例,否则将引发 `TypeError`。 ```python class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance def __init__(self): pass # 测试单例模式 obj1 = Singleton() obj2 = Singleton() print(obj1 is obj2) # 输出: True ``` **3. `__del__(self)`** 析构函数,当对象被销毁时自动调用。用于执行清理操作,如关闭文件、释放资源等。 ```python class Resource: def __init__(self, name): self.name = name print(f"{name} created") def __del__(self): print(f"{self.name} destroyed") # 当Resource对象超出作用域或被显式删除时,__del__ 会被调用 r = Resource("Resource1") del r # 输出: Resource1 destroyed ``` #### 17.2.2 属性访问 **1. `__getattr__(self, name)`** 当尝试访问一个不存在的属性时,Python会调用此方法。可以用来实现动态属性或懒加载等特性。 ```python class LazyProperty: def __init__(self, func): self.func = func def __get__(self, instance, cls): if instance is None: return self result = self.func(instance) setattr(instance, self.func.__name__, result) # 将结果缓存为实例属性 return result class MyClass: @LazyProperty def expensive_calculation(self): print("Calculating...") return 42 obj = MyClass() print(obj.expensive_calculation) # 第一次调用,执行计算 print(obj.expensive_calculation) # 第二次调用,从缓存中获取 ``` **2. `__setattr__(self, name, value)`** 用于设置对象的属性值。重写此方法时,应小心避免无限递归,通常通过调用 `super().__setattr__(name, value)` 来处理普通属性的设置。 **3. `__getattribute__(self, name)`** 用于获取对象的属性值。与 `__getattr__` 不同,`__getattribute__` 会在任何属性访问时被调用,包括普通属性和特殊方法。因此,重写此方法时需要特别小心,以避免无限递归。 #### 17.2.3 容器类型 **1. 序列类型** - `__len__(self)`:返回容器中的元素数量。 - `__getitem__(self, key)`:根据索引或键获取容器中的元素。 - `__setitem__(self, key, value)`:设置容器中指定索引或键的元素值。 - `__delitem__(self, key)`:删除容器中指定索引或键的元素。 **2. 迭代器与生成器** - `__iter__(self)`:返回一个迭代器对象。 - `__next__(self)`:返回容器的下一个元素,并在末尾引发 `StopIteration` 异常。 **示例:实现一个简单的栈** ```python class Stack: def __init__(self): self.items = [] def __len__(self): return len(self.items) def __getitem__(self, index): return self.items[index] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() def __iter__(self): return iter(self.items[::-1]) # 返回逆序迭代器 # 使用栈 s = Stack() s.push(1) s.push(2) s.push(3) print(s[0]) # 输出: 3 for item in s: print(item) # 输出: 3, 2, 1 ``` #### 17.2.4 数值运算 Python中的数值类型(如整数、浮点数)支持丰富的运算符,如加法(`+`)、减法(`-`)等。通过定义特定的魔术方法,可以让自定义的类也支持这些运算。 - `__add__(self, other)`:加法。 - `__sub__(self, other)`:减法。 - `__mul__(self, other)`:乘法。 - `__truediv__(self, other)`:真除法。 - `__floordiv__(self, other)`:整数除法(地板除)。 - `__mod__(self, other)`:取模。 - `__pow__(self, other[, modulo])`:幂运算。 **示例:实现一个简单的二维向量类** ```python class Vector2D: def __init__(self, x=0, y=0): self.x = x self.y = y def __add__(self, other): return Vector2D(self.x + other.x, self.y + other.y) def __mul__(self, scalar): return Vector2D(self.x * scalar, self.y * scalar) def __str__(self): return f"Vector2D({self.x}, {self.y})" # 使用Vector2D v1 = Vector2D(1, 2) v2 = Vector2D(3, 4) print(v1 + v2) # 输出: Vector2D(4, 6) print(v1 * 2) # 输出: Vector2D(2, 4) ``` #### 17.2.5 比较与排序 - `__eq__(self, other)`:等于。 - `__ne__(self, other)`:不等于。 - `__lt__(self, other)`:小于。 - `__le__(self, other)`:小于等于。 - `__gt__(self, other)`:大于。 - `__ge__(self, other)`:大于等于。 这些魔术方法定义了对象之间的比较行为,使得自定义对象可以像内置类型一样被比较和排序。 #### 总结 Python的魔术方法是Python对象模型的核心部分,它们为Python对象提供了丰富的行为和特性。通过定义和重写这些魔术方法,可以使得自定义的类更加灵活、强大,更加符合Python的编程习惯。然而,在重写这些魔术方法时,也需要特别注意避免无限递归、保持方法的通用性和一致性等问题。希望本章的内容能够帮助你更好地理解Python的魔术方法,并在实际编程中灵活运用它们。
上一篇:
17.1.4 什么时候应该使用属性
下一篇:
17.2.1 字符串表示魔术方法
该分类下的相关小册推荐:
Python与办公-玩转Excel
Python机器学习实战
Python编程轻松进阶(三)
Python数据分析与挖掘实战(下)
Python合辑6-字典专题
Python编程轻松进阶(四)
Python爬虫入门与实战开发(上)
Python高性能编程与实战
剑指Python(万变不离其宗)
Python合辑10-函数
Python合辑8-变量和运算符
Python机器学习基础教程(上)