Python学习之-魔术方法

news2024/11/17 12:50:22

前言:

Python 中的魔术方法(Magic Methods),也称作特殊方法(Special Methods),是那些被双下划线包围的方法,例如 init。这些方法在 Python 中有特殊的含义,它们并不需要直接调用,而是在特定的情境下自动触发。通过定义或重写这些方法,可以自定义对象的行为,包括迭代、函数调用、属性访问等多种操作。

1.基本的魔术方法

在这里插入图片描述

1.1 有关属性

在这里插入图片描述

2 常见的几个魔术方法:

2.1 对象初始化:init(self[, …])

__init__我们很熟悉了,它在对象初始化的时候调用,我们一般将它理解为"构造函数"。这个方法在新建对象并进行初始化时被调用。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


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


person = Person('Alice', 30)
print(person.name)  # Alice

2.1.1 new 和__init__的解释

new 方法
new 是一个静态方法(虽然通常不需要显式声明为 @staticmethod),它负责创建并返回一个新的实例。也就是说,在对象的创建过程中,new 方法会被首先调用。
new 方法的第一个参数是类本身(通常命名为 cls),该方法应该返回类的一个实例。
对于不可变类型,比如整型、字符串和元组等,修改实例是不可能的,所以这些类型通常都需要通过重写 new 方法来进行实例的创建。
init 方法
init 方法用于实例的初始化操作。当 new 方法创建一个实例并返回时,这个实例随即被传递给 init 方法的 self 参数,以执行初始化。
init 不应该返回任何值,它的返回值被忽略。
调用顺序:
首先,new 方法被调用创建实例。
然后,创建出的实例(即 new 的返回值)被传递给 init 方法的 self 参数。
最后,init 方法初始化实例。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class MyClass(object):
    def __new__(cls, *args, **kwargs):
        print("Creating instance")
        instance = super(MyClass, cls).__new__(cls)
        return instance

    def __init__(self, value):
        print("Initializing instance")
        self.value = value


# 创建 MyClass 的一个实例
obj = MyClass("Hello")

# Creating instance
# Initializing instance

在这个例子中,当尝试创建 MyClass 的一个实例时,首先调用 new 方法来创建一个新的实例。创建成功后,这个新创建的实例会被自动传递给 init 方法以完成初始化操作。因此,你可以看到首先打印了 “Creating instance”,随后打印了 “Initializing instance”。
在大多数情况下,开发者无需重写 new 方法,只需关注 init 方法来初始化类的实例即可。但在处理不可变数据类型或者想要控制实例创建过程的高级用法时,可能需要自定义 new 方法。

2.2 字符串表现形式:str(self) 和 repr(self)

str 当你打印或者使用 str() 转换对象时被调用。
repr 用来给开发者看的字符串表现形式,它的目标是清晰无歧义。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


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

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

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


person = Person('Alice', 30)
print(person)  # Person(name=Alice, age=30)
print(repr(person))  # Person('Alice', 30)

2.3 属性访问:

getattr(self, name), setattr(self, name, value) 和 delattr(self, name)
这些方法负责管理属性的访问、设置和删除。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class Record:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __getattr__(self, name):
        return f"{name} not found"

    def __setattr__(self, name, value):
        self.__dict__[name] = value

    def __delattr__(self, name):
        del self.__dict__[name]


rec = Record(name="Alice", age=30)
print(rec.name)  # Alice
rec.location = "New York"
print(rec.location)  # New York
del rec.location
# print(rec.location) # Raises "location not found" due to __getattr__

2.4 算术运算符重载:

add(self, other), sub(self, other) 等
允许你定义对象在加减乘除等算术运算中的行为。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class Length:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        return Length(self.value + other.value)


l1 = Length(5)
l2 = Length(3)
l3 = l1 + l2
print(l3.value)  # 8

2.5 容器类型方法:

