Наследование Python от конструктора

#python #inheritance #parent-child #subclass #super

#python #наследование #родитель-потомок #подкласс #супер

Вопрос:

person.py

 class Person:
   """---A class representing a person---"""
   # Person constructor
   def __init__(self,n,a): 
       self.full_name = n
       self.age = a
class Student(Person):
    # Student constructor   
    def __init__(self,n,a,s):
       Person.__init__(self,n,a)
       self.school = s
  

driver.py

 from person import *
    a = Student("Alice", 19, "Univ")
  

Он выдает TypeError: __init__() takes 3 positional arguments but 4 were given
Я попытался изменить класс Student на следующий:

 class Student(Person):
        # Student constructor   
        def __init__(self,n,a,s):
           super().__init__(n,a)
           self.school = s
  

Ошибка все еще существует.

Почему это происходит? super() Требуется ли ключевое слово для добавления новых атрибутов?

РЕДАКТИРОВАТЬ: проблема решена. В исходном коде была проблема с отступом, отображающая это странное поведение, поэтому вопрос следует закрыть.

Ответ №1:

Эта строка:

 Person.__init__(self,n,a)
  

Проблема. Напомним, что методам автоматически передается ссылка на самих себя, поэтому вы просто передали вторую.

Для этого также существует устоявшийся шаблон:

 class Person
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self, school, *args):
        super().__init__(*args)
        self.school = school

student = Student('Washington Elementary', "Johnny Go'gettem", 10)
  

хотя обратите внимание, что простого удаления вашей ссылки self в Person.__init__ вызове внутри Student.__init__ было бы достаточно.


Обратите внимание, что вы можете переопределить поведение метода по умолчанию с помощью нескольких декораторов, которые становятся весьма полезными в определенных ситуациях. Здесь не применяется ни то, ни другое, а просто немного знаний, чтобы немного подразнить ваш мозг:

 def SomeClass:
    attr = "class-scoped"

    def __init__(self):
        self.attr = "instance-scoped"

    def some_method(self):
        return self.attr == "instance-scoped"

    @classmethod
    def some_classmethod(cls):
        return cls.attr == "class-scoped"

    @staticmethod
    def some_staticmethod():
        return "I'm not given a "self" parameter at all!"
  

classmethod s особенно полезны в качестве альтернативных конструкторов

 class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_tuple(cls, tup) -> "Person":
        """Expects a tuple of (name, age) and constructs a Person"""
        name, age = tup
        return cls(name, age)

    @classmethod
    def from_dict(cls, dct) -> "Person":
        """Expects a dictionary with keys "name" and "age" and constructs a Person"""
        try:
            name = dct['name']
            age = dct['age']
        except KeyError:
            raise ValueError(f"Dictionary {dct} does not have required keys 'name' and 'age'")
        else:
            return cls(name, age)
  

Комментарии:

1. Я понял, что проблема не в конструкторе itself….It это с некоторым плохим отступом от исходного кода, который я пишу. Я случайно добавляю пробелы или табуляции для комментариев, что приводит к плохому поведению в логике. После удаления пробелов все работает нормально. Я просто не мог сосредоточиться на написании Java или C, выясняя, как учитываются отступы или пробелы в Python!

2. отступ @Jerry213 изменит поведение, но упомянутое вами сообщение об ошибке ожидается, учитывая опубликованный вами код, отступ которого кажется правильным. Рассмотрите пробелы в Python, эквивалентные фигурным скобкам в Java / C — это поможет 🙂