Python常见的魔术方法和魔术属性(一)

简介: Python常见的魔术方法和魔术属性(一)

魔术方法

Python的魔术方法(也称为特殊方法)是对象的一些特殊方法,它们都是以双下划线开头并以双下划线结尾,例如__init__。

魔术方法所体现的设计思想是构成python风格的重要组成部分。

它们的目的是让对象能够响应内置的运算符或函数,比如len(),+运算符等。例如,当我们使用len(obj)函数调用对象obj的长度时,实际上会调用对象的__len__方法。

1、 __new__ 魔术方法

触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定。cls是系统自动传递的。类名字随意
返回值:通常返回对象 或 None

创建对象时可以选择给或者不给

(1) 基本使用

class MyClass2():
    a = 100
obj2 = MyClass2()
#print(obj2)

一般情况下,通过类创建对象,默认返回类对象。是借助其默认继承的父类object创建的。如果我们想自己控制对象的创建,要通过__new__

自己控制创建对象,使用__new__魔术方法。但要写返回值,不然创建的对象为None

class MyClass1():
    def __new__(cls):
        # print(cls)        
        # 1.返回本类对象
        """类.成员方法(类)"""
        # return object.__new__(cls)
        # 2.返回其他类的对象
        # return obj2
        # 3.不返回对象,None
        return None        
    
obj = MyClass1()
#print(obj.a)
print(obj)


__new__传参,传类本身

#通过父类调用方法返回,这是默认情况下,借助父类创建的对象

返回其它类对象,可以直接调用其它类成员

#不返回对象,None

可以严格控制创建对象的过程

(2) __new__ 触发时机要快于 __init__

__new__ 创建对象

__init__ 初始化对象

先创建,再初始化

class MyClass():

    def __new__(cls):
        print(1)
        return object.__new__(cls)

    def __init__(self):
        print(2)
    
obj = MyClass()    

#__new__触发时机快于__init__,如下,虽然__init__定义早于__new__。但创建对象的时候,执行顺序还是先执行__new__
定义谁在前谁在后,没影响,关键在调用处,谁先谁后。系统默认调用的。由此可见__new__优先调用,触发时机快于__init__

(3) __new__的参数要和__init__参数一一对应。参数个数一致就行

class Boat():
    def __new__(cls,name):
        return object.__new__(cls)
    
    def __init__(self,name):
        self.name  = name

obj = Boat("万里阳光号")
print(obj.name)

参数个数不一致会报错

其实传给__new__的参数也没用上,要是船的参数比较多,这样一一对应比较麻烦。我们可以使用收集参数进行改造

这样,不管初始化多少参数,__new__都可以接收

#使用收集参数进行改造

class Boat():
    # *args,**kwargs 可以收集多余的所有参数
    def __new__(cls,*args,**kwargs):
        return object.__new__(cls)
    
    def __init__(self,name,type):
        self.name  = name
        self.type = type

obj = Boat("万里阳光号","破木头做的")
print(obj.name , obj.type)

(4) __new____init__之间的注意点

如果__new__ 没有返回对象,或者返回的是其他类的对象,不会调用构造方法.
只有在返回自己本类对象的时候,才会调用构造方法.

class Children():
    def __new__(cls,*args,**kwargs):
        return obj2
        # pass
        
    def __init__(self,name,skin):
        print("构造方法被触发 ... ")
        # self.name = name
        # self.skin = skin
        
obj = Children("灭霸","紫薯")

# print(obj.name) error
# print(obj.skin) error

如果__new__什么也不返回,那返回的是None。此时该类的构造方法也不会被调用。构造不会被触发。对象都没被创建,无法初始化

如果__new__方法返回其他对象,则构造函数不会被调用。其实此时对象找的是被返回对象类里面的该成员

如果被返回的对象,类里面有name成员,那么将被正常打印。虽然是通过此类创建的对象,但由于__new__返回的是其他类的对象,实际上创建的是其他类的对象

