AI智能
改变未来

『无为则无心』Python面向对象 — 59、魔法方法

[toc]

在Python语言中,有些方法名比较特别,在名称的前后各有两个下划线,这样的方法往往具有特殊的意义,我们统称为魔法方法,也叫特殊方法。需要注意的是,我们在创建自定义方法时要避免这样的格式,防止造成不必要的冲突。

Python的魔法方法有很多,我们主要介绍常用的几个魔法方法。以后需要用到其他的魔法方法,按照介绍的这几个调用方式,自己尝试一下就可以了,很简单的。

1、魔法方法

__new__()

类的实例化时,调用的第一个方法是

__new__

方法。官方定义如下,可以看到

__new__

被定义成静态方法,第一个必须传入的参数是

cls

,代表需要实例化的类。

class Demo():def __new__(cls, *args, **kwargs):print(\'调用__new__方法\')def __init__(self):print(\'调用__init__方法\')# 结果:调用__new__方法d = Demo()

从结果看到,只调用了

__new__

方法,但奇怪的是并没有调用

__init__

方法,这是为什么呢?

实际上,

__new__

是负责对当前类进行实例化,并将实例返回,传给

__init__

方法。

__init__

方法中的

self

就是指代

__new__

传过来的对象,所以再次强调,

__init__

是实例化后调用的第一个方法。

只有

__new__

方法返回创建的实例对象,后边的

__init__

方法才能执行。

class Demo:def __new__(cls, *args, **kwargs):print(\'调用__new__方法\')return object.__new__(cls)def __init__(self):print(\'调用__init__方法\')# 创建对象d = Demo()"""输出结果:调用__new__方法调用__init__方法"""

总结:

__new__()

方法是一个魔法方法(同时也是一种静态方法),用于创建一个类的实例,返回一个类的实例对象,用于传入初始化方法

__init__()

方法中。一般并不需要对其进行声明和重写,若是重写的话,需要注意返回一个有效的类的实例对象,实例通过

object

父类调用类的实例化方法,用于返回一个对象实例。若是不返回一个类的实例对象,会导致类的

__init__()

方法不会被调用,当然实例(

self

为空)也不会被成功创建。

2、魔法方法

__init__()

__init__

方法是类创建过程中用的比较多的魔法方法,是类对象创建后调用的初始化方法,紧跟者

__new__

方法后调用,主要用于实例变量的初始化操作。

__init__

方法可以理解为一个类的实例的构造器,其方法的特点是不会返回任何对象或者值,若返回则会抛出

TypeError

异常。

(1)体验

__init__()

思考:洗衣机的宽度高度是与生俱来的属性,可不可以在生产过程中就赋予这些属性呢?

答:理应如此。

__init__()

方法的作用:初始化对象。

示例:

"""目标: 定义init方法设置初始化属性并访问调用1. 定义类init方法: width 和 height添加实例方法:访问实例属性2. 创建对象3. 验证成果调用实例方法"""# 1.定义类class Washer():# 定义初始化功能的函数def __init__(self):# 添加实例属性self.width = 500self.height = 800def print_info(self):# 类里面调用实例属性print(f\'洗衣机的宽度是{self.width}, 高度是{self.height}\')# 2. 创建对象haier1 = Washer()# 3. 调用实例方法haier1.print_info()

注意:

  • __init__()

    方法,在创建一个对象时默认被调用,不需要手动调用。

  • __init__(self)

    中的self参数,不需要开发者传递,Python解释器会自动把当前的对象引用传递过去。

(2)带参数的

__init__()

思考:一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢?

答:传参数。

# 定义类class Washer():# 定义带参数的init方法def __init__(self, width, height):self.width = widthself.height = height# 定义实例方法def print_info(self):# 调用实例属性print(f\'洗衣机的宽度是{self.width}\')print(f\'洗衣机的高度是{self.height}\')haier1 = Washer(10, 20)haier1.print_info()# 如果创建对象的时候不传递参数,会报错。# haier2 = Washer()haier2 = Washer(100, 200)haier2.print_info()

图解如下:

3、魔法方法

__del__()

当删除对象时,Python解释器也会默认调用

__del__()

方法。

__del__()

方法属于析构函数。

__del__()

方法不会被主动调用,只有当类的实例对象的引用计数为0时,才会被调用,一般不建议重写

__del__()

方法。

示例

class Washer():def __init__(self, width, height):self.width = widthself.height = heightdef __del__(self):print(f\'{self}对象已经被删除\')haier1 = Washer(10, 20)# <__main__.Washer object at 0x0000026118223278>对象已经被删除del haier1

即便不手动删除对象,也能调用到

__del__()

方法,也就上面示例中,不编写最后

del haier1

语句,当Python程序执行完成后,也会打印一样的结果,是Python解释器自动调用的。

4、魔法方法

__str__()

__repr__()

  • Python 定义了

    __str__()

    __repr__()

    两种方法,

    __str__()

    用于显示给用户,而

    __repr__()

    用于显示给开发人员。

  • __str__

    方法默认情况下,它会返回当前对象的

    类名+object at+内存地址

    。如下:

    <__main__.Students object at 0x0000000002443808>
  • 有时候想让屏幕打印的结果不是对象的内存地址,而是它的形式的字符串,以便更直观地显示对象内容,可以通过在该对象的类中重写

    __str__()

    __repr__()

    方法来实现。

  • 注意:

    __str__()

    方法和

    __repr__()

    方法的返回值只能是字符串!

(1)关于调用两种方法的时机

以下三种场景中,会优先调用对象的

__str__()

方法。若没有,就调用

__repr__()

方法。若再没有,则显示其内存地址。

  • 使用
    print()

    时。

  • 使用
    %s

    f\'{}\'

    拼接对象时。

  • 使用
    str(x)

    转换对象x时。

对于下面两种场景:

  • %r

    进行字符串拼接时。

  • repr(x)

    转换对象x时。

则会调用这个对象的

__repr__()

方法。若没有,则不再看其是否有

__str__()

方法。若再没有,则显示其内存地址。

(2)示例

__str__

方法一般放置的是一些解释说明的文字。

示例:

class Washer():def __init__(self, width, height):self.width = widthself.height = heightdef __str__(self):# return repr(\'这是海尔洗衣机的说明书\')return \'这是海尔洗衣机的说明书\'# __repr__方法在实际工作总一般如下使用__repr__ = __str__haier1 = Washer(10, 20)# 结果:这是海尔洗衣机的说明书print(haier1)

5、魔法方法

__call__()

对象后面加括号,触发执行。

提示:

  • __init__

    方法的执行是由创建对象触发的,即:

    对象 = 类名()

  • 而对于
    __call__

    方法的执行是由对象后加括号触发的,即:

    对象()

    或者

    类()()

示例:

class Person(object):def __init__(self):print("__init__方法执行了")def __call__(self, *args, **kwargs):print("__call__方法中执行了")# 1.对象 = 类名()p = Person()  # 执行__init__# 2.对象() 调用__call__方法p()# 3.类()() 调用__call__方法Person()()  # 执行__call__

提示:这个方法在工作中的应用自己以后总结,先知道怎么用就好。

6、魔法方法

__len__()

__len__()

方法在

list

dict

set

tuple

str

等序列中都存在,而在

int

float

类中是不存在的。

print(\'__len__\' in dir(int))  # Falseprint(\'__len__\' in dir(float))  # Falseprint(\'__len__\' in dir(str))  # Trueprint(\'__len__\' in dir(list))  # Trueprint(\'__len__\' in dir(tuple))  # Trueprint(\'__len__\' in dir(dict))  # Trueprint(\'__len__\' in dir(set))   # True

如果一个类要表现得像一个

list

一样,有需求要获取有多少个元素,就得用

len()

函数。

要让

len()

函数工作正常,类中就必须提供一个魔法方法

__len__()

方法,它的作用是返回元素的个数。

示例:

# 定义一个类,接收同学名的名字class Students(object):def __init__(self, *args):self.names = argsdef __len__(self):return len(self.names)stu = Students(\'唐僧\', \'孙悟空\', \'猪八戒\', \'沙和尚\')print(len(stu))  # 4print(stu.__len__())  # 4

提示:只要在类中正确实现了

__len__()

方法,就可以用

len()

函数。

7、魔法方法

__getitem__()

__setitem__()

__delitem__()

在Python中,如果我们想实现创建类似于序列和映射的类,可以通过重写魔法方法

__getitem__()

方法、

__setitem__()

方法、

__delitem__()

方法去模拟。

示例:

class MyDict(object):def __init__(self):self.item = {}# 获取成员def __getitem__(self, key):return self.item.get(key)# 添加成员def __setitem__(self, key, value):self.item[key] = value# 删除成员def __delitem__(self, key):del self.item[key]# 获取人员数量def __len__(self):return len(self.item)if __name__ == "__main__":# 创建序列对象myDict = MyDict()# 添加元素myDict.__setitem__(\'师傅\', \'唐憎\')myDict.__setitem__(\'大师兄\', \'孙悟空\')# 查看刚添加的成员print(myDict.__getitem__(\'大师兄\'))print(f"现在成员{len(myDict)}人", )  # 2# 修改成员myDict.__setitem__(\'大师兄\', \'齐天大圣\')print(myDict.__getitem__(\'大师兄\'))print(f"现在成员{len(myDict)}人", )  # 2# 删除元素myDict.__delitem__(\'师傅\')print(f"现在成员{len(myDict)}人", )  # 1"""输出结果:孙悟空现在成员2人齐天大圣现在成员2人现在成员1人"""

参考:

  • https://www.cnblogs.com/woniuxy/p/11507648.html
  • https://blog.csdn.net/chf1142152101/java/article/details/78715296
  • https://www.cnblogs.com/oddgod/p/10992366.html
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 『无为则无心』Python面向对象 — 59、魔法方法