Несколько конструкторов в 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)
Могу ли я иметь два конструктора в одном классе?
Если да, могу ли я иметь конструктор, унаследованный от суперкласса, и добавить новый?
Спасибо заранее.
Ответы
Ответ 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
Вы все равно можете инициализировать значения