2、 单态模式 : 同一个类,无论实例化多少次,都有且只有一个对象

每创建一个对象,就会在内存中多占用一份空间

为了节省空间,提升执行效率,使用单态模式

场景:只是单纯调用类中的成员,而不会额外为当前对象添加成员;

一般__new__方法大多数出现在单态模式

单态适用于对数据库操作,用一个对象解决不同的问题。节省空间

class Singleton():
    __obj = None
    def __new__(cls):
        if cls.__obj is None:
            cls.__obj = object.__new__(cls)
        return cls.__obj

给类设置私有属性,公有属性都可以。但一般设置为私有,因为设置公有的话,可以通过类来获取到,但获取到的为None。所以设置为私有,只能通过实例化之后调用

通过__new__方法创建对象之前,先判断一下,如果对象存在就将原对象返回,不存在再创建

调用属性,要么通过 类.属性 要么通过 对象.属性 不能直接调属性,否则报错 如下 cls.obj是通过类调 cls是__new__方法传参的传的类

如下所示,使用单态模式,两次创建的对象是同一个内存地址。而正常的类创建两个对象,内存地址不同,开辟了两个内存空间

由此可见,单态模式节省内存空间

“”"

第一次,在实例化对象时触发__new__魔术方法

if cls.__obj is None 条件成立 cls.__obj = object.__new__(cls) 创建一个对象给私有成员属性__obj

return cls.__obj 用obj1接收到了对象

第二次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象

return cls.__obj

第三次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象

return cls.__obj

“”"

obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
print(obj1,obj2,obj3)

这样无论实例化多少次对象,有且只有第一次创建的一个对象

class Singleton():
    __obj = None
    def __new__(cls,*args,**kwargs):
        if cls.__obj is None:
            cls.__obj = object.__new__(cls)
        return cls.__obj
        
    def __init__(self,name):
        self.name = name

obj1 = Singleton("康玉康")
obj2 = Singleton("张保张")
print(obj1,obj2)
print(obj1.name)
print(obj2.name)

“”"

康玉康 康玉康

康玉康 张保张

张保张 张保张

第一次实例化对象时,

触发__new__ if cls.__obj is None: 创建一个新的对象进行返回

然后触发__init__ self.name = 康玉康

第二次实例化对象时

触发__new__ if cls.__obj is None: 条件不满足,返回的是第一次实例化的对象,是同一个

然后触发__init__ self.name = 张保张

“”"

name = "康裕康"
name = "张保障"
print(name)

名义上创建不同对象,实际上返回的是第一个对象,但是每次创建时都可以调用构造方法,根据传参不同,得到不同的执行结果

但要是多次实例化对象后再打印,对象是第一次实例化的,虽然后面返回的是第一次实例化的对象,但构造函数每次都执行,再打印成员属性时,是最后一次执行构造函数的结果。

3、 __del__ 魔术方法(析构方法)

触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
    功能:对象使用完毕后资源回收
参数:一个self接收对象
返回值:无

(1) 基本语法

class Lion():
    def __init__(self,name):
        self.name = name
        
    def __del__(self):
        print("析构方法被触发 ... ")

# 触发方式一: 页面执行完毕回收所有变量
obj1 = Lion("辛巴")

#触发方式二: 所有对象被del的时候
obj2 = obj1
obj3 = obj1
print(obj2 , obj1 ,obj3)
print("<====start===>")
del obj1
del obj2
del obj3
print("<====end===>")

所有对象被删除时触发,而不是页面走完才触发

如果不是所有对象被删除,则到页面执行结束时触发

本质上都是对象全部释放的时候触发

析构方法综合运用

(2) 模拟文件操作

import os
class ReadFile():
    # 根据文件是否存在,创建对象
    def __new__(cls,filename):
        if os.path.exists(filename):
            return object.__new__(cls)
        else:
            print("抱歉,没有这个文件")
    
    # 打开文件
    def __init__(self,filename):
        self.fp = open(filename,mode="r",encoding="utf-8")
        
    # 关闭文件
    def __del__(self):
        self.fp.close()
        
    # 读取文件
    def readcontent(self):
        return self.fp.read()
        

