学习什么是Python魔法方法

134 阅读7分钟

What Are Python Magic Methods

Python 中的魔法方法是一个方法集合,它自动与语言中的每个类定义相关联。如果你创建了自己的类,你可以覆盖一个或多个标准的魔法方法来定制它们的行为。Python 中有许多神奇的方法,我们在本教程的末尾列出了它们的表格。现在,我们想看看一些更常用的魔法方法,它们在日常编程中很有用。魔法可以用来定制你的对象如何被表示为字符串,控制在获取和设置过程中如何访问对象的属性,检查是否相等,以及使一个对象像函数一样可以被调用。


字符串表示法

我们要学习的前两个神奇的方法是 Python 用来生成对象的字符串表示法。一个叫做**__str__,另一个叫做__repr__** 。函数**__str__用于输出对象的一个用户友好的字符串描述,通常是为了显示给用户。__repr__函数更多的是用于软件的开发者。它输出一个可以用于调试的字符串,所以它被用来显示大量的详细信息。这些函数以各种方式在一个对象上被调用。当你调用print()函数并传入对象时,或者当你使用__str____repr__**铸造函数时,这些方法将被调用。

__str__和__repr__

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

    # The __str__ function is used to return a user-friendly string
    # representation of the object
    def __str__(self):
        return f'{self.title} by {self.author}, costs {self.price}'

    # The __str__ function is used to return a developer-friendly string
    # representation of the object
    def __repr__(self):
        return f'title={self.title},author={self.author},price={self.price}'


book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)

# print each object
print(book1)
print(book2)

# use str() and repr()
print(str(book1))
print(repr(book2))
Python Crash Course by Eric Matthes, costs 23.99
Serious Python by Julien Danjou, costs 25.43

Python Crash Course by Eric Matthes, costs 23.99
title=Serious Python,author=Julien Danjou,price=25.43

等价和比较

通过使用平等和比较的魔法方法,我们可以给对象以相互比较的能力。当你的对象与另一个对象比较时,名为eq的魔法方法会被调用。下面的代码还实现了大于或等于魔法方法和小于魔法方法。

