QQ登录

只需一步,快速开始

开启左侧

Python学习第五十九天—类和对象8-Python懂魔法

[复制链接]
15271953841 发表于 2024-3-23 22:19:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
原来Python懂魔法
一、        对象是怎么样的?魔法方法
(一)__init__(self[,…])能在对象初始化时候实现个性化定制。
(二)__new__(cls[,..])它是在__init__之前被调用的,事实上对象是由__new__方法创建的,所以我们看到了它的第一个参数是cls,是类,而不是self,对象诞生的流程是先调用__new__方法,创建一个类的实例,将其传递给__init__方法,再进行个性化定制。如果有人问:是哪种魔法方法创建了实例对象,或者说实例话对象中调用的第一个魔法方法是什么?那么答案必须是__new__,因为self就是它返回的,有了self才有这个对象,才有这个方法跟对象的绑定。
不过,需要重写__new__方法的情况较少,通常有两种情况,一种情况在原类中去定制类,原类是一个更高级的概念,是Python最难理解的概念之一被称之为魔法方法背后的魔法方法,这个后面会有讲解,这个情况这里按住不表。
另一种情况比较特殊,是在继承不可变数据类型的时候,如果我们想要从中作梗,就可通过重写__new__方法进行拦截。
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
class CapStr(str):                       (CapStr是继承自str这个字符串的)
    def __new__(cls,string):              (cls类,string实例化传进去的一个参数)
        string = string.upper()            (变成大写字母组成的形式)
        return super().__new__(cls,string)   (让父类去考虑是这个__new__怎么去构造对象的)

   
cs=CapStr("FishC")
cs                   (这里对不可变对象进行修改,是因为赶在实例对象被创建之前,就进行了拦截,然后才调用super().__new__去创建真正的实例。
由于CapStr类是继承自str字符串类的,字符串该有的方法,它也一并继承了下来,比如我们要把它变成小写或首字母大写:
'FISHC'
cs.lower()
'fishc'
cs.capitalize()
'Fishc'
当对象既将被销毁的时候,会调用一个魔法方法,叫做__del__(self).
(三)__del__(self)
class C:
    def __init__(self):            (构造方法)
        print("我来了~")          (当类被创建时,打印“我来了”)
    def __del__(self):
        print("我走了~")           (当类被销毁时,打印“我走了”)
        
c = C()                  (实例化对象的时候)
我来了~
del c                     (调用del语句把它删除的时候,但是必须检测到一个对象没有任何引用的时候,才会将它销毁)
我走了~
c = C()
我来了~
d = c                     (做一个引用给d)
del c                      (此时,del c没有用)
del d                      (但是这个引用d被销毁,c才会被销毁)
我走了~

二、__del__是对象销毁前的最后拦截,有没有利用这个实现对象的重生,__del__方法可以通过创建一个该实例的新引用,来推迟其销毁,这也被称为对象的重生,虽然官方不建议,但它又告诉你可以实现,不妨尝试一下,虽然对象随着__del__语句删除了,这没错,但是如果能够在对象被销毁之前将self送出去,那么这个对象就算是得以重生了。
class D:
    def __init__(self,name):
        self.name = name
    def __del__(self):          (方法其实也是一个函数,只是多了一个对象绑定的操作和参数)
        global x                (创建一个全局变量x)
        x = self                  (然后x=self)

        
d = D("小姐姐")
d
<__main__.D object at 0x000001EA934014F0>
d.name
'小姐姐'
del d
d
Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    d
NameError: name 'd' is not defined. Did you mean: 'D'?
x
<__main__.D object at 0x000001EA934014F0>
x.name
'小姐姐'
我们在讲全局变量的时候,非迫不得已,尽量不要使用全局变量,因为它会污染命名空间,那么我们就要考虑,会不会有另一种方法:是不是可以在对象被销毁之前,让它去调用一个函数,然后通过参数传递的形式将self给传出去。所以还有一种方法:通过函数调用的形式,将这个对象,将这个self保存起来)
class E:
    def __init__(self,name,func):
        self.name = name
        self.func = func
    def __del__(self):
        self.func(self)

        
def outter():                  (定义一个闭包函数,)
    x = 0
    def inner(y=None):
        nonlocal x
        if y:
            x = y
        else:
            return x
    return inner

f = outter()
e = E("小姐姐",f)
e
<__main__.E object at 0x000001EA93401AF0>
e.name
'小姐姐'
del e
e
Traceback (most recent call last):
  File "<pyshell#60>", line 1, in <module>
    e
NameError: name 'e' is not defined. Did you mean: 'E'?
g = f()
g
<__main__.E object at 0x000001EA93401AF0>
g.name
'小姐姐'                    (小姐姐又复活了)

怎么实现的:这是我们定义为闭包函数的原因是为了让self保存在外部函数x变量,而内部函数的作用是用于窃取这个self对象,在del魔法方法中调用它的时候是带参数的,它就把这个(self.func(self))参数给存储起来,如果在外部调用这个函数,它(g=f())不带参数,就使用默认值None,它就返回刚刚拿到的self,这个就是刚刚发生的过程。

客服热线
400-1234-888 周一至周日:09:00 - 21:00
公司地址:襄阳市樊城区长虹路现代城5号楼188

创客帮MAKER.BAND青少年创客创意社区是一个融教育、科技、体育资讯为一体的综合服务平台,专注于教育创新、专注于科技体育、专注于教育资讯。

Powered by Discuz! X3.4 © 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表