Подтвердить что ты не робот

Несколько конструкторов в python, используя наследование

У меня есть класс AbstractDataHandle, с его методом init и классификатором классов. Я хотел бы иметь два конструктора в 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)

Могу ли я иметь два конструктора в одном классе? Если да, могу ли я иметь конструктор, унаследованный от суперкласса, и добавить новый?

Спасибо заранее.

4b9b3361

Ответ 1

У вас не может быть двух конструкторов в одном классе.

Конструкторы должны быть названы __init__. И, в отличие от Java, Python не позволяет перегружать функции или методы по типу своих аргументов. Итак, если у вас было два конструктора, они оба были бы одной и той же функцией.

Есть несколько способов обойти это.


Используйте @classmethod в качестве альтернативных конструкторов:

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, который можно построить с помощью 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)

Конечно, ни в коем случае нельзя есть завтрак без спама.

Ответ 2

Вы можете использовать методы класса, которые работают как методы factory. Это лучший подход для нескольких конструкторов. Первый аргумент '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')

Затем вы вызываете метод factory следующим образом:

mycar = Car.Sport()

Ответ 3

В принятом ответе есть методы, но я думаю, что это довольно гибко. Он запутан, но очень гибкий.

Когда класс инициируется, init вызывает метод и передает ему строковый аргумент (полученный от экземпляра). Эта функция использует условные выражения для вызова правой функции "конструктор" для инициализации ваших значений, допустим, у вас есть разные наборы возможных начальных значений.

Если вам нужно указать другие аргументы (например, которые могут иметь значение только во время выполнения), вы можете использовать значения по умолчанию в 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

Значение Variable1 в конструкторе 1

Значение Variable2 в конструкторе 1

Назначьте значение по умолчанию, чтобы сделать этот другой аргумент необязательным

Используйте этот метод как конструктор 2

Значение Variable1 в конструкторе 2

Значение Variable2 в конструкторе 2

Вы все равно можете инициализировать значения