_eq__ __ge__ __lt__

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

    def __eq__(self, value):
        if not isinstance(value, Book):
            raise ValueError('Can't compare book to non-book type')

        return (self.title == value.title and
                self.author == value.author and
                self.price == value.price)

    def __ge__(self, value):
        if not isinstance(value, Book):
            raise ValueError('Can't compare book to non-book type')

        return self.price >= value.price

    def __lt__(self, value):
        if not isinstance(value, Book):
            raise ValueError('Can't compare book to non-book type')

        return self.price < value.price


book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
book3 = Book('Automate the Boring Stuff with Python', 'Al Sweigart ', 26.99)
book4 = Book('Python for Kids', 'Jason Briggs', 19.79)

# Check for equality
print(book1 == book3)
print(book1 == book2)
print(book3 == book3)

# Check for greater and lesser value
print(book2 >= book1)
print(book2 < book1)
print(book3 >= book2)

# Sorting books
books = [book1, book3, book2, book4]
books.sort()
print([book.title for book in books])
False
False
True

True
False
True

['Python for Kids', 'Python Crash Course', 'Serious Python', 'Automate the Boring Stuff with Python']

属性访问

Python 的魔法方法也给了你对如何访问一个对象的属性的完全控制。一个类可以定义方法,在任何时候设置或检索一个属性时都可以拦截这个过程。我们在本节中要看的方法如下。

  • __getattribute__当一个属性被检索时被调用。注意你不能直接访问 attr 名称,否则会产生一个递归循环。
  • __setattr__当一个属性值被设置时被调用。不要在这里直接设置 attr,否则一个递归循环会导致崩溃。
  • 当 __getattribute__ 查询失败时调用**__getattr__**- 你可以用这个方法即时生成属性。

__getattribute__ __setattr__ __getattr__

class Book():
    def __init__(self, title, author, price):
        super().__init__()
        self.title = title
        self.author = author
        self.price = price
        self._discount = 0.1

    def __str__(self):
        return f'{self.title} by {self.author}, costs {self.price}'

    def __getattribute__(self, name):
        if (name == 'price'):
            price = super().__getattribute__('price')
            discount = super().__getattribute__('_discount')
            return price - (price * discount)
        return super().__getattribute__(name)

    def __setattr__(self, name, value):
        if (name == 'price'):
            if type(value) is not float:
                raise ValueError('The "price" attribute must be a float')
        return super().__setattr__(name, value)

    def __getattr__(self, name):
        return name + ' is not here!'


book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)

# Try setting and accessing the price
book1.price = 37.95
print(book1)

book2.price = float(40)  # using an int will raise an exception
print(book2)

# If an attribute doesn't exist, __getattr__ will be called
print(book1.randomprop)
Python Crash Course by Eric Matthes, costs 34.155
Serious Python by Julien Danjou, costs 36.0
randomprop is not here!

使一个对象可被调用

__call__魔法方法有一个有趣的能力,可以使一个对象可被调用,就像你在 Python 中调用其他函数一样。

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

    def __str__(self):
        return f'{self.title} by {self.author}, costs {self.price}'

    def __call__(self, title, author, price):
        self.title = title
        self.author = author
        self.price = price


book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)

# call the object as if it were a function
print(book1)
book1('Learning Python', 'Mark Lutz', 44.94)
print(book1)
Python Crash Course by Eric Matthes, costs 23.99
Learning Python by Mark Lutz, costs 44.94

Python魔法方法参考

初始化和构造它的作用
__new__(cls, other)允许我们通过__new__魔法方法覆盖任何对象的新建步骤。
__init__(self, other)当一个对象被创建时,通过调用对象的__init__方法来初始化它。
__del__(self)__del__是一个析构器方法,当对象的所有引用被删除时,即当一个对象被垃圾回收时,它就被调用。
单元运算符和函数它的作用
__pos__(self)实现单数正数的行为(例如:+some_object)。
__neg__(self)当单数**-**运算符在我们的对象上被调用时,执行行为。
__abs__(self)被内置的abs()函数调用。它从一个数字中去掉负号 (如果它是负的)。
__invert__(self)使用~运算符。它是一个 "反转 "或 "补数 "的操作,输入数据的所有位都被反转。
__round__(self,n)实现round()函数的行为。返回一个指定数字的四舍五入版本的浮点数。
返回一个四舍五入的浮点数执行内置的math.floor()函数。
返回指定数字的四舍五入版本的浮点数。ceil()返回 x 的最高值,即不小于 x 的最小整数。
__trunc__(self)去掉任何小数,就是math.trunc()的作用。
增强的赋值它的作用是什么?
__iadd__(self, other)用赋值做加法:a +=b
__isub__(self, other)带有赋值的减法:a -=b
__imul__(self, other)带有赋值的乘法:a *=b
整数除法: a *=b整数除法,赋值:a //=b
__idiv__(self, other)带有赋值的除法:a /=b
赋值:a /=b __itruediv__(self, other)带赋值的真除法
__imod__(self, other)带赋值的模数:a%=b
赋值:a%=b __ipow__(self, other)带赋值的指数:a **=b
左移__(self, other)左位移位,赋值:a<<=b
__irshift__(self, other)右位移位,带有赋值:a >>=b
__iand__(self, other)带有赋值的位数和:a&=b
顺序__(self, other)位数OR,赋值为:**a=b**
值为:a=b。位数XOR,赋值为:a ^=b
类型转换它的作用是什么?
__int__(self)**int()**方法将一个类型转换为一个 int。
__float__(self)float() 方法将一个类型转换为 float。
方法将一个类型转换为复数compound() 方法将一个类型转换为复数。
方法将一个类型转换为复数oct() 方法将一个类型转换为八进制。
__hex__(self)hex() 方法将一个类型转换为十六进制。
__index__(self)当对象在分片表达式中使用时,执行类型转换为int
__trunc__(self)从数学中获得调用。**trunc()**方法
字符串魔法方法它的作用
__str__(self)str()方法,返回一个类型的字符串表示。
__repr__(self)repr()方法返回一个类型的机器可读表示。
方法返回类型的机器可读表示法unicode()方法返回一个类型的unicode字符串。
__format__(self, formatstr)string.format()方法,返回一个新的字符串样式。
方法返回一个新的字符串样式。hash()方法返回一个整数。
使用__nonzero__(self)bool() 方法,返回真或假。
__dir__(self)dir()方法,返回一个类的属性列表。
__sizeof__(self)sys.getsizeof()方法,返回一个对象的大小。
属性魔法方法它的作用
__getattr__(self, name)访问一个不存在的类的属性时被调用。
__setattr__(self, name, value)当给一个类的属性赋值时被调用。
当删除一个类的属性时,调用__delattr__(self, name)删除一个类的属性时被调用。
操作符魔法方法它的作用
__add__(self, other)使用**+**操作符进行添加操作。
__sub__(self, other)使用**-**运算符进行减法运算
__mul__(self, other**)**使用*****运算符进行乘法运算
使用运算符**__floordiv__(self, other)**地面除法操作,使用**//**操作符
__div__(self, other)除法运算,使用**/**操作符
__mod__(self, other)使用**%**运算符进行模数运算
__pow__(self, other[, modulo])使用******运算符来计算功率
__lt__(self, other)使用**<**操作符进行比较
__le__(self, other)使用**<=**操作符进行比较
__eq__(self, other)使用**==**运算符进行比较
使用__ne__(self, other)使用**!=**操作符进行比较
__ge__(self, other)使用**>=**运算符进行比较