画线救救火柴人无限体力
45.62MB · 2025-12-06
大家好,我是 倔强青铜三。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!
欢迎来到 苦练Python第52天!
如果你已经跟着我从“青铜”肝到“黄金”,今天咱们直接上 王者局!
今天要聊的是 Python 类里 最神秘、最常被忽视、却又最强大 的七把剑——魔术方法(magic methods):
__new__、__init__、__del____repr__、__str__、__format__、__bytes__别被名字吓到,它们本质只做一件事:让你100%掌控对象的“生老病死”和“自我介绍”!
一口气吃透它们,写类就像写小说,生得优雅,死得体面,自我介绍惊艳全场!
__new__:对象的“出生证明”当你写下 MyClass() 时,Python 先调 __new__,再调 __init__。
__new__ 是 静态方法(即使不写 @staticmethod),第一个参数是 cls。__init__ 不会执行!class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
print(" 创建新实例")
cls._instance = super().__new__(cls)
else:
print("️ 实例已存在,直接返回")
return cls._instance
def __init__(self, name):
self.name = name
print(f" __init__ 被调用,name={name}")
# 测试
a = Singleton("张三")
b = Singleton("李四")
print(a is b) # True
输出:
创建新实例
__init__ 被调用,name=张三
️ 实例已存在,直接返回
__init__ 被调用,name=李四
True
点评:
__new__ 控制“生不生”,__init__ 控制“怎么养”。tuple, str)都靠它。__init__:对象的“成人礼”__new__ 返回实例后,立即触发。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
print(f" 汪汪!我是 {name},今年 {age} 岁!")
dog = Dog("", 3)
输出:
汪汪!我是 ,今年 3 岁!
点评:
__init__,但记住:它只是“装修队”,不是“建筑队”!__del__:对象的“临终遗言”class FileHandler:
def __init__(self, filepath):
self.file = open(filepath, 'w')
print(" 文件已打开")
def __del__(self):
self.file.close()
print("️ 文件已关闭")
f = FileHandler("test.txt")
del f # 手动触发
输出:
文件已打开
️ 文件已关闭
点评:
__del__ 做关键逻辑!推荐用 with 语句或 contextlib。__del__ 打印日志,观察对象生命周期。__repr__:程序员的“神份整”repr(obj)、%r、!r 格式化。class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(repr(p)) # Point(3, 4)
点评:
eval(repr(obj)) == obj 尽量成立!__repr__ 时,默认打印 <__main__.Point object at 0x...>,调试想打人!__str__:用户的“名片”print(obj)、str(obj)、%s、{} 格式化。class Student:
def __init__(self, name, score):
self.name, self.score = name, score
def __str__(self):
return f"学生:{self.name},成绩:{self.score}"
s = Student("小明", 95)
print(s) # 学生:小明,成绩:95
点评:
__str__,Python 会退而求其次找 __repr__。__format__:格式化“化妆师”format(obj, '格式')、f"{obj:格式}"。from datetime import datetime
class MyDate:
def __init__(self, year, month, day):
self.date = datetime(year, month, day)
def __format__(self, fmt):
if fmt == "iso":
return self.date.strftime("%Y-%m-%d")
elif fmt == "us":
return self.date.strftime("%m/%d/%Y")
return str(self.date)
d = MyDate(2025, 8, 4)
print(f"ISO格式:{d:iso}") # ISO格式:2025-08-04
print(f"美式格式:{d:us}") # 美式格式:08/04/2025
点评:
f"{price:.2f}" 这种骚操作。__bytes__:二进制“写真”bytes(obj)。class Color:
def __init__(self, r, g, b):
self.r, self.g, self.b = r, g, b
def __bytes__(self):
return bytes([self.r, self.g, self.b])
c = Color(255, 0, 128)
print(bytes(c)) # b'xffx00x80'
点评:
bytes(obj) 搞定!| 魔术方法 | 触发场景 | 作用 | 常见用途 |
|---|---|---|---|
__new__ | 创建实例时 | 控制“生不生” | 单例、缓存、不可变类 |
__init__ | __new__ 之后 | 初始化属性 | 99%的类都会写 |
__del__ | 垃圾回收前 | 清理资源 | 文件句柄、网络连接 |
__repr__ | 调试、repr() | 开发者友好打印 | 日志、REPL |
__str__ | 打印、str() | 用户友好打印 | 前端展示 |
__format__ | format() | 自定义格式化 | 日期、数字美化 |
__bytes__ | bytes() | 二进制表示 | 网络传输、存储 |
class LogEntry:
def __init__(self, level, msg):
self.level, self.msg = level, msg
def __repr__(self):
return f"LogEntry({self.level!r}, {self.msg!r})"
def __str__(self):
return f"[{self.level}] {self.msg}"
def __format__(self, fmt):
if fmt == "json":
return f'{{"level":"{self.level}", "msg":"{self.msg}"}}'
return str(self)
def __bytes__(self):
return str(self).encode("utf-8")
# 测试
log = LogEntry("ERROR", "磁盘已满")
print(repr(log)) # LogEntry('ERROR', '磁盘已满')
print(str(log)) # [ERROR] 磁盘已满
print(f"{log:json}") # {"level":"ERROR", "msg":"磁盘已满"}
print(bytes(log)) # b'[ERROR] xe7xa3x81xe7x9bx98xe5xb7xb2xe6xbbxa1'
| 坑 | 解释 | 解决 |
|---|---|---|
__del__ 不执行 | 循环引用、进程崩溃 | 用 with 或 weakref |
__repr__ 写太复杂 | 调试时信息爆炸 | 保持简洁,能还原即可 |
__str__ 缺失 | 打印时显示 <object at ...> | 至少写 __repr__ |
__format__ 不支持 | f-string 报错 | 实现 __format__ |
__new__ 管生,__init__ 管养,__del__ 管埋。__repr__ 给开发者看,__str__ 给用户看,__format__ 化妆,__bytes__ 整容成二进制。你最常用哪个魔术方法?
A. __init__(初始化狂魔)
B. __repr__(调试党)
C. __str__(打印狂魔)
D. __new__(单例控)
评论区告诉我你的答案 + 骚操作!
45.62MB · 2025-12-06
135.33MB · 2025-12-06
250.97M · 2025-12-06