Python魔力方法

发布时间 2023-03-30 22:55:28作者: 我不知道取什么名字好

Python的魔术方法(Magic Methods)也称为双下划线方法(double underscore method),以双下划线开头和结尾,用于重载类的特殊行为。可以使类的实例对象表现出像内置类型的行为,如加、减、乘、切片、比较等,增加代码的可读性和可维护性。以下是Python中一些重要的魔术方法:

1.__init__方法

__init__(self[, ...])方法在创建类的实例对象时自动调用,用于进行初始化操作,为实例对象的属性设置初始值。其中,self代表实例对象本身。此外,__new__方法在创建类的实例对象之前被调用,可以用来进行一些定制化的操作。

示例:

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

obj = MyClass("Tom")
print(obj.name)  # 输出 Tom

2.__call__方法

__call__(self[, ...])方法使得对象可以像函数一样被调用,用于对实例对象添加可调用特性。一般情况下,Python中的函数即对象,而__call__方法可以让实例对象也表现得像函数。

示例:

class MyClass:
    def __call__(self):
        print("Hello, I can be called like a function.")

obj = MyClass()
obj()  # 输出:Hello, I can be called like a function.

3.__str____repr__方法

__str__(self)方法返回一个字符串,用于自定义实例对象的字符串输出格式。__repr__(self)方法也返回一个字符串,表示对实例对象进行计算或操作的表达式或字符串,通常被用于调试和日志输出。

示例:

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

    def __str__(self):
        return f"{self.name}, {self.age} years old."

    def __repr__(self):
        return f"Person(name={self.name}, age={self.age})"

p = Person("Tom", 18)
print(str(p))  # 输出:Tom, 18 years old.
print(repr(p))  # 输出:Person(name=Tom, age=18)

4.__add____sub____mul____div__(加减乘除)

__add__(self, other)方法表示“加”,用于定义对象的加法行为,self代表第一个加数,other代表第二个加数。类似的,有__sub____mul____div__等方法表示减、乘、除等。

示例:

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

    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    def __str__(self):
        return f"({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 输出:(4, 6)

5.__len__方法

__len__(self)方法用于定义实例对象的长度,返回一个整数,即对象中元素的数量。常用于定制容器类型的大小。

示例:

class MyClass:
    def __init__(self, lst=None):
        self.lst = lst

    def __len__(self):
        return len(self.lst)

obj = MyClass([1, 2, 3])
print(len(obj))  # 输出:3

6.__getitem____setitem____delitem__方法

__getitem__(self, key)方法和__setitem__(self, key, value)方法定义了实例对象的索引和切片功能,__delitem__(self, key)方法用于实现删除操作。其中,key表示索引或切片范围,value表示要赋值的值。

示例:

class MyList:
    def __init__(self, lst=None):
        self.lst = lst if lst else []

    def __getitem__(self, index):
        return self.lst[index]

    def __setitem__(self, index, value):
        self.lst[index] = value

    def __delitem__(self, index):
        del self.lst[index]

    def __len__(self):
        return len(self.lst)

lst = MyList([1, 2, 3])
print(lst[1])   # 输出:2
lst[1] = 5
print(lst[1])   # 输出:5
del lst[0]
print(len(lst))  # 输出:2

7.__iter____next__方法

__iter__(self)方法返回一个可迭代对象,用于定义实例对象的迭代行为。__next__(self)方法用于定义实例对象的下一个元素是什么,具体包括迭代开始、迭代状态以及迭代结束时所需的返回值。

示例:

class Fibonacci:
    def __init__(self, n):
        self.n = n
        self.current = 0
        self.next = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current + self.next > self.n:
            raise StopIteration
        self.current, self.next = self.next, self.current + self.next
        return self.current

for i in Fibonacci(100): 
    print(i, end=' ')  # 输出:1 1 2 3 5 8 13 21 34 55 89

8.__getattr____setattr__方法

__getattr__(self, attr)方法用于获取实例对象的属性,当代码中使用了实例对象没有的属性时,该方法会被调用,如果没有定义该方法,则会抛出AttributeError异常。__setattr__(self, attr, value)方法用于设置实例对象的属性,当代码中设置实例对象没有的属性时,该方法会被调用。

示例:

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

    def __getattr__(self, attr):
        return f"{attr} 属性不存在。"

    def __setattr__(self, attr, value):
        if attr == "name":
            self.__dict__[attr] = value.upper()
        else:
            self.__dict__[attr] = value

obj = MyClass("Tom")
print(obj.name)  # 输出:TOM
print(obj.age)   # 输出:age 属性不存在。

9.__enter____exit__方法

