zl程序教程

您现在的位置是:首页 >  Python

当前栏目

python魔法方法

2023-02-18 16:37:29 时间

在学习面向对象的时候,我们知道在 python 中有一类特殊的方法,叫做魔法方法,这种方法的特点如下:

  1. 方法定义的时候以两个下划线开头和两个下划线结尾:如__init____str____repr__
  2. 这类方法一般不需要我们手动调用,在满足某个条件的时候会自动调用,这个满足的条件我们可以成为调用时机

__str__()方法

这个类方法(str())主要的作用是在print(实例)的时候返回你指定的字符串,一般来说在定义类的时候不用重写这个方法的,但是在一些注重交互的模块类的编写上,可能会重写这个类。下面直接进入例子。

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

接下来我们实例化这个类,并打印这个实例。

A = Car('BNW')
print(A)

我们一般就能看到这样的结果:
<__main__.Car object at 0x000002B249DD4E20>
这个结果主要是告诉我们这个A是哪一个类(Car类),还有所在内存位置(0x000002B249DD4E20)
下面我们在Car类中重写__str__方法,再打印这个A,看看会有什么差别。

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

    def __str__(self) -> str:
        text = f'这是一辆车,名字是{self.name}'
        return text


A = Car('BNW')
print(A)
这是一辆车,名字是BNW

可以看到,这个时候print(实例),将会出现我们指定好的str内容。这就是__str__()方法的用处,不过要注意,这个方法必须要保证返回的是一个str。

对一个对象打印时,自动执行 str 方法

class A:

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.sex = "男"

    def __str__(self):
        print(555)
        return "abc"

a1 = A("尘世风", 18)
# 对一个对象打印时,自动执行 __str__ 方法
print(a1)
# 运行结果:
# 555
# abc

__len__()方法

len()可以检测对象中某个数据得信息,只有一个参数self,用于接收当前对象,它必须有返回值,返回值必须是整数;
当我们不使用__len__()方法检测对象时,会报TypeError: object of type ‘UseLen’ has no len()错误

class UseLen(object):
    def __init__(self, age):
        self.age = age
        self.li = ['a', 'v', 's']

U = UseLen(12)
print(len(U))
Traceback (most recent call last):
  File "D:\code\xmczapitest\test.py", line 7, in <module>
    print(len(U))
TypeError: object of type 'UseLen' has no len()

当我们使用__len__方法检测对象时,需要注意的是必须有返回值,方法中只有一个self参数

class UseLen(object):
    def __init__(self, age):
        self.age = age
        self.li = ['a', 'v', 's']

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

U = UseLen(12)
print(len(U))     # 2

__call__ 方法

__call__可以使得方法变成可被调用对象

class Foo:

    def __init__(self):
        print("实例化一个对象时自动执行 __init__ 方法")

    def __call__(self, *args, **kwargs):
        print('调用实例化对象时自动触发 __call__ 方法')


obj = Foo()     # 实例化一个对象时自动执行 __init__ 方法
obj()           # 调用实例化对象时自动触发 __call__ 方法

new() 方法

当Python实例化一个对象时,首先调用__new__()方法构造一个类的实例,并为其分配对应类型的内存空间,该实例的内存地址就是它的唯一标识符。然后再调用__init__()方法对实例进行初始化,通常是对该实例的属性进行初始化
以下用几个实例来说明:
实例1:先调用__new__()方法再调用__init__()方法

class Person(object):

    def __new__(cls):
        print("__new__ called")
        return super().__new__(cls)

    def __init__(self):
        print("__init__ called")


a = Person()

结果

__new__ called
__init__ called

实例2:new()方法构造一个类实例,并将该实例传递给自身的__init__()方法,即__init__()方法的self参数。

class Person(object):

    def __new__(cls):
        print("__new__ called")
        instance = super().__new__(cls)
        print(type(instance))
        print(instance)
        print(id(instance))
        return instance

    def __init__(self):
        print("__init__ called")
        print(id(self))


b = Person()

结果

__new__ called
<class '__main__.Person'>
<__main__.Person object at 0x0000026D76844DC0>
2669163072960
__init__ called
2669163072960

实例3:如果__new__()方法不返回任何实例的话,init()方法将不会被调用。

class Person(object):

    def __new__(cls):
        print("__new__ called")

    def __init__(self):
        print("__init__ called")


c = Person()

结果:

__new__ called

实例4:如果__new__()方法返回一个其他类的实例的话,那它自身的__init__()方法将不会被调用。而且,new()方法将会初始化一个其他类的对象。

class Animal(object):

    def __init__(self):
        pass


class Person(object):

    def __new__(cls):
        print("__new__ called")
        return Animal()

    def __init__(self):
        print("__init__ called")


d = Person()
print(type(d))
print(d)

结果:

__new__ called
<class '__main__.Animal'>
<__main__.Animal object at 0x0000022BDDEEF400>

实例5:如果重写__new__()方法时,除了cls参数外不再设置其他参数的话,将无法用__init__()方法来设置初始化参数。

class Person(object):

    def __new__(cls):
        print("__new__ called")
        instance = super().__new__(cls)
        return instance

    def __init__(self, name):
        print("__init__ called")
        self.name = name


e = Person("Alice")
print(e.name)  # TypeError: Person.__new__() takes 1 positional argument but 2 were given

实例6:在重写__new__()方法时,需要在参数中加入*args,**kwargs,或者显式地加入对应的参数,才能通过__init__()方法初始化参数。

class Person(object):

    def __new__(cls, *args,**kwargs):  # Or def __new__(cls, name)
        print("__new__ called")
        instance = super().__new__(cls)
        return instance

    def __init__(self, name):
        print("__init__ called")
        self.name = name


e = Person("Alice")
print(e.name)

结果:

__new__ called
__init__ called
Alice