鱼C论坛

 找回密码
 立即注册
查看: 146|回复: 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`会得到结果并打印出来。

我们可以将代码进行简单修改,添加打印语句来验证一下:

  1. class MetaC(type):
  2.     def __call__(cls, *args, **kwargs):
  3.         new_args = [each.upper() for each in args if isinstance(each, str)]
  4.         print("拦截的参数:", new_args)
  5.         return type.__call__(cls, *new_args, **kwargs)

  6. class C(metaclass=MetaC):
  7.     def __init__(self, name):
  8.         self.name = name
  9.         print("执行的初始化函数")
  10.         
  11. c = C('FishC')
  12. print(c.name)
复制代码


输出结果为:
  1. 拦截的参数: ['FISHC']
  2. 执行的初始化函数
  3. 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__()`方法可以用来初始化对象的属性或执行必要的设置操作。它是一个特殊的方法,以双下划线开头和结尾,这种命名约定表示它是一个特殊的方法。

下面是一个示例代码:

  1. class Person:
  2.     def __init__(self, name, age):
  3.         self.name = name
  4.         self.age = age

  5. person1 = Person("Alice", 25)
  6. print(person1.name)  # 输出 "Alice"
  7. 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__()方法的执行顺序:

  1. class MyMeta(type):
  2.     def __new__(cls, name, bases, attrs):
  3.         print("Entering MyMeta.__new__()")
  4.         # 创建类对象
  5.         obj = super().__new__(cls, name, bases, attrs)
  6.         print("Exiting MyMeta.__new__()")
  7.         return obj

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

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


  17. class MyClass(metaclass=MyMeta):
  18.     def __new__(cls, *args, **kwargs):
  19.         print("Entering MyClass.__new__()")
  20.         obj = super().__new__(cls)
  21.         print("Exiting MyClass.__new__()")
  22.         return obj

  23.     def __init__(self):
  24.         print("Initializing MyClass")


  25. my_obj = MyClass()
复制代码


输出结果:
  1. Entering MyMeta.__new__()
  2. Exiting MyMeta.__new__()
  3. Initializing MyClass
  4. Entering MyClass.__new__()
  5. Exiting MyClass.__new__()
  6. Entering MyMeta.__call__()
  7. Exiting MyMeta.__call__()
  8. 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__()`方法初始化对象。

下面是一个简单的示例代码,帮你更好地理解上述过程:

  1. class MyMetaClass(type):
  2.     def __call__(cls, *args, **kwargs):
  3.         print("调用元类的__call__()方法")
  4.         obj = super().__call__(*args, **kwargs)
  5.         return obj

  6. class MyClass(metaclass=MyMetaClass):
  7.     def __new__(cls, *args, **kwargs):
  8.         print("调用类的__new__()方法")
  9.         obj = super().__new__(cls)
  10.         return obj
  11.    
  12.     def __init__(self, *args, **kwargs):
  13.         print("调用类的__init__()方法")

  14. my_obj = MyClass()
复制代码


输出结果为:

  1. 调用元类的__call__()方法
  2. 调用类的__new__()方法
  3. 调用类的__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__()方法,用于初始化这个实例对象。

下面是一个示例代码,帮助你更好地理解:

  1. class MetaClass(type):
  2.     def __new__(cls, name, bases, attrs):
  3.         print("元类的__new__()方法被调用")
  4.         return super().__new__(cls, name, bases, attrs)
  5.    
  6.     def __init__(cls, name, bases, attrs):
  7.         print("元类的__init__()方法被调用")
  8.         super().__init__(name, bases, attrs)
  9.         
  10.     def __call__(cls, *args, **kwargs):
  11.         print("元类的__call__()方法被调用")
  12.         return super().__call__(*args, **kwargs)

  13. class MyClass(metaclass=MetaClass):
  14.     def __new__(cls, *args, **kwargs):
  15.         print("类的__new__()方法被调用")
  16.         return super().__new__(cls)
  17.    
  18.     def __init__(self, *args, **kwargs):
  19.         print("类的__init__()方法被调用")
  20.         super().__init__(*args, **kwargs)

  21. obj = MyClass()
复制代码


输出结果为:

  1. 元类的__new__()方法被调用
  2. 元类的__init__()方法被调用
  3. 类的__new__()方法被调用
  4. 类的__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-4-30 21:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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