【问题标题】:Multiple constructors in python, using inheritancepython中的多个构造函数,使用继承
【发布时间】:2013-10-18 18:36:57
【问题描述】:

我有一个 AbstractDataHandle 类,带有他的 init 方法和一个 Classifier。我想在 Classifier 中有两个构造函数,Java 之类的。一个继承自它的超类,一个是全新的。

可能是这样的(但我打算“保留”这两个构造函数):

class AbstractDataHandle():
    def __init__(self, elements, attributes, labels):
        self._load(elements, attributes, labels)


class Classifier(AbstractDataHandle):
    def __init__(self, classifier="LinearSVC", proba=False):
        self._fit(classifier, proba)

我可以在一个类中有两个构造函数吗? 如果是,我可以从超类继承构造函数并添加一个新构造函数吗?

提前谢谢你。

【问题讨论】:

  • 你可以让子类构造函数通过superstackoverflow.com/questions/576169/…调用超类构造函数
  • 感谢您的回答。问题是,调用 super,我将只有一个构造函数。如果参数的数量(和/或类型)不同,则在 Java 中可能有多个。我想知道python中是否存在同样的东西。
  • 您可以使用@classmethod 来创建任意数量的类似构造函数的方法。
  • 具体为什么需要两个构造函数?你可能想看看类方法来模拟这种行为stackoverflow.com/a/141777/735204

标签: python oop inheritance python-2.7 constructor


【解决方案1】:

一个类中不能有两个构造函数。

构造函数必须命名为__init__。而且,与 Java 不同,Python 不允许通过参数类型重载函数或方法。所以,如果你有两个构造函数,它们都是同一个函数。

有几种方法可以解决这个问题。


使用@classmethods 作为替代构造函数:

class Breakfast(object):
    @classmethod
    def from_eggs(cls, eggs):
        obj = cls()
        obj.spam, obj.eggs = 5, eggs
        return obj

    @classmethod
    def from_spam_and_eggs(cls, spam, eggs):
        obj = cls()
        obj.spam, obj.eggs = spam, eggs
        return obj

标准库中的一个简单示例是datetime.datetime,除了default之外,它还可以使用now、fromtimestamp或其他一些替代构造函数来构造。


使用默认值、仅关键字和/或可变参数参数来创建可以以不同方式调用的单个构造函数:

class Breakfast(object):
    def __init__(self, eggs=0, spam=5):
        self.spam, self.eggs = spam, eggs

int 就是一个例子:您可以从字符串和基数创建它,或者从知道如何将自身转换为整数的单个参数创建它。


创建每个具有不同构造函数的子类:

class Breakfast(object):
    pass

class HealthyBreakfast(object):
    def __init__(self, spam):
        self.spam, self.eggs = spam, 0

class NormalBreakfast(object):
    def __init__(self, spam, eggs):
        self.spam, self.eggs = spam, eggs

在任何这些情况下,您都可以将共性分解到一个“基本”初始化程序中。例如:

class Breakfast(object):
    def __init__(self, eggs, spam):
        self.spam, self.eggs = spam, eggs

class HealthyBreakfast(object):
    def __init__(self, spam):
        super(HealthyBreakfast, self).__init__(0, spam)

当然,在任何情况下,早餐都不可能没有垃圾邮件。

【讨论】:

  • 只是为了记录,__init__ 不是构造函数,它(顾名思义)是一个初始化器。正确的构造函数是__new__
  • @brunodesthuilliers:文档反复调用 __init__ 构造函数(例如,here)。这与其他语言是一致的——例如,在 C++ 中,与获取初始化值的类同名的方法是构造函数;分配存储的方法被称为new 是分配器。
  • @brunodesthuilliers:当文档仔细讲时,“构造函数”仅指对类对象的调用,最终可能会调用__new__ 和/或@ 987654341@,不是任何一种方法。但是当他们说话不小心的时候,总是__init__,而不是__new__,这叫构造函数。
  • 该文档还使用术语“变量”和“赋值”而不是“名称”和“绑定”,顺便说一句,这让来自 C 世界的人非常困惑。此外,__new__ 不一定会“分配”任何存储空间 - 它可以返回您希望返回的任何内容,包括已经存在的对象。
  • @brunodesthuilliers:您可以争辩说文档措辞不当。但是说“__init__ 不是构造函数……正确的构造函数是__new__……”是错误的。文档调用__init__ 而不是__new__ 构造函数,而__init__ 与其他语言的构造函数类似;你不能只是重新定义术语来表达与其他人不同的意思,然后说“根据我的特殊定义,你是不正确的。”
【解决方案2】:

您可以使用类方法,它们用作工厂方法。这是多个构造函数的最佳方法。第一个参数 'cls' 是类本身,而不是实例,因此类方法中的 cls('Truck') 会调用 Car 类的构造函数。

class Car(object):
    def __init__(self, type='car'):
        self.car_type = type

    @classmethod
    def Truck(cls):
        return cls('Truck')

    @classmethod
    def Sport(cls):
        return cls('Sport')

    @classmethod
    def Van(cls):
        return cls('Van')

那你这样调用工厂方法:

mycar = Car.Sport()

【讨论】:

    【解决方案3】:

    接受的答案中有方法,但我认为这个方法相当灵活。它很复杂,但非常灵活。

    当类被实例化时,init 调用一个方法并传递一个字符串参数(从实例化中获得)。该函数使用条件调用正确的“构造函数”函数来初始化您的值,假设您有不同的可能起始值集。

    如果您需要提供其他参数(例如,可能仅在运行时有值),您可以在 init() 中使用默认值来允许可选参数,并在 中初始化这些参数像往常一样初始化。

    class MyClass:
    def __init__(self,argsSet1, otherAttribute="Assigning this default value 
                 to make this other argument optional",):
        self.selectArgSet(argsSet1)
        self.otherAttribute = otherAttribute
        print otherAttribute
    def selectArgSet(self,ArgSet1):
        if ArgSet1 == "constructorArgSet1":
            self.constructorArgSet1()
        elif ArgSet1 == "constructorArgSet2":
            self.constructorArgSet2()
    def constructorArgSet1(self):
        print "Use this method as Constructor 1"
        self.variable1 = "Variable1 value in Constructor 1"
        self.variable2 = "Variable2 value in Constructor 1"
        print self.variable1
        print self.variable2
    def constructorArgSet2(self):
        print "Use this method as Constructor 2"
    
    
          self.variable1 = "Variable1 value in Constructor 2"
            self.variable2 = "Variable2 value in Constructor 2"
            print self.variable1
            print self.variable2
    
    myConstructor_1_Instance = MyClass("constructorArgSet1")
    myConstructor_2_Instance = MyClass("constructorArgSet2", "You can still 
                                               initialize values normally")
    

    其输出为:

    将此方法用作构造函数1

    构造函数 1 中的变量 1 值

    构造函数 1 中的变量 2 值

    分配默认值以使其他参数可选

    将此方法用作构造函数2

    构造函数 2 中的变量 1 值

    构造函数 2 中的变量 2 值

    你仍然可以正常初始化值

    【讨论】:

      猜你喜欢
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 2015-01-17
      • 2014-10-11
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      相关资源
      最近更新 更多