Python排除实例创建

时间:2017-07-19 08:17:53

标签: python

我在Python类创建方面遇到了一些麻烦。我的任务是使用一些解析方法创建对象。但我想使用doFetch() { fetch('mysite', { ... }) }) .then((response) => response.json()) .then((responseJson) => { this.setState({someData: responseJson.success}); //***** put the result -> state }) .catch((error) => { console.error(error); }) ); } render () { {/* whatever you would like to show for someData */} <Text< {this.state.someData} </Text> } }

关闭基本类创建

例如,我有

__init__

这让我有机会使用像这样的命令创建对象

class A: @classmethod def create_from_file(cls, file): # Create instance form file... return self

但是这段代码让我有机会使用a = A.create_from_file()

创建实例

__init__不会引发异常......

当我尝试添加自己的a = A()方法时,我的解析函数也会引发异常。

__init__

我如何解决这个问题,以及编写这个类的最Pythonic方法是什么?

2 个答案:

答案 0 :(得分:1)

__init__不负责创建实例。它是一个钩子方法,Python在实例创建之后为您调用。你不能阻止那里的实例创建。此外,您不希望阻止所有实例创建,即使您的classmethod必须在某个时间创建实例

由于当您的工厂方法用于创建实例时,您想要做的只是引发异常,因此在__init__方法中引发异常仍然可以。这将阻止新实例被分配到任何地方。您需要做的是区分直接访问和使用的工厂方法。

你可以通过几种不同的方式实现这一点。你可以使用&#34;秘密&#34;只有工厂方法传入的标记:

_token = object()  # unique token to flag factory use

class A:
    def __init__(self, data, _from_factory=None):
        if _from_factory is not _token:
            raise TypeError(f"Can't create {type(self).__name__!r} objects directly")
        self._data = data

    @classmethod
    def create_from_file(cls, file):
        data = file.read()
        return cls(data, _from_factory=_token)

classmethod仍然创建一个实例,仍然为该实例调用__init__,并且因为传入了正确的令牌而没有引发异常。

您可以将您的课程作为模块的实施细节,并仅提供公共工厂功能

def create_from_file(cls, file):
    data = file.read()
    return _A(data)

class _A:
    def __init__(self, data):
        self._data = data

现在公共API只为您提供create_from_file(),领先的下划线告诉开发人员_A()是一个内部名称,不应该依赖于模块外部。

实际实例创建是object.__new__ method的责任;您也可以使用该方法来防止创建新实例。您可以使用与上面显示的相同的令牌方法,您可以通过使用super()来调用原始重写的实现来完全绕过它:

class A:
    def __new__(cls, *args, **kwargs):
        raise TypeError(f"Can't create {cls.__name__!r} objects directly")

    def __init__(self, data):
        self._data = data

    @classmethod
    def create_from_file(cls, file):
        data = file.read()
        # Don't use __new__ *on this class*, but on the next one in the
        # MRO. We'll have to manually apply __init__ now.
        instance = super().__new__(cls)
        instance.__init__(data)
        return instance

此处直接调用A()会引发异常,但在super().__new__中使用classmethod我们会绕过A.__new__实施。

注意:__new__隐含地设为staticmethod,因此当我们从cls调用时,我们必须手动传入classmethod参数。

答案 1 :(得分:0)

如果你只有一个方法来创建对象,那就把它作为构造函数。也就是说,而不是

@classmethod
def create_from_file(cls, file):
  # Create instance form file...
  return self

你会有

def __init__(self, file):
  # Create instance form file...

如果有几种不同的创建对象的方法,那么它们中的一种通常会比其他方法更基础 - 换句话说,其他方法的参数可以是& #34;转换&#34;进入一个方法的参数。例如,您可能有create_from_file()create_from_url()create_from_string(),其中前两种方法基本上读取文件或网址的内容,然后对其执行相同的操作{{1} 1}}。因此,只需将create_from_string()转换为create_from_string(),然后让其他两个方法读取文件或网址,并使用内容调用构造函数。

如果你真的没有单一的&#34;基础&#34;创建对象的方法,可能值得考虑你是否应该有一个基类的不同子类。