gpt4 book ai didi

python - 从元类访问构造函数的参数

转载 作者:行者123 更新时间:2023-12-01 02:17:33 27 4
gpt4 key购买 nike

TL;DR -
我有一个使用元类的类。
我想在初始化过程之前从元类访问对象构造函数的参数,但我找不到访问这些参数的方法。
如何从元类函数__new__访问构造函数的参数?

<小时/>

为了练习在Python中使用元类,我想创建一个类,用作《银河系漫游指南》一书中的 super 计算机“Deep Thought”。

我的类(class)的目的是存储 super 计算机从用户那里获得的各种查询。
最重要的是,它只会获取一些参数并存储它们。
如果给定的参数之一是数字 42 或字符串“生命、宇宙和一切的答案”,我不想创建一个新对象,而是返回一个指向现有对象的指针。
这背后的想法是,这些对象将完全相同,因此当使用 is 运算符比较这两个对象时,结果将为 true。

为了能够使用 is 运算符并获得 True 作为答案,我需要确保这些变量指向同一个对象。因此,为了返回指向现有对象的指针,我需要干预该对象的初始化过程。我无法检查构造函数本身的给定参数并相应地修改对象的内部变量,因为为时已晚:如果我仅将给定参数作为 __init__ 函数的一部分进行检查,那么这两个对象将分配在内存的不同部分(它们可能相等,但在使用 is 运算符时不会返回 True)。

我想做这样的事情:

class SuperComputer(type):

answer = 42

def __new__(meta, name, bases, attributes):
# Check if args contains the number "42"
# or has the string "The answer to life, the universe, and everything"
# If so, just return a pointer to an existing object:
return SuperComputer.answer

# Else, just create the object as it is:
return super(SuperComputer, meta).__new__(meta, name, bases, attributes)


class Query(object):
__metaclass__ = SuperComputer

def __init__(self, *args, **kwargs):
self.args = args
for key, value in kwargs.items():
setattr(self, key, value)


def main():
number = Query(42)
string = Query("The answer to life, the universe, and everything")
other = Query("Sunny", "Sunday", 123)
num2 = Query(45)

print number is string # Should print True
print other is string # Should print False
print number is num2 # Should print False


if __name__ == '__main__':
main()

但我坚持从构造函数获取参数。
我看到 __new__ 方法仅获取四个参数:
元类实例本身、类的名称、其基类及其属性。
如何将参数从构造函数发送到元类?
我可以做什么来实现我的目标?

最佳答案

您不需要元类。

事实是__init__不是Python中对象的“构造函数”,而是通常称为“初始化器”。 __new__更接近其他语言中“构造函数”的角色,并且它不仅仅适用于元类 - 所有类都有 __new__方法。如果没有明确实现, object.__new__直接调用。

实际上,它是 object.__new__它在 Python 中创建一个新对象。从纯 Python 代码中,没有其他可能的方法来创建对象:它总是会经过那里。这意味着如果您实现 __new__方法在您自己的类上,您可以选择不创建新实例,而是返回同一类(或任何其他对象)的另一个预先存在的实例。

您只需记住:如果 __new__返回同一个类的实例,那么默认行为是 __init__在同一个实例上调用。否则,__init__没有被调用。

还值得注意的是,近年来,一些使用元类在 Python 中创建“单例”的方法变得流行 - 这实际上是一种过度杀伤的方法,这是压倒性的 __new__也更适合创建单例。

在你的情况下,你只需要有一个字典,其中包含你想要跟踪的参数作为键,并检查是否创建一个新实例或每当 __new__ 时“回收”一个实例。运行。字典可以是类属性,也可以是模块级别的全局变量 - 这是您的选择:

class Recycler:
_instances = {}
def __new__(cls, parameter1, ...):
if parameter1 in cls._instances:
return cls._instances[parameter1]
self = super().__new__(cls) # don't pass remaining parameters to object.__new__
_instances[parameter1] = self
return self

如果您在__init__中有任何代码除此之外,将其移至 __new__以及。

您可以拥有具有此行为的基类并拥有类层次结构,而无需重新实现 __new__每堂课。

对于元类,当实际创建使用该元类创建的类的新实例时,不会调用它的任何方法。只有通过装饰或创建新的 __new__ 自动插入此行为才有用。方法,在使用该元类创建的类上。由于此行为更容易跟踪、维护,并且总体上只需使用普通继承即可与其他类组合,因此根本不需要元类。

关于python - 从元类访问构造函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48254371/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com