Quark's Outlines:Python 基础定制

发布: (2026年1月17日 GMT+8 20:11)
7 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的具体文本内容(文章正文),我将把它翻译成简体中文并保留原有的格式、Markdown 语法以及代码块和链接不变。谢谢!

Source:

概览、历史时间线、问题与解决方案

当你在 Python 中创建一个类时,可以改变对象在某些常见情形下的行为。这称为 Python 基础自定义。Python 为你提供了以双下划线开头和结尾的 特殊方法 名称。这些方法让你能够控制对象在以下情况下会发生什么:

  • 创建时
  • 显示(打印)时
  • 比较时
  • 删除时
  • 真值测试时

不要自行调用这些方法——Python 会在恰当的时机调用它们。你只需要定义它们的行为即可。

示例:__init____str__

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

    def __str__(self):
        return f"Hello, {self.name}!"

g = Greeter("Ada")
print(g)
# prints:
# Hello, Ada!

这里,Python 在对象创建时调用 __init__,在对象被打印时调用 __str__

常见的特殊(魔法)方法

方法何时运行
__init__对象创建
__del__对象删除(当引用计数降至零时)
__str__print()str()
__repr__repr() 或交互式解释器显示
__cmp__Python 2:通用比较
__eq__, __lt__, __le__, __gt__, __ge__, __ne__Python 3:丰富比较
__hash__对象用作字典键或集合元素时
__bool__(在 Python 2 中为 __nonzero__真值测试(if obj:

你可以在类中定义上述任意方法,以让对象以更有用的方式表现。

使用魔法方法挂钩核心操作

class Number:
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value != 0

print(bool(Number(0)))   # False
print(bool(Number(5)))   # True

该对象根据其内部值告诉 Python 应该将其视为 True 还是 False

Python 的自定义方法来源何处?

YearMilestone
1980Smalltalk 和 C++ 引入了用于构造、析构和字符串表示的特殊方法名。
1989Python 的类模型采用了 __init____del____str__
1991Python 0.9.0 添加了 __cmp____repr__ 用于比较和调试视图。
1995真值测试加入了 __nonzero__(后在 Python 3 中被 __bool__ 替代)。
2001在 Python 2.2 中细化了 __hash__ 规则,以实现可预测的字典行为。
2008Python 3.0 移除了 __cmp__,改用富比较方法(__eq____lt__ 等)。
2025核心方法名称已稳定;近期的更改仅关注性能或内部使用。

Source:

如何正确使用 Python 基础定制

下面列出了一些常见问题及其解决方案,每个示例都展示了特定的魔法方法。

1. 在对象创建时运行代码

问题: 你希望在对象实例化的瞬间保存名称,而不必在之后再调用其他方法。

解决方案: 定义 __init__

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

u = User("Ada")
print(u.name)   # prints: Ada

2. 在打印对象时显示可读的字符串

问题: 直接打印实例会得到类似 “ 的输出。你想要一个简洁、友好的表示。

解决方案: 定义 __str__

class Report:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"Report: {self.title}"

r = Report("Q2 Sales")
print(r)   # prints: Report: Q2 Sales

3. 在对象销毁时清理资源

问题: 对象使用了文件或网络资源,需要在对象不再需要时确保其关闭。

解决方案: 定义 __del__

class Connection:
    def __del__(self):
        print("Connection closed.")

c = Connection()
del c          # prints: Connection closed.

注意: 单独依赖 __del__ 可能不够可靠(例如循环引用)。若需确定的清理,建议使用上下文管理器(with 语句)以及 __enter__/__exit__ 协议。

4. 比较对象

问题: 你有一个表示商品及其价格的类,需要对它们进行比较。

解决方案: 在 Python 3 中,实现所需的富比较方法(如 __lt____eq__ 等)。

class Item:
    def __init__(self, price):
        self.price = price

    def __lt__(self, other):
        return self.price < other.price

a = Item(10)
b = Item(15)
print(a < b)   # prints: True

如果需要完整的排序功能,可以继承自 functools.total_ordering,并实现 __eq__ 加上任意一个其他比较方法。

5. 将对象用作字典键

问题: 你希望自定义类的实例能够作为字典的键,这要求哈希值稳定且与相等性保持一致。

解决方案: 一致地实现 __hash__(以及 __eq__)。

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

    def __eq__(self, other):
        if not isinstance(other, Point):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

    def __hash__(self):
        return hash((self.x, self.y))

p1 = Point(1, 2)
p2 = Point(1, 2)
my_dict = {p1: "origin"}
print(my_dict[p2])   # prints: origin

摘要

Python 的 魔法方法(即带有双下划线的那些)让你可以挂接到语言的核心操作——对象创建、表示、比较、真值测试、哈希以及清理。通过在类中定义相应的方法,你可以让对象在日常 Python 代码中表现得自然直观。

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

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

p = Point(1, 2)
d = {p: "here"}
print(d[p])
# prints:
# here

Python 调用 __hash__ 来确定对象在字典中应存放的位置。


Mike Vincent 是一位来自加利福尼亚州洛杉矶的美国软件工程师和应用开发者。了解更多关于 Mike Vincent 的信息。

Back to Blog

相关文章

阅读更多 »