Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.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 使用classmethods实现替代构造函数,如何向这些替代构造函数添加函数?_Python - Fatal编程技术网

Python 使用classmethods实现替代构造函数,如何向这些替代构造函数添加函数?

Python 使用classmethods实现替代构造函数,如何向这些替代构造函数添加函数?,python,Python,我有一个类,它可以通过使用类方法的替代构造函数来构造 class A: def __init__(self, a, b): self.a = a self.b = b @classmethod def empty(cls, b): return cls( 0 , b) 因此,假设我现在也可以做A.empty(),而不是像A()那样构造A 为了方便用户,我想进一步扩展这个empty方法,这样我就可以通过A

我有一个类,它可以通过使用类方法的替代构造函数来构造

class A:

    def __init__(self, a, b):
            self.a = a
            self.b = b

    @classmethod
    def empty(cls, b):
        return cls( 0 , b)
因此,假设我现在也可以做
A.empty()
,而不是像
A()
那样构造
A

为了方便用户,我想进一步扩展这个
empty
方法,这样我就可以通过
A.empty()
以及更专业但密切相关的
A.empty.typeI()
A.empty.typeII()
来初始化
A

我天真的做法并没有达到我的目的:

class A:

    def __init__(self, a, b):
            self.a = a
            self.b = b

    @classmethod
    def empty(cls, b):

        def TypeI(b):
            return cls( 0 , b-1)

        def TypeII(b):
            return cls( 0 , b-2)

        return cls( 0 , b)

有谁能告诉我这是怎么做到的(或者至少能说服我为什么这是个糟糕的主意)。我想强调的是,对于使用,我认为这种方法对于用户来说非常方便和清晰,因为功能是直观地分组的。

通常最好有统一的类接口,这意味着不同的使用应该彼此一致。我认为<代码> Apple()/代码>和<代码> A.Wo.Type()/代码>彼此不一致,因为前缀<代码> A.empty < /代码>在每一个中都意味着不同的东西。

更好的接口是:

class A:
    @classmethod
    def empty_default(cls, ...): ...
    @classmethod
    def empty_type1(cls, ...): ...
    @classmethod
    def empty_type2(cls, ...): ...
或:


通常最好有统一的类接口,这意味着不同的用法应该彼此一致。我认为<代码> Apple()/代码>和<代码> A.Wo.Type()/代码>彼此不一致,因为前缀<代码> A.empty < /代码>在每一个中都意味着不同的东西。

更好的接口是:

class A:
    @classmethod
    def empty_default(cls, ...): ...
    @classmethod
    def empty_type1(cls, ...): ...
    @classmethod
    def empty_type2(cls, ...): ...
或:


您不能这样做,因为
A.empty.something
需要将底层方法对象绑定到类型,因此您可以实际调用它。Python根本不会这样做,因为类型的成员是
空的
,而不是
TypeI

因此,您需要做的是在您的类型中有一些返回绑定类方法的对象
为空
(例如a)。问题是,我们还不能访问类型,因为我们使用
结构定义它。因此,我们无法访问其成员来设置这样的对象。相反,我们必须在事后进行:

class A:
    def __init__ (self, a, b):
        self.a = a
        self.b = b

    @classmethod
    def _empty_a (cls, b):
        return cls(1, b)

    @classmethod
    def _empty_b (cls, b):
        return cls(2, b)

A.empty = SimpleNamespace(a = A._empty_a, b = A._empty_b)
现在,您可以访问该成员的项并获取绑定方法:

>>> A.empty.a
<bound method type._empty_a of <class '__main__.A'>>
>>> A.empty.a('foo').a
1
神奇的是,它起作用了:

>>> A.empty.empty_a
<bound method type._empty_a of <class '__main__.A'>>
>>A.empty.empty\u A

既然我们已经以某种方式实现了,当然我们应该讨论一下这是否真的是你想要做的事情。我的意见是你不应该。您已经可以从所做的努力中看出,这不是Python通常所做的事情。这已经是一个好迹象,表明你不应该这么做,因此,期望用户键入类方法的全名可能是一个更好的主意。我上面的例子的结构当然是
a.empty.empty\u a
比a.empty\u a更长。但即使是你的名字,也没有理由不能只是下划线而不是点


