2013-10-10 2 views
11

У меня есть класс AbstractDataHandle, с его методом init и классификатором классов. Я хотел бы иметь два конструктора в Classifier, например Java. Один унаследован от его суперкласса и один новый.Несколько конструкторов в python, используя наследование

Было бы что-то вроде (но я намерен «держать» два конструктора):

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) 

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

Заранее спасибо.

+2

вы могли бы иметь конструктор подкласса называют суперкласс конструктор через 'супер' http://stackoverflow.com/questions/576169/understanding-python-super-and-init-methods –

+0

Спасибо за ответ. Дело в том, что, позвонив супер, у меня будет только один конструктор. В Java возможно иметь более одного, если число (и/или тип) аргументов различно. Интересно, существует ли то же самое в python. –

+1

Вы можете использовать '@ classmethod', чтобы сделать столько конструктор-подобных методов, сколько хотите. – roippi

ответ

38

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

Конструкторы должны быть названы __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 или несколько других альтернативных Конструкторы, кроме default ,


Использовать по умолчанию многозначного, только с ключевыми словами, и/или параметры переменного аргумента, чтобы сделать один конструктор, который можно назвать по-разному:

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) 

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

+3

Только для записи '__init__' является * не * конструктором, это (как следует из названия) инициализатор , Правильный конструктор - '__new__' –

+4

@brunodesthuilliers: в ​​документации многократнозывается конструктор '__init__' (например, [здесь] (http://docs.python.org/3.3/reference/datamodel.html#object.__init__)) , И это согласуется с другими языками, например, в C++, метод с тем же именем, что и класс, который принимает значения инициализации, является конструктором; метод, который выделяет хранилище и называется 'new', является распределителем. – abarnert

+2

@brunodesthuilliers: Когда документы внимательно говорят, «конструктор» относится только к _call_ к объекту класса, который может в конечном итоге вызвать '__new__' и/или' __init__', а не один из методов. Но когда они говорят небрежно, это всегда '__init__', а не' __new__', это называется конструктором. – abarnert

3

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

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

Когда класс инициируется, 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

Переменная2 значение Конструктор 1

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

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

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

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

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

Смежные вопросы