Python:初始化类的多种方法

Jay*_*hik 4 python

A我有一个可以通过两种不同方式“初始化”的类。因此,我根据本文的第二个答案为其提供了一个“类似工厂”的界面。

class A(object):

    @staticmethod
    def from_method_1(<method_1_parameters>):
        a = A()
        # set parameters of 'a' using <method_1_parameters>
        return a

    @staticmethod
    def from_method_2(<method_2_parameters>):
        a = A()
        # set parameters of 'a' using <method_2_parameters>
        return a
Run Code Online (Sandbox Code Playgroud)

这两种方法非常不同,我不能将它们的参数插入到类的__init__. 因此,类A应该使用以下方式初始化:

a = A.from_method_1(<method_1_parameters>)
Run Code Online (Sandbox Code Playgroud)

或者

a = A.from_method_2(<method_2_parameters>)
Run Code Online (Sandbox Code Playgroud)

但是,仍然可以调用“默认初始化” A

a = A() # just an empty 'A' object
Run Code Online (Sandbox Code Playgroud)

有什么办法可以防止这种情况发生吗?我不能只是NotImplementedError从筹集资金__init__,因为两个“工厂方法”也使用它。

或者我是否需要使用完全不同的方法。

Aur*_*ang 5

自从这个问题被提出以来已经很长时间了,但我认为它很有趣,值得重提。

当我第一次看到你的问题时,这个private constructor概念就突然出现在我的脑海中。这是一个在其他 OOP 语言中很重要的概念,但由于 Python 不强制隐私,自从 Python 成为我的主要语言以来,我并没有真正考虑过它。

因此,我变得好奇,并发现了这个“Python中的私有构造函数”问题。它几乎涵盖了有关该主题的所有内容,我认为第二个答案在这里可能会有所帮助。

基本上,它使用名称修饰来声明伪私有类属性(Python 中没有私有变量之类的东西)并将类对象分配给它。因此,您将拥有一个 as-private-as-Python 允许变量来检查您的初始化是从类方法还是从外部调用进行的。我根据这个机制做了如下的例子:

class A(object):
    __obj = object()

    def __init__(self, obj=None):
        assert(obj == A.__obj), \
            'A object must be created using A.from_method_1 or A.from_method_2'

    @classmethod
    def from_method_1(cls):
        a = A(cls.__obj)
        print('Created from method 1!')
        return a

    @classmethod
    def from_method_2(cls):
        a = A(cls.__obj)
        print('Created from method 2!')
        return a
Run Code Online (Sandbox Code Playgroud)

测试:

>>> A()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "t.py", line 6, in __init__
    'A object must be created using A.from_method_1 or A.from_method_2'
AssertionError: A object must be created using A.from_method_1 or A.from_method_2
>>> A.from_method_1()
Created from method 1!
<t.A object at 0x7f3f7f2ca450>
>>> A.from_method_2()
Created from method 2!
<t.A object at 0x7f3f7f2ca350>
Run Code Online (Sandbox Code Playgroud)

但是,由于此解决方案是一种名称修改的解决方法,因此如果您知道如何查找它,它确实有一个缺陷:

>>> A(A._A__obj)
<t.A object at 0x7f3f7f2ca450>
Run Code Online (Sandbox Code Playgroud)