继承问题创建对象

时间:2018-05-01 20:19:19

标签: python inheritance

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'

此示例仅用于在实际代码中重现问题。实际的解析函数涉及复杂的逻辑。

在上面的示例中,EmployeeCustomer类扩展了Person类。根据错误,由init调用Person类的parse方法构成同一个类,期待esalary。但esalary init方法上没有Person属性。

我的计划有什么问题?我想我不理解继承。拜托,纠正我。首先,我是否正确构建了我的程序?

2 个答案:

答案 0 :(得分:4)

您的问题是parse调用cls(name),只有一个参数,但clsEmployeeCustomer,不一定是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对象并且不想提供这个值,则这是不可避免的同时支付工资。

答案 1 :(得分:3)

请考虑以下事项:

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

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

bar = Bar()
bar.p()

这将打印&#34; Bar&#34;。从Foo.p内部调用时传递给Bar.p的类对象实际上是Bar类,而不是Foo类。

因此,在您的代码中,当您通过Person.parse致电Employee.parse时,Person.parsereturn cls(name)中的行实际上正在调用Employee(name),但{{1}初始化需要2个位置参数。

要使您的代码使用此结构,您的Employee必须具有相同的签名或至少兼容的签名(例如,通过向__init__添加* args {s} { {1}}方法并将它们传递给构造函数)。