当前位置: 首页 > 知识库问答 >
问题:

允许deafult构造函数接受一个实例并将其不受约束地返回

漆雕伟志
2023-03-14

我想允许我的类构造函数接受这个类的一个实例,在这种情况下返回这个相同的实例而不是创建一个新对象。就像tuple所做的那样:

>>> t = (1, 2, 3)
>>> tuple(t) is t
True

我想我需要为此重写__new__方法,并在__init__方法中处理这个特殊情况。这有什么食谱吗?

当构造函数被赋予一个将返回不变的类实例时,我宁愿完全跳过__init__,但我看不出有什么办法。我还对cls与super的三重用法持怀疑态度:

class C:
    @staticmethod
    def __new__(cls, x=None):
        if isinstance(x, cls):
            return x
        else:
            return super(cls, cls).__new__(cls)

    def __init__(self, x=None):
        if x is self: return  # Can I just skip __init__ instead?
        self.x = x

(我知道Super()没有参数,但我不喜欢不一致的魔法。)

在了解了更多关于Super和Python中的MRO的信息后,我发现这段代码不好。例如,子类化C会导致

>>> class D(C): pass
>>> d = D(1)
......
RecursionError: maximum recursion depth exceeded while calling a Python object

我非常害怕< code>super()没有参数,却神奇地从(词法或动态?)上下文,我决定添加一个“回调”来完成类定义,而不是使用它:

class C2:
    @classmethod
    def finalise(this_cls_yes_this_one):
        @staticmethod
        def __new__(cls, x=None):
            if isinstance(x, cls):
                return x
            else:
                return super(this_cls_yes_this_one, cls).__new__(cls)

        this_cls_yes_this_one.__new__ = __new__

        del this_cls_yes_this_one.finalise

    def __init__(self, x=None):
        if x is self: return
        self.x = x

C2.finalise()

共有1个答案

郭永安
2023-03-14

您可以使用元类。每当调用实例时,都会在元类的< code>__call__方法中调用< code>__init__和< code>__new__方法。您可以通过重写元类< code>__call__函数来处理这两种情况。

class MyMetaClass(type):

    def __call__(cls, obj, *args, **kwargs):
        if (isinstance(obj, cls)):
            return obj
        else:
            self = cls.__new__(cls, obj, *args, **kwargs)
            cls.__init__(self, obj, *args, **kwargs)
            return self
            # Note: In order to be sure that you don't miss anything
            # It's better to do super().__call__(obj, *args, **kwargs) here

class A(metaclass=MyMetaClass):
    def __init__(self, obj, *args, **kwargs):
        self.val = obj

演示:

a = A(10)
b = A(a)
c = A(40)
print(b is a)
print(a.val)
print(b.val)
print(c is a)
print(c.val)

# out:
True
10
10
False
40
 类似资料:
  • 问题内容: 因此,构造函数在说)预期,错误不是陈述,并且; 预期 对象类 问题答案: 应该 您的构造函数(由定义)应按此顺序要求String,String,int和long 。 不带双引号的Allison不是字符串。

  • 我在Spring Boot项目中添加了Liquibase配置: 当我启动应用程序时,我得到这个错误: 你知道我如何解决这个问题吗?

  • 问题内容: 我想创建一个函数,该函数返回符合协议的对象,但是协议使用。给出以下玩具示例: 并且已扩展为符合,并且每个方法都实现了返回不同类型的方法。 现在,我想创建一个返回符合协议的对象的类。我不在乎课程是什么,只是我可以发送消息。当我尝试以下操作时,会生成一个编译错误: 错误: 协议“ HasAwesomeness”只能用作一般约束,因为它具有“自我”或相关类型要求 可以想像,其目的是返回或基于

  • 问题内容: 我想使用接受单个参数的构造函数从其对象实例化一个对象。 这是一些符合我想要的代码: 但是,它实例化没有文本的对象。我想使用接受字符串作为初始文本的构造函数。有没有一种方法可以从对象中选择特定的构造函数? 问题答案: 调用no- arg构造函数(不带任何参数的构造函数)。为了调用其他构造函数,您需要使用反射包()。 获取一个这样的实例: 的调用指定您要使用单个参数的构造函数。现在创建一个

  • 我预计我的< code>UICollectionView会有问题,基本上当我清除约束时,它会完美地滚动,尽管我无法到达底部(但那是另一天的事情),但是宽度太大了,我只能看到我的< code>UICollectionView的左半部分。 现在,当我设置使其适合屏幕时,它将不再滚动。即使UIRefreshControl也不会触发。 我没有办法了,有人有线索吗?或者解决办法? 非常感谢! 编辑:它不会滚