Python零基础入门:魔法方法详解

一、什么是魔法方法?

魔法方法(Magic Methods)是Python中一种特殊的方法,它们以双下划线(__)开头和结尾(如__init____str__等)。魔法方法允许你定义类在特定情况下的行为,例如初始化、字符串表示、运算符重载等。

二、常见的魔法方法分类

1. 构造和初始化

  • __new__(cls, [...]): 创建实例时调用的第一个方法

  • __init__(self, [...]): 实例初始化方法

  • __del__(self): 析构方法,当实例被销毁时调用

2. 字符串表示

  • __str__(self): 定义str()print()的行为

  • __repr__(self): 定义repr()的行为,通常用于调试

  • __format__(self, format_spec): 定义format()的行为

3. 比较运算符

  • __eq__(self, other): 定义==行为

  • __ne__(self, other): 定义!=行为

  • __lt__(self, other): 定义<行为

  • __le__(self, other): 定义<=行为

  • __gt__(self, other): 定义>行为

  • __ge__(self, other): 定义>=行为

4. 算术运算符

  • __add__(self, other)+

  • __sub__(self, other)-

  • __mul__(self, other)*

  • __truediv__(self, other)/

  • __floordiv__(self, other)//

  • __mod__(self, other)%

  • __pow__(self, other)**

5. 容器类型方法

  • __len__(self): 定义len()行为

  • __getitem__(self, key): 定义self[key]行为

  • __setitem__(self, key, value): 定义self[key] = value行为

  • __delitem__(self, key): 定义del self[key]行为

  • __contains__(self, item): 定义in操作符行为

6. 可调用对象

  • __call__(self, [...]): 使实例可以像函数一样被调用

7. 上下文管理

  • __enter__(self): 定义with语句开始时的行为

  • __exit__(self, exc_type, exc_val, exc_tb): 定义with语句结束时的行为

三、魔法方法练习题

1. __init__ - 构造初始化方法

这是最常见的魔法方法,用于初始化新创建的对象。

class Dog:
    def __init__(self, name, age):
        self.name = name  # 设置实例属性
        self.age = age
        print(f"一只名叫{name}的狗出生了!")

# 创建实例时会自动调用__init__
my_dog = Dog("旺财", 3)  # 输出:一只名叫旺财的狗出生了!
print(my_dog.name)      # 输出:旺财

2. __str__ vs __repr__ - 字符串表示

  • __str__:给用户看的友好字符串

  • __repr__:给开发者看的准确字符串(通常可以用来重建对象)

    class Point:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __str__(self):
            return f"这是一个点({self.x}, {self.y})"
        
        def __repr__(self):
            return f"Point({self.x}, {self.y})"
    
    p = Point(1, 2)
    print(p)         # 输出:这是一个点(1, 2)
    print(str(p))    # 输出:这是一个点(1, 2)
    
    
    print(repr(p))   # 输出:Point(1, 2)

3. 算术运算符

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 __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(1, 1)
print(v1 + v2)  # Vector(3, 4)
print(v1 - v2)  # Vector(1, 2)
print(v1 * 3)   # Vector(6, 9)

4. 比较运算符

class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    # 等于 ==
    def __eq__(self, other):
        return self.score == other.score
    
    # 大于 >
    def __gt__(self, other):
        return self.score > other.score
    
    # 小于等于 <=
    def __le__(self, other):
        return self.score <= other.score

alice = Student("Alice", 85)
bob = Student("Bob", 75)
print(alice == bob)  # False
print(alice > bob)   # True
print(alice <= bob)  # False

5. __len__ - 获取长度

class Playlist:
    def __init__(self, songs):
        self.songs = list(songs)
    
    def __len__(self):
        return len(self.songs)

my_playlist = Playlist(["Song1", "Song2", "Song3"])
print(len(my_playlist))  # 输出:3

6. __getitem__ 和 __setitem__ - 索引访问

class Playlist:
    def __init__(self, songs):
        self.songs = list(songs)
    
    def __getitem__(self, index):
        return self.songs[index]
    
    def __setitem__(self, index, value):
        self.songs[index] = value

pl = Playlist(["A", "B", "C"])
print(pl[1])    # 输出:B
pl[1] = "New Song"
print(pl[1])    # 输出:New Song

7. __iter__ - 使对象可迭代

class CountDown:
    def __init__(self, start):
        self.start = start
    
    def __iter__(self):
        current = self.start
        while current > 0:
            yield current
            current -= 1

