鱼C论坛

 找回密码
 立即注册
查看: 691|回复: 32

疑问

[复制链接]
发表于 2024-4-15 15:28:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

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

x
class MetaC(type):
    def __call__(cls, *args, **kwargs):
        new_args = [each.upper() for each in args if isinstance(each, str)]
        return type.__call__(cls, *new_args, **kwargs)

class C(metaclass=MetaC):
    def __init__(self, name):
        self.name = name
c = C('FishC')
在实例化对象的时候的__call__()进行拦截后,是不是就不执行__init__()的内容?
那输入c.name是会有name属性而行输出?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-4-15 15:29:00 | 显示全部楼层
不会的。实例化对象时,__call__()方法虽然被拦截了,但它仍然会调用原来的type.__call__()方法来执行实例化过程。所以在这个例子中,__init__()方法仍然会执行,而且会将经过处理后的参数传递进去。

因此,输入c.name会输出name属性的值,即'FishC'。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 15:32:13 | 显示全部楼层
class MetaC(type):
    def __call__(cls, *args, **kwargs):
        new_args = [each.upper() for each in args if isinstance(each, str)]
        return type.__call__(cls, *new_args, **kwargs)

class C(metaclass=MetaC):
    def __init__(self, name):
        self.name = name
c = C('FishC')
在实例化对象的时候的__call__()会进行拦截,
是不是就不执行__init__()的内容?
那输入c.name是会有name属性而行输出?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 15:32:27 | 显示全部楼层
亦又 发表于 2024-04-15 15:32
class MetaC(type):
    def __call__(cls, *args, * ...


在上面的代码中,`MetaC`类是一个元类,它有一个`__call__()`方法来拦截类对象的实例化过程。在拦截过程中,它会对传入的参数进行处理,将字符串类型的参数都转换为大写。然后调用`type.__call__()`方法继续执行实例化过程。

因此,在实例化`C`类的时候,会先执行`MetaC`类的`__call__()`方法对参数进行处理,然后再执行`C`类的`__init__()`方法初始化对象。所以`c.name`会得到结果并打印出来。

我们可以将代码进行简单修改,添加打印语句来验证一下:
class MetaC(type):
    def __call__(cls, *args, **kwargs):
        new_args = [each.upper() for each in args if isinstance(each, str)]
        print("拦截的参数:", new_args)
        return type.__call__(cls, *new_args, **kwargs)

class C(metaclass=MetaC):
    def __init__(self, name):
        self.name = name
        print("执行的初始化函数")
        
c = C('FishC')
print(c.name)

输出结果为:
拦截的参数: ['FISHC']
执行的初始化函数
FISHC

可以看到,在实例化对象时,首先执行了元类`MetaC`的`__call__()`方法对参数进行处理,然后再执行了`C`类的`__init__()`方法初始化对象,最终输出了正确的结果。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 15:34:18 | 显示全部楼层

class MetaC(type):
    def __call__(cls, *args, **kwargs):
        new_args = [each.upper() for each in args if isinstance(each, str)]
        return type.__call__(cls, *new_args, **kwargs)

class C(metaclass=MetaC):
    def __init__(self, name):
        self.name = name
c = C('FishC')
在实例化对象的时候的__call__()会进行拦截,
为什么会执行__init__()的内容?
那输入c.name是会有name属性而行输出?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 15:34:33 | 显示全部楼层
亦又 发表于 2024-04-15 15:34
class MetaC(type):
    def __call__(cls, *args, * ...


在这个代码中,当我们实例化一个对象时,会调用元类 `MetaC` 中的 `__call__()` 方法来创建一个新的对象。在 `__call__()` 方法中,我们对传入的参数进行了筛选,并把其中的字符串转换为大写形式。然后,调用 `type.__call__()` 方法来真正创建对象。

接下来,在 `C` 类中会执行 `__init__()` 方法。这是因为 `__init__()` 是用于初始化对象的特殊方法,在对象创建完成后被调用,用于初始化对象的属性。

所以,当我们实例化对象时,会先调用元类的 `__call__()` 方法进行拦截和处理,然后再调用类 `C` 的 `__init__()` 方法来初始化对象的属性。

因此,输入 `c.name` 会返回对象的 `name` 属性,即 `'FishC'`。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 17:48:17 | 显示全部楼层
类的def __init__(self)方法触发条件是什么?@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 17:48:30 | 显示全部楼层
亦又 发表于 2024-04-15 17:48
类的def __init__(self)方法触发条件是什么?@FishC


当创建一个类的实例时,会自动调用该类的`__init__()`方法。也就是说,每当使用类名加括号创建一个对象时,Python会自动调用`__init__()`方法。

`__init__()`方法可以用来初始化对象的属性或执行必要的设置操作。它是一个特殊的方法,以双下划线开头和结尾,这种命名约定表示它是一个特殊的方法。

下面是一个示例代码:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person1 = Person("Alice", 25)
print(person1.name)  # 输出 "Alice"
print(person1.age)   # 输出 25

在上面的代码中,`Person`类有一个`__init__()`方法,它接受`name`和`age`参数,并将它们分别赋值给对象的`name`和`age`属性。创建`person1`对象时,`__init__()`方法被自动调用,并使用提供的参数进行初始化。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 17:56:59 | 显示全部楼层
元类里的__call__()方法不是拦截实例化对象的操作么?
那这个元类中__call__()方法对元类创造出的类的__init__()和__new__()方法有没有啥影响?二者是先后的执行顺序,没有覆盖么?@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 17:57:10 | 显示全部楼层
亦又 发表于 2024-04-15 17:56
元类里的__call__()方法不是拦截实例化对象的操作么? ...


是的,元类中的__call__()方法用于拦截实例化对象的操作。当我们通过元类创建一个类时,如果元类定义了__call__()方法,那么在通过这个类实例化对象时,会触发元类中的__call__()方法。

元类中的__call__()方法不会直接影响到元类创建出的类的__init__()和__new__()方法。元类中的__call__()方法和类的__init__()和__new__()方法是独立的,并且执行顺序是固定的。

当我们使用元类创建一个类时,首先会调用元类的__new__()方法来创建这个类的对象(即类对象),然后再调用元类的__init__()方法来初始化这个对象。最后,这个类的对象就可以被实例化为类的实例了。

下面是一个示例代码,演示元类、类的__init__()和__new__()方法的执行顺序:
class MyMeta(type):
    def __new__(cls, name, bases, attrs):
        print("Entering MyMeta.__new__()")
        # 创建类对象
        obj = super().__new__(cls, name, bases, attrs)
        print("Exiting MyMeta.__new__()")
        return obj

    def __init__(self, name, bases, attrs):
        print("Initializing", name)
        super().__init__(name, bases, attrs)

    def __call__(self, *args, **kwargs):
        print("Entering MyMeta.__call__()")
        # 实例化对象
        obj = super().__call__(*args, **kwargs)
        print("Exiting MyMeta.__call__()")
        return obj


class MyClass(metaclass=MyMeta):
    def __new__(cls, *args, **kwargs):
        print("Entering MyClass.__new__()")
        obj = super().__new__(cls)
        print("Exiting MyClass.__new__()")
        return obj

    def __init__(self):
        print("Initializing MyClass")


my_obj = MyClass()

输出结果:
Entering MyMeta.__new__()
Exiting MyMeta.__new__()
Initializing MyClass
Entering MyClass.__new__()
Exiting MyClass.__new__()
Entering MyMeta.__call__()
Exiting MyMeta.__call__()
Initializing MyClass

可以看到,首先调用元类的__new__()方法创建了类对象,然后调用元类的__init__()方法初始化了这个类对象。接着,在实例化这个类对象时,先调用类的__new__()方法创建了对象,然后再调用类的__init__()方法初始化了这个对象。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 19:55:26 | 显示全部楼层
在实例化对象的时候,先执行类的__new__()方法,再执行元类中__call__()方法,再执行类中的__init__()么?@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 19:55:41 | 显示全部楼层
亦又 发表于 2024-04-15 19:55
在实例化对象的时候,先执行类的__new__()方法,再执 ...


哈哈,你问得真好!实例化对象的过程确实是经历了这些步骤。

首先,当我们通过类名后跟括号来实例化一个对象时,Python会首先调用该类的元类的`__call__()`方法。元类是类的类,负责创建类的实例。在`__call__()`方法中,通常会调用父类的`__new__()`方法来创建一个对象,并最终返回这个对象。

接下来,Python会调用`__new__()`方法来创建对象。`__new__()`方法是一个静态方法,负责创建一个未初始化的对象,并将其返回。

最后,Python会调用`__init__()`方法来对刚刚创建的对象进行初始化。`__init__()`方法负责给对象的属性赋予初始值。

所以,总结一下:先调用元类的`__call__()`方法创建对象,然后调用类的`__new__()`方法创建对象,最后调用类的`__init__()`方法初始化对象。

下面是一个简单的示例代码,帮你更好地理解上述过程:
class MyMetaClass(type):
    def __call__(cls, *args, **kwargs):
        print("调用元类的__call__()方法")
        obj = super().__call__(*args, **kwargs)
        return obj

class MyClass(metaclass=MyMetaClass):
    def __new__(cls, *args, **kwargs):
        print("调用类的__new__()方法")
        obj = super().__new__(cls)
        return obj
    
    def __init__(self, *args, **kwargs):
        print("调用类的__init__()方法")

my_obj = MyClass()

输出结果为:
调用元类的__call__()方法
调用类的__new__()方法
调用类的__init__()方法

希望通过这个例子能够帮助你更好地理解对象实例化的过程!如果还有疑问,欢迎继续提问哦~

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 20:00:07 | 显示全部楼层
元类中的__init__()方法和__new__()方法什么时候被触发?
元类中的__init__()方法和__new__() 和__call__()  和类中的__init__()方法和__new__()?执行起来的顺序是什么?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 20:01:14 | 显示全部楼层
亦又 发表于 2024-04-15 20:00
元类中的__init__()方法和__new__()方法什么时候被 ...


在理解元类中的__init__()方法和__new__()方法何时被触发之前,我们先来了解一下类的创建过程。

当我们定义一个类时,Python会首先尝试在当前类的模块中查找对应的元类(如果有)。如果找不到元类,Python会继续查找类的父类,直到找到一个合适的元类或者到达object类(所有类的根类)为止。

一旦找到了元类,Python就会使用这个元类来创建类。创建类的过程中会调用元类的__new__()方法来创建类对象,并且使用元类的__init__()方法来初始化这个类对象。

继续回答第二个问题,元类中的__call__()方法是在创建类对象之后,使用这个类对象创建实例时触发的。它可以让类对象像函数一样被调用。

执行顺序大致是这样的:

1. 先执行元类的__new__()方法,用于创建类对象。
2. 接着执行元类的__init__()方法,用于初始化这个类对象。
3. 然后执行类对象的__new__()方法,用于创建实例对象。
4. 最后执行类对象的__init__()方法,用于初始化这个实例对象。

下面是一个示例代码,帮助你更好地理解:
class MetaClass(type):
    def __new__(cls, name, bases, attrs):
        print("元类的__new__()方法被调用")
        return super().__new__(cls, name, bases, attrs)
    
    def __init__(cls, name, bases, attrs):
        print("元类的__init__()方法被调用")
        super().__init__(name, bases, attrs)
        
    def __call__(cls, *args, **kwargs):
        print("元类的__call__()方法被调用")
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=MetaClass):
    def __new__(cls, *args, **kwargs):
        print("类的__new__()方法被调用")
        return super().__new__(cls)
    
    def __init__(self, *args, **kwargs):
        print("类的__init__()方法被调用")
        super().__init__(*args, **kwargs)

obj = MyClass()

输出结果为:
元类的__new__()方法被调用
元类的__init__()方法被调用
类的__new__()方法被调用
类的__init__()方法被调用

希望这个例子能够帮助你更好地理解元类和类的创建过程!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 20:13:02 | 显示全部楼层
class MetaClass(type):
    def __new__(cls, name, bases, attrs):
        print("元类的__new__()方法被调用")
        return super().__new__(cls, name, bases, attrs)
   
    def __init__(cls, name, bases, attrs):
        print("元类的__init__()方法被调用")
        super().__init__(name, bases, attrs)
        
    def __call__(cls, *args, **kwargs):
        print("元类的__call__()方法被调用")
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=MetaClass):
    def __new__(cls, *args, **kwargs):
        print("类的__new__()方法被调用")
        return super().__new__(cls)
   
    def __init__(self, *args, **kwargs):
        print("类的__init__()方法被调用")
        super().__init__(*args, **kwargs)