obj = ReadFile("0.py")
print(obj.readcontent())

4、 __str__ 魔术方法

触发时机: 使用print(对象)或者str(对象)的时候触发
功能:     查看对象
参数:     一个self接受当前对象
返回值:   必须返回字符串类型

如果定义了__str__方法,但没有返回字符串,或者无返回值,则会报错。必须返回字符串

class Cat():
    gift = "抓老鼠"
    def __init__(self,name):
        self.name = name
        
    def cat_gift(self):
        return "小猫叫{},小猫会{}".format(self.name,self.gift)
    
    def __str__(self):
        return self.cat_gift()    

    __repr__ = __str__
    
tom = Cat("汤姆")
# 触发时机1 :  print(对象)
# print(tom)

定义了__str__方法。当打印对象时,会将__str__方法返回的内容打印出来

#触发时机2 : str(对象)

res = str(tom)
print(res)

print("<==================>")
res = repr(tom)
print(res , type(res))
print("<==================>")

5、__repr__ 魔术方法

触发时机: 使用repr(对象)的时候触发
功能:     查看对象,与魔术方法__str__相似
参数:     一个self接受当前对象
返回值:   必须返回字符串类型
class Mouse():
    gift = "偷油吃"
    def __init__(self,name):
        self.name = name
    
    def mouse_gift(self):
        return "老鼠叫{},老鼠会{}".format(self.name,self.gift)
    
    def __repr__(self):
        return self.mouse_gift()
    
    # 系统底层默认把__repr__方法赋值给__str__方法,所以通过print或者str强转可以触发;
    # __str__ = __repr__
    
jerry = Mouse("杰瑞")
# res = repr(jerry)
# print(res)

# 可以触发
# print(jerry)
res = str(jerry)
print(res)

如果写了__str__ 。想实现__repr__方法,必须将__str__赋值给__repr__。因为这个方向,系统默认没写

手动将__str__赋值给__repr__ 就可以了


Python常见的魔术方法和魔术属性(二):https://developer.aliyun.com/article/1495785

相关文章
|
5天前
|
存储 数据处理 Python
Python如何显示对象的某个属性的所有值
本文介绍了如何在Python中使用`getattr`和`hasattr`函数来访问和检查对象的属性。通过这些工具,可以轻松遍历对象列表并提取特定属性的所有值,适用于数据处理和分析任务。示例包括获取对象列表中所有书籍的作者和检查动物对象的名称属性。
16 2
|
2月前
|
索引 Python
python-类属性操作
【10月更文挑战第11天】 python类属性操作列举
26 1
|
3月前
|
存储 API 索引
让 Python 的属性查找具有 C 一级的性能
让 Python 的属性查找具有 C 一级的性能
19 0
|
3月前
|
Python
Python中类属性与实例属性的区别
了解这些区别对于编写高效、易维护的Python代码至关重要。正确地使用类属性和实例属性不仅能帮助我们更好地组织代码,还能提高代码运行的效率。
39 0
|
3月前
|
Python
Python类中属性和方法区分3-8
Python类中属性和方法区分3-8
|
18天前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
17天前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
5天前
|
Unix Linux 程序员
[oeasy]python053_学编程为什么从hello_world_开始
视频介绍了“Hello World”程序的由来及其在编程中的重要性。从贝尔实验室诞生的Unix系统和C语言说起,讲述了“Hello World”作为经典示例的起源和流传过程。文章还探讨了C语言对其他编程语言的影响,以及它在系统编程中的地位。最后总结了“Hello World”、print、小括号和双引号等编程概念的来源。
98 80
|
24天前
|
存储 索引 Python
Python编程数据结构的深入理解
深入理解 Python 中的数据结构是提高编程能力的重要途径。通过合理选择和使用数据结构,可以提高程序的效率和质量
134 59
|
4天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
24 2