len(self), getitem(self, key), setitem(self, key, value), delitem(self, key) 等
这使得对象可以表现得像容器类型一样,支持 len(), []访问等。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class Shelf:
    def __init__(self):
        self._items = {}

    def __setitem__(self, key, value):
        self._items[key] = value

    def __getitem__(self, key):
        return self._items.get(key, None)

    def __delitem__(self, key):
        del self._items[key]


shelf = Shelf()
shelf['book'] = 'Python Programming'
print(shelf['book'])  # Python Programming
del shelf['book']

2.6 call(self, [args…])

该方法允许类的实例跟函数一样表现,call 是 Python 中的一个特殊方法,它使得一个对象可以像函数一样被调用。当你尝试像调用函数一样调用一个对象时,如果这个对象的类中定义了 call 方法,那么这个 call 方法会被执行。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class Adder:
    def __init__(self, n):
        self.n = n

    def __call__(self, x):
        return self.n + x


# 创建一个 Adder 实例,它会把传入的参数增加 10
adder = Adder(10)

# 由于定义了 __call__ 方法,我们可以将 adder 当作是函数来调用
result = adder(5)  # 相当于调用 adder.__call__(5)
print(result)  # 输出 15

在这个例子中,我们定义了一个类 Adder,它有一个初始化方法和一个 call 方法。call 方法接收一个参数 x 并且返回 self.n + x。当我们创建了一个 Adder 实例 adder 并且传入了初始值 10,这个实例就可以像一个函数那样被调用。调用 adder(5) 实际上会执行 adder.call(5),最终返回值是 15。
call 方法的使用场景主要是想使得实例的行为更类似函数或者是定义可调用对象,同时保留存储状态等功能,这在使用类装饰器或者设计类似函数式编程中的函数对象时会特别有用。

2.7 format(self, [args…])

