当前位置: 首页 > 面试题库 >

有没有一种方法可以实例化一个类而无需调用__init__?

张财
2023-03-14
问题内容

有没有办法绕过__init__python中的类的构造函数?

例:

class A(object):    
    def __init__(self):
        print "FAILURE"

    def Print(self):
        print "YEHAA"

现在,我想创建一个实例A。看起来可能像这样,但是这种语法不正确。

a = A
a.Print()

编辑:

一个更复杂的示例:

假设我有一个对象C,目的是存储一个参数并对其进行一些计算。但是,该参数并未按原样传递,而是被嵌入到巨大的参数文件中。它可能看起来像这样:

class C(object):
    def __init__(self, ParameterFile):
        self._Parameter = self._ExtractParamterFile(ParameterFile)
    def _ExtractParamterFile(self, ParameterFile):
        #does some complex magic to extract the right parameter
        return the_extracted_parameter

现在,我想转储并加载该对象的实例C。但是,在加载该对象时,我只有一个变量,self._Parameter并且无法调用构造函数,因为它需要参数文件。

    @staticmethod
    def Load(file):
        f = open(file, "rb")
        oldObject = pickle.load(f)
        f.close()

        #somehow create newObject without calling __init__
        newObject._Parameter = oldObject._Parameter
        return newObject

换句话说,在不传递参数文件的情况下无法创建实例。但是,在我的“真实”情况下,它不是参数文件,而是一些巨大的数据,我当然不希望在内存中随身携带,甚至不希望将其存储到磁盘上。

而且由于我想C从方法中返回一个实例,所以Load我不得不以某种方式调用构造函数。

旧编辑:

一个更复杂的示例,它解释了 为什么 我要问这个问题:

class B(object):    
    def __init__(self, name, data):
        self._Name = name
        #do something with data, but do NOT save data in a variable

    @staticmethod
    def Load(self, file, newName):
        f = open(file, "rb")
        s = pickle.load(f)
        f.close()

        newS = B(???)
        newS._Name = newName
        return newS

如您所见,由于data未存储在类变量中,因此无法将其传递给__init__。当然,我可以简单地存储它,但是如果数据是一个巨大的对象,我不想一直将其存储在内存中,甚至不想将其保存到磁盘上怎么办?


问题答案:

可以__init__通过__new__直接致电
规避。然后,您可以创建给定类型的对象,并为调用替代方法__init__。这是pickle可以做到的。

但是,首先,我非常想强调一点,这是您 不应该
做的事情,无论您要达到什么目的,都有更好的方法可以做到,其中一些已在其他答案中提到。特别是,跳过call是一个 主意__init__

创建对象时,或多或少会发生这种情况:

a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)

您可以跳过第二步。

这就是为什么您 不应该这样
做的原因:
的目的__init__是初始化对象,填写所有字段并确保__init__还调用父类的方法。有了pickle它是一个例外,因为它尝试存储与该对象关联的所有数据(包括为该对象设置的
任何 字段/实例变量),因此,__init__上次设置的任何内容都将由pickle还原,没有需要再次调用它。

如果跳过__init__并使用替代的初始化程序,则会有某种形式的代码重复-
实例变量将在两个位置填充,并且很容易在其中一个初始化程序中错过其中一个,或者不小心使其中一个两个填充字段的行为不同。这样就可以发现难以跟踪的细微错误(您必须
知道 调用了哪个初始化程序),并且代码将更难以维护。更不用说如果您使用继承会陷入更大的混乱-
问题将在继承链中蔓延,因为您必须在链的各处使用此替代初始化器。

通过这样做,您或多或少会覆盖Python的实例创建并自行创建。Python已经为您很好地做到了这一点,无需重新发明它,它会使使用您的代码的人们感到困惑。

最好的替代__init__方法是:对于将所有实例变量正确初始化的类的所有可能实例,请使用单个方法。对于不同的初始化模式,请使用以下两种方法之一:

  1. __init__通过使用可选参数,为处理您的案件提供不同的签名。
  2. 创建几个用作替代构造函数的类方法。确保它们都按正常方式(即调用__init__)创建类的实例,如Roman Bodnarchuk所示,同时执行其他工作或执行其他操作。最好将它们传递给类(并__init__处理)所有数据,但是如果这不可能或不方便,则可以在创建实例并__init__完成初始化之后设置一些实例变量。

如果__init__具有可选步骤(例如,像处理该data参数那样,尽管您必须更具体一些),则可以将其设为可选参数,也可以使之成为执行该处理的常规方法…或同时执行两者。



 类似资料:
  • 问题内容: 我有一个过程密集型任务,我想在后台运行。 用户单击一个页面,PHP脚本运行,最后,根据某些条件(如果需要),它必须运行Shell脚本EG: 当前,我使用shell_exec, 但这 需要脚本等待输出。有什么方法可以执行我想要的命令, 而无需 等待命令完成? 问题答案: 如何添加。 请注意,这也摆脱了stdio和stderr。

  • 问题内容: 我正在研究Java应用程序的一部分,该应用程序将图像作为字节数组,将其读入实例,然后将其传递给第三方库进行处理。 对于单元测试,我想获取一个图像(从磁盘上的文件中获取),并断言它等于代码处理过的同一图像。 我的 预期 是使用从磁盘上的PNG文件读取的。 我的 测试 代码将相同的文件读入A,并将其作为PNG写入字节数组,以提供给被测系统。 当被测系统将字节数组写入新数组时,我想断言这两个

  • 问题内容: 嗨,我想使用WMI类来查找应用程序和产品信息。但是问题是我想使用Java或任何脚本语言(如python,javascript或perl)。我听说过JWMI,这可能是一个选择。有人可以帮我吗??? 问题答案: JavaScript和Java不是一回事。 JavaScript Windows脚本宿主(WSH)下提供了JavaScript。有了它,访问WMI相当容易: jWMI(Java)

  • 问题内容: 假设我们有这个流 我想在地图中保存几对相邻的字符串,其中第一个以“ err”开头。 我想到的就是这样 但是我对它并不完全满意,主要有两个原因 我在“滥用” 功能。在Stream API中,每个函数都有其明确的定义明确的目的:应该计算最大值,应该根据条件进行过滤,应该产生递增的累加值,依此类推。 这样做会使我无法使用Streams强大的机制:如果我想将搜索范围限制在前两个结果中,该怎么办

  • 问题内容: 给定一个结构: 以及带有结构名称的字符串 要么 如何从字符串名称而不是结构创建结构的实例?我的想法是,我将使用链接到二进制文件中的所有结构创建一个应用程序,但根据字符串创建运行时实例。(某种元元) 问题答案: Go中没有类型的中央注册表,因此在一般情况下您无法提出要求。 您可以使用从字符串到对应于每种类型的值的映射来手动建立自己的注册表来支持这种功能。例如: 然后,您可以创建如下类型的

  • 但我对它并不完全满意,主要有两个原因 我“滥用”了函数。在Stream API中,每个函数都有其明确、明确的用途:被认为是计算最大值,被认为是根据条件进行筛选,被认为是生成增量累加的值,等等。 这样做会阻止我使用Streams强大的机制:如果我想将搜索限制在前两个结果上怎么办? 这里我使用了,因为(据我所知)它是唯一一个允许比较两个值的函数,而这些值可以在某种程度上导致类似于“当前值”和“下一个值