Проблема наследования при создании объектов - PullRequest
0 голосов
/ 01 мая 2018

Person.py

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

    @classmethod
    def parse(cls, name):
        return cls(name)

Employee.py

class Employee(Person):
    def __init__(self, ename, esalary):
        super().__init__(ename)
        self.salary = esalary

    @classmethod
    def parse(cls, data):
        person = super().parse(data["name"])
        person.salary = data["salary"]
        return person

Customer.py

class Customer(Person):
    def __init__(self, ename, country):
        super().__init__(ename)
        self.country = country

    @classmethod
    def parse(cls, data):
        person = super().parse(data["name"])
        person.country = data["country"]
        return person

main.py

emp_data = {
    "name": "john",
    "salary": 1000
}
emp = Employee.parse(emp_data)
print(type(emp))
print(emp.name)
print(emp.salary)


cust_data = {
    "name": "peter",
    "country": "USA"
}
cust = Customer.parse(cust_data)
print(type(cust))
print(cust.name)
print(cust.country)

ошибка

TypeError                                 Traceback (most recent call last)
<ipython-input-32-a5abd51d9870> in <module>()
     36     "salary": 1000
     37 }
---> 38 emp = Employee.parse(emp_data)
     39 print(type(emp))
     40 print(emp.name)

<ipython-input-32-a5abd51d9870> in parse(cls, data)
     14     @classmethod
     15     def parse(cls, data):
---> 16         person = super().parse(data["name"])
     17         person.salary = data["salary"]
     18         return person

<ipython-input-32-a5abd51d9870> in parse(cls, name)
      5     @classmethod
      6     def parse(cls, name):
----> 7         return cls(name)
      8 
      9 class Employee(Person):

TypeError: __init__() missing 1 required positional argument: 'esalary'

Этот пример просто для воспроизведения проблемы в реальном коде. Фактические функции анализа включают сложную логику.

В приведенном выше примере классы Employee и Customer расширяют класс Person. Согласно ошибке, метод init класса Person, который вызывается parse из того же класса, ожидает esalary. Но у метода Person init нет свойства esalary.

Что не так с моей программой? Я думаю, что не правильно понял наследование. Пожалуйста, поправьте меня. Прежде всего, правильно ли я структурировал свою программу?

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Рассмотрим следующее:

class Foo():
    @classmethod
    def p(cls):
        print(cls.__name__)

 class Bar(Foo):
     @classmethod
     def p(cls):
         super().p()

bar = Bar()
bar.p()

Это напечатает "Бар". Объект класса, переданный в Foo.p при вызове из Bar.p, на самом деле является классом Bar, а не классом Foo.

Так что в вашем коде, когда вы вызываете Person.parse - Employee.parse, ваша строка в Person.parse, return cls(name) фактически вызывает Employee(name), но init Employee принимает 2 позиционных аргумента.

Чтобы ваш код работал с этой структурой, ваши __init__ должны иметь одинаковую подпись или, по крайней мере, совместимые подписи (например, путем добавления * args к Person методу __init__ и передачи их в конструктор).

0 голосов
/ 01 мая 2018

Ваша проблема в том, что parse вызывает cls(name), который имеет только один аргумент, но cls равен Employee или Customer, необязательно Person. Вы должны либо предоставить дополнительные аргументы (зарплата / страна) во время создания (когда вы вызываете parse), либо дать им значение по умолчанию, если они не предоставлены.

Либо предоставьте дополнительные необходимые аргументы конструктору через parse:

@classmethod
def parse(cls, name, *args, **kwargs):
    return cls(name, *args, **kwargs)

, который позволит вам сделать что-то вроде:

Employee.parse(name, salary)  # Really no different than Employee(name, salary)

Или добавьте значения по умолчанию к этим параметрам в дочерних конструкторах, чтобы они могли быть созданы только с именем:

class Customer(Person):
    def __init__(self, ename, country=None):
        # ...

class Employee(Person):
    def __init__(self, ename, esalary=None):
        # ...

Обратите внимание, что это может привести к тому, что в этих атрибутах будут появляться значения None, но это неизбежно, если вы хотите создать новый, скажем, объект Employee и не хотите также предоставлять зарплату на в то же время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...