Python:初始化类的多种方法

时间:2014-03-13 10:26:11

标签: python

我有一个班级A,可以通过两种不同的方式“初始化”。所以,我根据this post中的第二个答案为它提供了“类似工厂”的界面。

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

这两种方法不同,我不能只将它们的参数插入到类的__init__中。因此,应使用以下命令初始化类A

a = A.from_method_1(<method_1_parameters>)

a = A.from_method_2(<method_2_parameters>)

但是,仍然可以为A调用'default init':

a = A() # just an empty 'A' object

有什么方法可以阻止这种情况吗?我不能只从NotImplementedError提出__init__,因为这两种“工厂方法”也会使用它。

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

1 个答案:

答案 0 :(得分:2)

问了这个问题已经很长时间了,但是我认为它很有趣,可以复活。

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

因此,我好奇了,发现了这个"Private Constructor in Python" question。它涵盖了有关该主题的几乎所有内容,我认为第二个答案可以在这里有所帮助。

基本上,它使用name mangling声明一个伪私有类属性(there isn't such thing as private variables in 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

测试:

>>> 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>

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

>>> A(A._A__obj)
<t.A object at 0x7f3f7f2ca450>