__enter__(self)方法会在进入with语句时被调用,用于进行一些初始化操作,同时该方法需要返回一个上下文管理器对象。__exit__(self, exc_type, exc_value, traceback)方法会在离开with语句时被调用,用于进行一些清理操作。

示例:

class File:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.f = open(self.filename, "r")
        return self.f

    def __exit__(self, exc_type, exc_value, traceback):
        self.f.close()

with File("test.txt") as f:
    content = f.read()
    print(content)

10.__eq____lt____le__等比较方法

__eq__(self, other)方法用于定义等于运算符==__lt__(self, other)__le__(self, other)__gt__(self, other)__ge__(self, other)方法分别用于定义小于、小于等于、大于、大于等于运算符。

示例:

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

    def __eq__(self, other):
        return self.age == other.age

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

p1 = Person("Tom", 18)
p2 = Person("Jerry", 20)
print(p1 == p2)  # 输出:False
print(p1 < p2)   # 输出:True

11.__hash____call__方法

__hash__(self)方法定义了实例对象的hash值,通常用于优化字典、集合等操作。__call__(self)方法定义了实例对象的调用过程,用于将实例对象作为函数调用时的行为。

示例:

class MyClass:
    def __init__(self, attr):
        self.attr = attr

    def __hash__(self):
        return hash(self.attr)

    def __call__(self):
        print(f"The attribute is {self.attr}.")

obj1 = MyClass(1)
obj2 = MyClass(2)
print(hash(obj1))  # 输出:1
print(hash(obj2))  # 输出:2

obj1()  # 输出:The attribute is 1.

12.__format__方法

__format__(self, format_spec)方法用于自定义实例对象的格式化,其中format_spec为格式化字符串。

示例:

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

    def __format__(self, format_spec):
        if format_spec == "r":
            return f"({self.y}, {self.x})"
        else:
            return f"({self.x}, {self.y})"

p = Point(1, 2)
print(format(p))    # 输出:(1, 2)
print(format(p, "r"))  # 输出:(2, 1)

13.__dir__方法

__dir__(self)方法用于自定义类的dir()函数返回的属性列表,默认情况下会返回类的所有属性和方法,包括从父类继承的。

示例:

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

    def foo(self):
        pass

    def __dir__(self):
        return [attr for attr in dir(self.__class__) if not attr.startswith("__")]

obj = MyClass("Tom")
print(dir(obj))  # 输出:['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo', 'name']

在上述示例中,__dir__方法返回了类的所有属性和方法,但排除了以__开头的魔术方法。

14.__init_subclass__方法

__init_subclass__(cls, **kwargs)方法在每个子类被创建时被调用,通常用于对子类进行初始化或配置。

示例:

class BaseClass:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        print(f"Creating subclass {cls.__name__}")

class SubClass1(BaseClass):
    pass

class SubClass2(BaseClass):
    pass

# 输出:Creating subclass SubClass1
#       Creating subclass SubClass2

在上述示例中,当子类SubClass1SubClass2被创建时,会自动调用__init_subclass__方法,并输出相应的信息。

15.__set_name__方法

__set_name__(self, owner, name)方法在类的属性被设置时被调用,通常用于对属性进行验证或初始化。注意,该方法只在 Python 3.6 及以上版本中可用。

示例:

class Validator:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, owner):
        return obj.__dict__[self.name]

    def __set__(self, obj, value):
        if value < 0:
            raise ValueError(f"{self.name} should be greater than 0.")
        obj.__dict__[self.name] = value

class MyClass:
    x = Validator()

obj = MyClass()
obj.x = 1
print(obj.x)  # 输出:1
obj.x = -1   # 抛出 ValueError 异常

在上述示例中,Validator类的__set_name__方法会将属性名保存在name属性中,然后通过__get____set__方法对属性进行访问和设置。这里通过设置x属性来演示__set_name__方法的应用,如果设置的值小于 0,则抛出ValueError异常。

16.__new__方法

__new__(cls, *args, **kwargs)方法是一个特殊的静态方法,用于创建类的实例对象,通常用于自定义类的实例化过程。该方法会返回创建的新实例对象,然后调用__init__方法进行初始化。

示例:

class Singleton:
    instance = None

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls, *args, **kwargs)
            return cls.instance
        else:
            return cls.instance

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

obj1 = Singleton("Tom")
obj2 = Singleton("Jerry")
print(obj1 == obj2)  # 输出:True
print(obj1.name)     # 输出:Tom
print(obj2.name)     # 输出:Tom

在上述示例中,Singleton类通过重写__new__方法,实现了单例模式,保证每次实例化时返回的都是同一个实例对象。