format() 函数在 Python 中用于格式化输出,它允许你控制数据的显示形式。当你用 format(your_object) 调用它时,实际上会去查找 your_object 对应类的 format 魔术方法并调用它。你可以在自己的类中定义 format 方法来自定义格式化行为。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/7 8:25
# @Author  : Summer
# @File    : test.py
# @describe:
"""


class Order:
    def __init__(self, order_id, price):
        self.order_id = order_id
        self.price = price

    def __format__(self, format_spec):
        if format_spec == 'id':
            return f'Order ID: {self.order_id}'
        elif format_spec == 'price':
            return f'Order Price: ${self.price:.2f}'
        else:
            return f'Order ID: {self.order_id}, Price: ${self.price:.2f}'


# 创建一个 Order 对象
order = Order('123', 99.99)

# 使用 format() 进行格式化
formatted_order_id = format(order, 'id')
formatted_order_price = format(order, 'price')
formatted_order_default = format(order)  # 没有指定 format_spec,或者 format_spec 为空字符串

print(formatted_order_id)  # 输出 Order ID: 123
print(formatted_order_price)  # 输出 Order Price: $99.99
print(formatted_order_default)  # 输出 Order ID: 123, Price: $99.99

在这个例子中,我们定义了一个 Order 类,它有一个 format 方法,该方法接收一个参数 format_spec,它是一个字符串,指示如何格式化该对象。根据 format_spec 的值,format 返回不同的字符串。如果 format_spec 是 ‘id’,则只输出订单 ID;如果是 ‘price’,则只输出价格;如果 format_spec 不是这两种情况,它就会输出订单 ID 和价格。
这样,无论是直接调用 Python 内置的 format() 函数还是在字符串格式化时使用冒号 : 后跟格式说明符 {my_object:format_spec},都会使用对象的 format 方法进行格式化。

总结

对象的创建和销毁:
控制对象的创建 (new)、初始化 (init) 和销毁 (del) 的过程。
对象表示:
定制对象的字符串表示,包括通过 str 提供给用户的可打印版本,以及通过 repr 提供给开发者的官方字符串表示。
属性访问管理:
管理和自定义对象属性的访问、设置和删除 (getattr, setattr, delattr 等)。包括支持点号(.)运算符进行属性访问和动态属性。
容器类型模拟:
使自定义对象的行为类似于内置的容器类型,如序列和映射(getitem, setitem, delitem, len 等)。
算术和比较操作符重载:
定义对象如何相互作用,并对算术运算 (add, mul, 等) 和比较运算 (lt, eq, 等) 进行重载。
可调用对象:
通过 call 方法,将实例变为可调用,即像函数那样可以执行。
上下文管理器:
使对象可以用在 with 语句中,提供资源管理功能,如文件打开和关闭(enter, exit)。
迭代器和生成器:
让对象支持迭代,包括定义迭代器行为 (iter, next) 和生成器行为。
与 Python 内建类型及运动环境的集成:
包括定义对象的哈希 (hash),布尔值转换 (bool),大小 (len),以及格式化 (format) 等。
通过定义这些魔术方法,Python允许开发者以非常灵活和直观的方式来控制对象的行为。这一机制是Python的核心特性之一,为语言提供了极大的表达力和一致性。其实魔法方法远远不止这些,还有很多很多也值得我们去使用,Python中的魔法方法就跟它的名字一样有魔法,总是可以便捷的给你提供你所需要的各种需求,它们是Python面向对象编程的一大利器,使用魔术方法能构造出非常优美的代码结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1573829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ThingsBoard通过MQTT发送遥测数据

MQTT基础 客户端 MQTT连接 遥测上传API 案例 MQTT基础 MQTT是一种轻量级的发布-订阅消息传递协议,它可能最适合各种物联网设备。 你可以在此处找到有关MQTT的更多信息,ThingsBoard服务器支持QoS级别0(最多一次)和QoS级别1&…

程序猿成长之路之数据挖掘篇——频繁项集挖掘介绍

频繁项集挖掘可以说是数据挖掘中的重点,下面我们来分析以下频繁项集挖掘的过程和目标 如果对数据挖掘没有概念的小伙伴可以查看上次的文章 https://blog.csdn.net/qq_31236027/article/details/137046475 什么是频繁项集? 在回答这个问题之前&#xff…

蓝桥杯第101题 拉马车 C++ Java Python

目录 题目 思路和解题方法 复杂度: c 代码 Java 版本(仅供参考) Python 版本(仅供参考) 代码细节 C 版本: Java 版本: Python 版本: 题目 思路和解题方法 这个游戏是一个简单的纸牌游戏,两个玩家轮流出牌&am…

Springboot相关知识-图片描述(学习笔记)

学习java过程中的一些笔记,觉得比较重要就顺手记录下来了~ 目录 一、前后端请求1.前后端交互2.简单传参3.数组集合传参4.日期参数5.Json参数6.路径参数7.响应数据8.解析xml文件9.统一返回类10.三层架构11.分层解耦12.Bean的声明13.组件扫描14.自动注入 一、前后端请…

(免费分享)基于springboot,vue问卷调查系统

用户注册、用户登录、创建调查问卷、编辑问卷问题和选型(支持题型:单选、多选、单行文本、多行文本、数字、评分、日期、文本描述)、保存和发布问卷、停止问卷调查、游客填写调查问卷(一个IP地址只能填写一次) 技术&a…

4.3 IO day5

1&#xff1a;实现文件夹的拷贝功能 注意判断被拷贝的文件夹是否存在&#xff0c;如果不存在则提前创建&#xff0c;创建文件夹的函数为 mkdir 不考虑递归拷贝的问题 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h…

蓝桥杯刷题-09-三国游戏-贪心⭐⭐⭐

蓝桥杯2023年第十四届省赛真题-三国游戏 小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件&#xff0c;每个事件之间相互独立且最多只会发生一次&#xff0c;当第 i 个事件发生时会分别让 X, Y,…

清明作业 c++

1.封装一个类&#xff0c;实现对一个数求累和阶乘质数 #include <iostream>using namespace std; int mproduct(int a){if(a>1){return a*mproduct((a-1));}else{return 1;} } class number{int a; public:number():a(5){};number(int a):a(a){}void set(int a){thi…

开源的页面生成器:拖拽即可生成小程序、H5页面和网站

星搭精卫 MtBird 是一款低代码可视化页面生成器&#xff0c;可以帮助用户以可视化的形式搭建网页、小程序和表单等应用。 使用这个生成器&#xff0c;不需要代码就可以生成小程序、H5页面和网站&#xff0c;拖拽操作、样式配置快速生成页面应用&#xff0c;数据可视化接入&…

2024年【道路运输企业安全生产管理人员】找解析及道路运输企业安全生产管理人员作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员找解析参考答案及道路运输企业安全生产管理人员考试试题解析是安全生产模拟考试一点通题库老师及道路运输企业安全生产管理人员操作证已考过的学员汇总&#xff0c;相对有效帮助道路运输…

C++高频面试知识总结 part3

哈希 1.哈希表为什么快&#xff1f;2.哈希冲突解决方法3.哈希表扩容流程4.哈希表扩容太多次&#xff0c;需要遍历所有元素&#xff0c;如何优化&#xff1f;5.渐进式扩容为何可以正确访问哈希表&#xff1f; 1.哈希表为什么快&#xff1f; 哈希表&#xff08;Hash table&#…

告别旧IP,更换网络ip地址教程分享

在数字化世界中&#xff0c;IP地址作为每个网络设备的标识符&#xff0c;扮演着至关重要的角色。它不仅是设备在网络中的“门牌号”&#xff0c;还影响着网络连接的稳定性、安全性和数据传输效率。因此&#xff0c;在某些情况下&#xff0c;更换网络IP地址成为必要操作。虎观代…

平台规则的改变会影响低价治理结果吗

许多品牌在做低价链接投诉时&#xff0c;会用一套自己的标准去做&#xff0c;但如果无视平台规则&#xff0c;会出现非常多不好的结果&#xff0c;比如帐号投诉成功率被拉低&#xff0c;会直接影响后续链接的投诉时效和成功率&#xff0c;同时因为不尊重平台规则&#xff0c;而…

美国洛杉矶大带宽服务器带宽堵塞解决方法

随着互联网的快速发展&#xff0c;大带宽服务器成为了现代企业和个人进行数据传输、存储和处理的关键设施。然而&#xff0c;在美国洛杉矶等大城市&#xff0c;由于网络流量的激增、不合理的网络配置以及网络攻击等多种原因&#xff0c;大带宽服务器带宽堵塞问题日益凸显。本文…

【力扣】94. 二叉树的中序遍历、144. 二叉树的前序遍历、145. 二叉树的后序遍历

先序遍历&#xff1a;根-左-右中序遍历&#xff1a;左-根-右后序遍历&#xff1a;左-右-根 94. 二叉树的中序遍历 题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3…

基于springboot+vue+Mysql的教学视频点播系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

洛谷 1126.机器人搬重物

思路&#xff1a;BFS 这道BFS可谓是细节爆炸&#xff0c;对于编程能力和判断条件的能力的考察非常之大。 对于这道题&#xff0c;我们还需要额外考虑一些因素&#xff0c;那就是对于障碍物的考虑和机器人方位的考虑。 首先我们看第一个问题&#xff0c;就是对于障碍物的考虑…

Qt Creator 界面

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、认识 Qt Creator 界面 1、总览 2、左边栏 3、代码编辑区 4、UI设计界面 5、构建区 一、认识 …

GitHub入门与实践

ISBN: 978-7-115-39409-5 作者&#xff1a;【日】大塚弘记 译者&#xff1a;支鹏浩、刘斌 页数&#xff1a;255页 阅读时间&#xff1a;2023-08-05 推荐指数&#xff1a;★★★★★ 好久之前读完的了&#xff0c;一直没有写笔记。 这本入门Git的书籍还是非常推荐的&#xff0c;…

【蓝桥杯】蓝桥杯算法复习(四)

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…