大数跨境
0
0

Python 魔法方法:用 Dunder 函数编写更简洁的代码

Python 魔法方法:用 Dunder 函数编写更简洁的代码 InfraLink
2025-09-08
0
导读:了解 Python 的 dunder 方法(__str__、__add__、__eq__等)可以深入了解如何


了解 Python 的 dunder 方法(__str____add____eq__等)可以深入了解如何让你的代码更简洁、更直观、更强大。

你是否曾在 Python 中打印过一个对象并得到类似这样的结果?

是的……非常有帮助,对吧?

我还记得第一次遇到这种情况的情形。我只是想查看对象的内容,Python 却给我一个神秘的内存地址。我完全不知道发生了什么。结果发现,Python 并没有想象中的那么难——只是我没有学会让对象如何正确地表示自己。

其实这就是dunder 方法发挥作用的地方。

这些双下划线函数(__str____repr____add__等等)可以让你自定义对象的行为。你能够利用他们接入 Python 内置行为并根据自己的需求进行调整的方式。

如果你到现在还没有使用他们,那么相比你写Python代码还是比较困难的。下面就跟云朵君一起学习下dunder 方法吧~

Dunder 方法到底是什么?

Dunder(“双下划线”的缩写)方法是内置的 Python 函数,可让你控制对象的行为方式

  • 想要让你的对象像普通字符串一样打印吗?使用__str__
  • 需要比较类的两个实例吗?使用__eq__
  • 想要你的对象与能够使用+么?使用__add__

这些方法与 Python 内置类型的底层方法相同。你只需要在自己的类中重写它们即可。

丑陋的打印输出(__str____repr__

这是一个简单的类:

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

现在,尝试打印一个实例:

b = Book("1984""George Orwell")
print(b)

你得到了什么?

这看起来是不太有用。

重写__str____repr__

我喜欢将这两种方法视为一种用于与人类交互,一种用于调试

  • __str__→ 我想要打印什么?
  • __repr__→ 这在调试控制台中应该看起来是什么样子?

以下是我通常实现它们的方式:

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return f'"{self.title}" by {self.author}'

    def __repr__(self):
        return f'Book(title="{self.title}", author="{self.author}")'

现在,检查一下:

b = Book("1984""George Orwell")
print(b)
"1984" by George Orwell

好多了。

使对象像数字一样(__add____sub__等)

我第一次学习这个的时候就被惊到了。居然可以让自定义对象像数字一样处理,用于加减乘除!

假设我正在创建一个Wallet类。我希望它能实现以下功能:

wallet1 = Wallet( 50 ) 
wallet2 = Wallet( 30 ) 
total = wallet1 + wallet2   # 应该添加余额

这是因为 ,除非我告诉 Python 遇到+时,我的类要做什么,要不然它根本不知道。

重写__add__

class Wallet:
    def __init__(self, balance):
        self.balance = balance

    def __add__(self, other):
        if isinstance(other, Wallet):
            return Wallet(self.balance + other.balance)
        return NotImplemented

现在:

w1 = Wallet(50)
w2 = Wallet(30)
w3 = w1 + w2
print(w3.balance)  # 80

它确实有效。

而且它并不仅限于加法 — — 你可以对减法 ( __sub__)、乘法 ( __mul__) 甚至比较 ( __lt____gt__) 执行相同的操作。

比较对象(__eq____gt____lt__

这是我早期遇到的另一个问题。

假设我有两个具有相同余额的钱包实例:

w1 = Wallet(50)
w2 = Wallet(50)
print(w1 == w2)

你会认为 Python 会说True,对吗?

不。它返回False

这是因为,默认情况下,Python 不会比较对象内容——它会检查它们是否是内存中完全相同的对象

重写 __eq__

class Wallet:
    def __init__(self, balance):
        self.balance = balance

    def __eq__(self, other):
        return self.balance == other.balance if isinstance(other, Wallet) else False

现在:

w1 = Wallet(50)
w2 = Wallet(50)
print(w1 == w2)  # True

好多了。

使对象可迭代(__iter____next__

我记得在尝试构建交易历史跟踪器时,我曾为此苦苦挣扎。我想像这样循环遍历我的交易:

class TransactionHistory:
    def __init__(self, transactions):
        self.transactions = transactions
        self.index = 0

history = TransactionHistory(["Deposit $100""Withdraw $50""Deposit $200"])
for transaction in history:
    print(transaction)

但事实并非如此——Python 没有它:

重写__iter____next__

class TransactionHistory:
    def __init__(self, transactions):
        self.transactions = transactions
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.transactions):
            raise StopIteration
        transaction = self.transactions[self.index]
        self.index += 1
        return transaction

history = TransactionHistory(["Deposit $100""Withdraw $50""Deposit $200"])
for transaction in history:
    print(transaction)

现在它的行为就像一个列表。

Deposit $100
Withdraw $50
Deposit $200

写在最后

Dunder 方法不仅仅是为了好玩——它们让你的类感觉像是内置的 Python 类型

  • 如果没有__str__,你的对象打印出来就像垃圾一样。
  • 如果没有__eq__,Python 就不知道两个对象何时“相等”。
  • 如果没有__iter__,循环遍历对象就无法进行。

它们功能强大、易于使用,一旦你开始使用它们,你就会想知道如果没有它们你该如何编码。




关注我们!与InfraLink共赴智能未来



🔗 聚焦数据科学 | 深耕算法创新 | 赋能AI工程化

📌 技术干货持续更新,全球生态合作共建

✨ 点击关注@InfraLink,解锁更多前沿技术资讯与实践洞察

【声明】内容源于网络
0
0
InfraLink
链接技术基建,共筑智能未来。 在数据智能重塑产业格局的时代,InfraLink 以「构建技术基础设施的全球连接枢纽」为使命,聚焦 数据科学、算法创新、AI 工程化 三大核心领域,打造集技术资讯、实践经验、生态合作为一体的全球化社区平台。
内容 109
粉丝 0
InfraLink 链接技术基建,共筑智能未来。 在数据智能重塑产业格局的时代,InfraLink 以「构建技术基础设施的全球连接枢纽」为使命,聚焦 数据科学、算法创新、AI 工程化 三大核心领域,打造集技术资讯、实践经验、生态合作为一体的全球化社区平台。
总阅读14
粉丝0
内容109