而且,您可以简单地在一个方法中添加多个默认路径。提供默认参数值,或使用合理的回退,您可能不需要很多类方法来创建类型的替代版本。

您不能这样做,因为
A.empty。有些东西需要将基础方法对象绑定到类型,因此您可以实际调用它。Python根本不会这样做,因为类型的成员是
空的
,而不是
TypeI

因此,您需要做的是在您的类型中有一些返回绑定类方法的对象
为空
(例如a)。问题是,我们还不能访问类型,因为我们使用
结构定义它。因此,我们无法访问其成员来设置这样的对象。相反,我们必须在事后进行:

class A:
    def __init__ (self, a, b):
        self.a = a
        self.b = b

    @classmethod
    def _empty_a (cls, b):
        return cls(1, b)

    @classmethod
    def _empty_b (cls, b):
        return cls(2, b)

A.empty = SimpleNamespace(a = A._empty_a, b = A._empty_b)
现在,您可以访问该成员的项并获取绑定方法:

>>> A.empty.a
<bound method type._empty_a of <class '__main__.A'>>
>>> A.empty.a('foo').a
1
神奇的是,它起作用了:

>>> A.empty.empty_a
<bound method type._empty_a of <class '__main__.A'>>
>>A.empty.empty\u A

既然我们已经以某种方式实现了,当然我们应该讨论一下这是否真的是你想要做的事情。我的意见是你不应该。您已经可以从所做的努力中看出,这不是Python通常所做的事情。这已经是一个好迹象,表明你不应该这么做,因此,期望用户键入类方法的全名可能是一个更好的主意。我上面的例子的结构当然是
a.empty.empty\u a
比a.empty\u a
更长。但即使是你的名字,也没有理由不能只是下划线而不是点


而且,您可以简单地在一个方法中添加多个默认路径。提供默认参数值,或使用合理的回退,您可能不需要很多类方法来创建类型的替代版本。

您可以通过将
设为空
而不是类方法的嵌套类来实现所需。最重要的是,它提供了一个方便的名称空间——从未创建过它的实例——在其中放置各种替代构造函数,并且可以轻松地进行扩展

class A(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return 'A({}, {})'.format(self.a, self.b)

    class Empty(object):  # nested class
        def __new__(cls, b):
            return A(0, b)  # ignore cls & return instance of enclosing class

        @staticmethod
        def TypeI(b):
            return A(0, b-1)

        @staticmethod
        def TypeII(b):
            return A(0, b-2)

a = A(1, 1)
print('a: {}'.format(a))      # --> a: A(1, 1)
b = A.Empty(2)
print('b: {}'.format(b))      # --> b: A(0, 2)
bi = A.Empty.TypeI(4)
print('bi: {}'.format(bi))    # --> bi: A(0, 3)
bii = A.Empty.TypeII(6)
print('bii: {}'.format(bii))  # --> bii: A(0, 4)

您可以通过将
设为空
而不是类方法来实现所需的功能。最重要的是,它提供了一个方便的名称空间——从未创建过它的实例——在其中放置各种替代构造函数,并且可以轻松地进行扩展

class A(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return 'A({}, {})'.format(self.a, self.b)

    class Empty(object):  # nested class
        def __new__(cls, b):
            return A(0, b)  # ignore cls & return instance of enclosing class

        @staticmethod
        def TypeI(b):
            return A(0, b-1)

        @staticmethod
        def TypeII(b):
            return A(0, b-2)

a = A(1, 1)
print('a: {}'.format(a))      # --> a: A(1, 1)
b = A.Empty(2)
print('b: {}'.format(b))      # --> b: A(0, 2)
bi = A.Empty.TypeI(4)
print('bi: {}'.format(bi))    # --> bi: A(0, 3)
bii = A.Empty.TypeII(6)
print('bii: {}'.format(bii))  # --> bii: A(0, 4)

这里是my的一个增强的实现,正如一位评论者所说,它“很好地处理继承”。您可能不需要这样做,但其他人可能会做类似的事情

它通过使用动态创建和添加嵌套的
Empty
类来实现这一点,类似于另一个答案中所示的类。T