Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:创建幂等初始值设定项_Python_Python 3.x - Fatal编程技术网

Python:创建幂等初始值设定项

Python:创建幂等初始值设定项,python,python-3.x,Python,Python 3.x,在python中创建幂等初始值设定项的正确方法是什么?所谓幂等元,我的意思是,如果objectx是类A的实例,那么A(x)就是x(类似于正则表达式模式、冻结集、字符串和元组)。我可以想出三种解决办法: 覆盖新的 class A: def __new__(cls, *args, **kwargs): if not kwargs and len(args) == 1 and isinstance(args[0],cls): return args[0] return

在python中创建幂等初始值设定项的正确方法是什么?所谓幂等元,我的意思是,如果object
x
是类
A
的实例,那么
A(x)就是x
(类似于正则表达式模式、冻结集、字符串和元组)。我可以想出三种解决办法:

  • 覆盖新的

    class A:
      def __new__(cls, *args, **kwargs):
        if not kwargs and len(args) == 1 and isinstance(args[0],cls):
           return args[0]
        return super().__new__(*args, **kwargs)
      def __init__(*args, **kwargs):
        # check that init isn't called on the same object twice
        if not kwargs and len(args) == 1 and isinstance(args[0],cls):
           return
        ... # actual initialization goes here
    
  • 将实际类隐藏在初始化函数后面

    class A:
        ...
    def a(*args, **kwargs):
        if not kwargs and len(args) == 1 and isinstance(args[0], A):
            return args[0]
        return A(*args, **kwargs)
    
  • 创建元类

    class Meta(type):
        def __call__(cls, *args, **kwargs):
            if not kwargs and len(args) == 1 and isinstance(args[0], cls):
                return args[0]
            return super().__call__(*args, **kwargs)
    class A(metaclass = Meta):
        ...
    
    对我来说,所有这些解决方案似乎都很老套,而且每个都有明显的缺点。做这件事的方法是什么


  • 规范的方法是让
    \uuuuu new\uuuu
    返回对象本身。这正是
    frozenset
    、字符串和元组所做的,尽管是在C代码中

    例如,
    frozenset.\uuuuu new\uuuuu
    是使用:

    /* frozenset(f) is idempotent */
    if (PyFrozenSet_CheckExact(iterable)) {
        Py_INCREF(iterable);
        return iterable;
    }
    
    考虑到这些是不可变的类型,因此它们不定义
    \uuuu init\uuu
    方法(或等效的C)。这很重要,因为从
    \uuuu new\uuuu
    返回作为当前类(或子类)实例的对象将自动触发
    \uuuu init\uuuu
    ,如果已定义,则将调用该对象。您不希望在此处重新初始化对象

    因此,正确的实现将把所有内容放入
    \uuuuu new\uuuu


    很好的回答,谢谢。虽然我要说的是,我确实确保了init方法不会影响以这种方式返回的对象。@Bentheii:我知道,但这只是在不可变对象上使用
    \uuuu init\uuu
    的一种变通方法。
    class A:
        def __new__(cls, *args, **kwargs):
            if not kwargs and len(args) == 1 and isinstance(args[0], cls):
                # A(instance_of_A) is idempotent
                return args[0]
    
            instance = super().__new__(*args, **kwargs)
            # actual initialization goes here
            return instance
    
        # **NO** __init__ method for 'immutable' objects