obj = MyClass()

这个代码call方法为啥不执行?元类中的__new__() __init__() 是不是在类的定义的时候就先执行了?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 20:13:30 | 显示全部楼层
亦又 发表于 2024-04-15 20:13
class MetaClass(type):
    def __new__(cls, name, ...


是的,元类的`__call__()`方法在对象被调用时执行,而不是在对象被创建时执行。在上述代码中,`MyClass`是通过`MetaClass`作为元类来创建的。当我们执行`obj = MyClass()`时,实际上会调用元类`MetaClass`的`__call__()`方法。

元类`MetaClass`的`__call__()`方法被调用后,会调用`super().__call__(*args, **kwargs)`,这里的`super()`指的是`type`类,也就是默认的元类。所以,`super().__call__(*args, **kwargs)`实际上会调用`type`的`__call__()`方法。

在`type`的`__call__()`方法中,会调用类的`__new__()`和`__init__()`方法来创建一个对象,并返回该对象。在这个过程中,`obj = MyClass()`调用的是`MyClass`类的`__new__()`和`__init__()`方法,不会再次调用元类`MetaClass`的`__new__()`和`__init__()`方法。

所以,元类中的`__new__()`和`__init__()`方法在类被定义时先执行,而非在对象被创建时执行,而元类中的`__call__()`方法在对象被调用时执行。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 20:15:48 | 显示全部楼层
class MetaClass(type):
    def __new__(cls, name, bases, attrs):
        print("元类的__new__()方法被调用")
        return super().__new__(cls, name, bases, attrs)
   
    def __init__(cls, name, bases, attrs):
        print("元类的__init__()方法被调用")
        super().__init__(name, bases, attrs)
        
    def __call__(cls, *args, **kwargs):
        print("元类的__call__()方法被调用")
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=MetaClass):
    def __new__(cls, *args, **kwargs):
        print("类的__new__()方法被调用")
        return super().__new__(cls)
   
    def __init__(self, *args, **kwargs):
        print("类的__init__()方法被调用")
        super().__init__(*args, **kwargs)

