Python

Python 魔术方法

2021-01-31  本文已影响0人  星光下的胖子
You'll miss 100% of shots you don't take.

一、魔术方法简介

Python 中所有以双下划线“__”包起来的方法,统称为“Magic Method”(魔术方法)

魔术方式是 Python 的内置方法,不需要主动调用,当我们对实例调用某些特定函数或运算符时,会自动触发。例如最常见的 __new____init__:当调用 p = Person() 时,首先触发 __new__ 创建一个 instance 并返回,然后触发 __init__ 用传入的参数对 instance 进行初始化。

Python 的魔术方法有很多,下面介绍一些常见的魔术方法。

二、常见的魔术方法及代码示例

1.实例生命周期、允许实例像函数一样被调用
__new__(cls)、__init__(self):创建实例、实例初始化的时候触发
__del__(self):销毁实例的时候触发
__call__(self):实例像函数一样被调用时触发

代码示例:

class Person(object):
    def __new__(cls, name, age, city="beijing"):
        print('__new__()方法,"创建实例"时触发。')
        instance = super(Person, cls).__new__(cls)
        # instance = object.__new__()
        print(instance, id(instance))
        return instance

    def __init__(self, name, age, city="beijing"):
        print('__init__()方法,"初始化实例"时触发。')
        # __init__()的输入参数self,就是__new__()的返回值instance
        print(self, id(self))
        self.name = name
        self.age = age
        self.city = city

    # 普通方法
    def cook(self, menu):
        print('这是一个普通函数:cook()')
        print(f"{self.name}正在煮{menu}...")

    def __call__(self, course):
        print('__call__()方法,"实例像函数一样被调用"时触发。')
        print(f"{self.name}正在自习室学习{course}...")

    def __del__(self):
        print('__del__()方法,"实例销毁"时触发。')


# 先触发__new__()创建一个instance,然后自动调用__init__()对实例进行初始化
p = Person('Tom', 16, city='shanghai')
print("----------")
p.cook('coffee')  # 调用普通函数
print("----------")
p('Maths')  # 允许实例像函数一样被调用,触发__call__()方法
print("----------")
del p  # 实例被销毁,触发__del__()方法

运行结果:

__new__()方法,"创建实例"时触发。
<__main__.Person object at 0x104001c90> 4362083472
__init__()方法,"初始化实例"时触发。
<__main__.Person object at 0x104001c90> 4362083472
----------
这是一个普通函数:cook()
Tom正在煮coffee...
----------
__call__()方法,"实例像函数一样被调用"时触发。
Tom正在自习室学习Maths...
----------
__del__()方法,"实例销毁"时触发。
2.实例的比较
__eq__(self, other):定义相等符号的行为,==
__ne__(self, other):定义不等符号的行为,!=
__lt__(self, other):定义小于符号的行为,<
__gt__(self, other):定义大于符号的行为,>
__le__(self, other):定义小于等于符号的行为,<=
__ge__(self, other):定义大于等于符号的行为,>=

代码示例:

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        print('实例比较"=="时触发__eq__()')
        return self.age == other.age

    def __ne__(self, other):
        print('实例比较"!="时触发__ne__()')
        return self.age != other.age

    def __gt__(self, other):
        print('实例比较">"时触发__gt__()')
        return self.age > other.age

    def __lt__(self, other):
        print('实例比较"<"时触发__lt__()')
        return self.age < other.age

    def __ge__(self, other):
        print('实例比较"<="时触发__ge__()')
        return self.age >= other.age

    def __le__(self, other):
        print('实例比较"<="时触发__le__()')
        return self.age <= other.age


p1, p2 = Person('Tom', 16), Person("Json", 16)
print(p1 == p2)  # 触发__eq__()
print("----------")
print(p1 != p2)  # 触发__ne__()
print("----------")
print(p1 > p2)  # 触发__gt__()
print("----------")
print(p1 < p2)  # 触发__lt__()
print("----------")
print(p1 >= p2)  # 触发__ge__()
print("----------")
print(p1 <= p2)  # 触发__le__()

运行结果:

实例比较"=="时触发__eq__()
True
----------
实例比较"!="时触发__ne__()
False
----------
实例比较">"时触发__gt__()
False
----------
实例比较"<"时触发__lt__()
False
----------
实例比较"<="时触发__ge__()
True
----------
实例比较"<="时触发__le__()
True
3.容器相关
__len__(self):len(instance)时触发
__getitem__(self, key):instance[key]时触发
__setitem__(self, key, value):instance[key]=value时触发
__delitem__(self, key, value):del instance[key]时触发

代码示例:

class Book(object):
    def __init__(self, title, page_size=100):
        self.title = title
        self.page_size = page_size
        self.li = [10, 20, 30]

    def __len__(self):
        print('调用"len(instance)"时触发__len__()方法')
        return self.page_size

    def __getitem__(self, item):
        print('"调用instance[key]"时触发__getitem__()方法')
        return self.li[item]

    def __setitem__(self, key, value):
        print('"调用instance[key]=value"时触发__setitem__()方法')
        self.li[key] = value

    def __delitem__(self, key):
        print('"调用del instance[key]"时触发__delitem__()方法')
        del self.li[key]


book = Book('maths', page_size=288)
print("这本书的页数:", len(book))  # 触发__len__()方法
print("----------")
print(book[0])  # 触发__getitem__()
print("----------")
print("before book.li:", book.li)
book[0] = 8  # 触发__setitem__()方法
print("middle book.li:", book.li)
print("----------")
del book[0]  # 触发__delitem__()
print("finally book.li:", book.li)

运行结果:

调用"len(instance)"时触发__len__()方法
这本书的页数: 288
----------
"调用instance[key]"时触发__getitem__()方法
10
----------
before book.li: [10, 20, 30]
"调用instance[key]=value"时触发__setitem__()方法
middle book.li: [8, 20, 30]
----------
"调用del instance[key]"时触发__delitem__()方法
finally book.li: [20, 30]
4.迭代器
定义一个迭代器,需实现__iter__()和__next__()。
__iter__(self):调用iter(instance)时触发,返回一个迭代器
__next__(self):调用next(instance)时或对instance进行迭代时触发

代码示例:

# 自定义迭代器
class MyIter(object):
    def __init__(self, total, start=0):
        self.total = total
        self.start = start

    def __iter__(self):
        print('"调用iter(instance)"时触发__iter__()')
        return self

    def __next__(self):
        print('"调用next(instance)"时触发__next__()')
        if self.start < self.total:
            self.start += 1
            return self.start
        else:
            raise StopIteration


myIter = MyIter(5)
print(next(myIter))  # 触发__next__()
print("----------")
it = iter(myIter)  # 触发__iter__()
print("----------")
print(next(it))  # 触发__next__()
print("----------")
for value in it:  # 进行迭代操作,触发__next__()
    print(value)

运行结果:

"调用next(instance)"时触发__next__()
1
----------
"调用iter(instance)"时触发__iter__()
----------
"调用next(instance)"时触发__next__()
2
----------
"调用iter(instance)"时触发__iter__()
"调用next(instance)"时触发__next__()
3
"调用next(instance)"时触发__next__()
4
"调用next(instance)"时触发__next__()
5
"调用next(instance)"时触发__next__()
上一篇下一篇

猜你喜欢

热点阅读