for num in CountDown(5):
    print(num)  # 输出:5 4 3 2 1

8. __call__ - 使实例可调用

class Adder:
    def __init__(self, n):
        self.n = n
    
    def __call__(self, x):
        return self.n + x

add5 = Adder(5)
print(add5(3))   # 输出:8
print(add5(10))  # 输出:15

9. __enter__ 和 __exit__ - 上下文管理

class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        self.end = time.time()
        print(f"耗时: {self.end - self.start:.2f}秒")

with Timer():
    # 模拟耗时操作
    sum(i for i in range(1000000))
# 输出:耗时: 0.12秒

 

四、综合练习案例

实现一个简单的分数类

class Fraction:
    def __init__(self, numerator, denominator=1):
        self.numerator = numerator
        self.denominator = denominator
        self._simplify()
    
    def _simplify(self):
        """约分分数"""
        def gcd(a, b):
            while b:
                a, b = b, a % b
            return a
        
        common_divisor = gcd(self.numerator, self.denominator)
        self.numerator //= common_divisor
        self.denominator //= common_divisor
    
    def __add__(self, other):
        new_num = self.numerator * other.denominator + other.numerator * self.denominator
        new_den = self.denominator * other.denominator
        return Fraction(new_num, new_den)
    
    def __sub__(self, other):
        new_num = self.numerator * other.denominator - other.numerator * self.denominator
        new_den = self.denominator * other.denominator
        return Fraction(new_num, new_den)
    
    def __mul__(self, other):
        return Fraction(self.numerator * other.numerator, 
                        self.denominator * other.denominator)
    
    def __truediv__(self, other):
        return Fraction(self.numerator * other.denominator,
                        self.denominator * other.numerator)
    
    def __eq__(self, other):
        return (self.numerator == other.numerator and 
                self.denominator == other.denominator)
    
    def __str__(self):
        return f"{self.numerator}/{self.denominator}"
    
    def __repr__(self):
        return f"Fraction({self.numerator}, {self.denominator})"

# 使用示例
f1 = Fraction(1, 2)
f2 = Fraction(1, 3)
print(f1 + f2)  # 输出:5/6
print(f1 - f2)  # 输出:1/6
print(f1 * f2)  # 输出:1/6
print(f1 / f2)  # 输出:3/2
print(f1 == f2)  # 输出:False

五、魔法方法总结

  1. 核心概念

    • 魔法方法是Python中特殊的方法,用于自定义类的行为

    • 它们以双下划线开头和结尾

    • Python在特定情况下自动调用这些方法

  2. 主要用途

    • 初始化对象(__init____new__)

    • 字符串表示(__str____repr__)

    • 运算符重载(__add____sub__等)

    • 容器行为(__len____getitem__等)

    • 上下文管理(__enter____exit__)

    • 可调用对象(__call__)

  3. 最佳实践

    • __repr__应该返回一个可以用来重建对象的字符串

    • __str__应该返回一个用户友好的字符串

    • 实现比较方法时保持一致性

    • 运算符重载应该保持直观的行为

  4. 注意事项

    • 不要滥用魔法方法,保持行为直观

    • 某些魔法方法需要成对实现(如__eq____hash__

    • 继承内置类型时要小心,可能需要重写多个魔法方法

  5. 学习建议

    • 从简单的__init____str__开始

    • 逐步尝试运算符重载

    • 理解Python的数据模型如何工作

    • 查看内置类型的源代码学习标准实现

  6. 魔法方法总结表

魔法方法描述触发方式
__init__(self)对象初始化obj = Class()
__str__(self)用户友好字符串表示str(obj)print(obj)
__repr__(self)开发者字符串表示repr(obj)
__add__(self, other)加法运算 +obj1 + obj2
__sub__(self, other)减法运算 -obj1 - obj2
__mul__(self, other)乘法运算 *obj1 * obj2
__eq__(self, other)等于比较 ==obj1 == obj2
__lt__(self, other)小于比较 <obj1 < obj2
__len__(self)获取长度len(obj)
__getitem__(self, key)索引访问obj[key]
__setitem__(self, key, value)索引赋值obj[key] = value
__iter__(self)迭代支持for x in obj
__call__(self, ...)使实例可调用obj()
__enter__(self)__exit__(self)上下文管理with obj:

记住这些魔法方法的关键是理解它们何时被Python自动调用。通过实现这些方法,你可以让你自定义的类表现得像Python内置类型一样自然。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不爱说话的分院帽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值