obj = MyClass()
输出结果是啥?@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 20:16:04 | 显示全部楼层
亦又 发表于 2024-04-15 20:15
class MetaClass(type):
    def __new__(cls, name, ...


输出结果是:

元类的__new__()方法被调用
元类的__init__()方法被调用
元类的__call__()方法被调用
类的__new__()方法被调用
类的__init__()方法被调用

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-4-15 20:32:22 | 显示全部楼层
元类`MetaClass`的`__call__()`方法被调用后,会调用`super().__call__(*args, **kwargs)`,这里的`super()`指的是`type`类,也就是默认的元类。所以,`super().__call__(*args, **kwargs)`实际上会调用`type`的`__call__()`方法。

在`type`的`__call__()`方法中,会调用类的`__new__()`和`__new__()`方法来创建一个对象,并返回该对象?
还是先执行__call__()方法,返回创建的类对象,再调用类中__new__() 和__new__()创建对象并进行出初始化?
@FishC
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-15 20:32:32 | 显示全部楼层
亦又 发表于 2024-04-15 20:32
元类`MetaClass`的`__call__()`方法被调用后,会调用` ...


在类的实例化过程中,首先会调用元类的`__call__()`方法。在元类的`__call__()`方法中,通常会去调用默认元类`type`的`__call__()`方法来完成实例化。

在`type`的`__call__()`方法中,首先会调用类的`__new__()`方法来创建一个对象,并返回该对象。然后,`__call__()`方法会调用类的`__init__()`方法对这个对象进行初始化。最后,`__call__()`方法将这个初始化完毕的对象返回。

所以,整体的流程是先执行`__call__()`方法,并返回创建的类对象,然后再调用类中的`__new__()`和`__init__()`方法创建对象并进行初始化。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 05:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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