【问题标题】:How to inherit a python base class?如何继承python基类?
【发布时间】:2017-05-11 02:45:54
【问题描述】:
dir/
  |
  |___ __init__.py
  |
  |___ Base_class.py
  |
  |___ Subclass.py

__init__.py 为空(如here 所述)


/* Base_class.py


class Employee:

    numOfEmployees = 0 # Pure class member, no need to override
    raiseAmount = 1.04 # Could not be pure class member, so, can it be overidden by object?
                           # Yes. make sense
                           # This is why we use self.raiseAmount in methods
    def __init__(self, firstName, lastName, pay):
        self.firstName = firstName
        self.lastName = lastName
        self.pay = pay
        self.email = firstName + '.' + lastName + '@email.com'

        Employee.numOfEmployees += 1

    def fullName(self):
        return '{} {}'.format(self.firstName, self.lastName)

    def appyRaise(self):
        self.pay = int(self.pay * self.raiseAmount)

        @classmethod
        def setRaiseAmt(cls, amount):
            cls.raiseAmount = amount

        @classmethod
        def createEmployee(cls, employeeStr):
            firstName, lastName, pay = employeeStr.split('-')
            return cls(firstName, lastName, pay)

        @staticmethod
        def isWorkDay(day):
            if day.weekday() == 5 or day.weekday() == 6:
                return False
            return True


emp1 = Employee('AAA', 'BBB', 50000)
emp2 = Employee('CCC', 'DDD', 40000)


print Employee.raiseAmount # 1.04
print emp1.raiseAmount     # 1.04
print emp2.raiseAmount     # 1.04

# Regular methods
emp1.fullName()          # Executing fullName(<__main__.Employee object at 0xb7dbef0c>) 
Employee.fullName(emp1)  # same as above 


# With classmethods, the class of the object instance is implicitly passed as the first argument instead of self.

Employee.setRaiseAmt(1.05) # class variable's cls member raiseAmount will get updated

print Employee.raiseAmount # 1.05
print emp1.raiseAmount     # 1.05
print emp2.raiseAmount     # 1.05

emp1.setRaiseAmt(1.05) # Invokes as, setRaise(<class '__main__.Employee'>,1.05)

# Application of class methods as constructors
employeeStr = 'John-Doe-70000'
newEmployee = Employee.createEmployee(employeeStr);

print newEmployee.email
print newEmployee.pay


# With static methods, neither self (the object instance) nor  cls (the class) is implicitly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class:

emp1 = Employee('AAA', 'BBB', 50000)
emp2 = Employee('CCC', 'DDD', 40000)

import datetime
myDate = datetime.date(2016, 7, 10)

print emp1.isWorkDay(myDate) # Executing isWorkDay(myDate)

/* Subclass.py */

from  Base_class import Employee

class Developer(Employee):
    pass

问题:

仅继承 Employee 类:

> python Subclass.py

为什么这是下面的输出?如何继承基类?

$ python Subclass.py
1.04
1.04
1.04
1.05
1.05
1.05
John.Doe@email.com
70000
False

【问题讨论】:

  • 当你导入 Employee python runs 时。因此文件末尾的所有print 语句都将被执行。
  • @StephenRauch 所有打印语句都不属于Employee。我只导入Employee
  • 不,您不仅在导入员工。评估整个文件....您所做的是将Employee 放入您的命名空间
  • @StephenRauch 如果整个文件有 100 个类,python 是否评估所有 100 个不相关的类以仅导入 Employee?评估整个文件需要什么?这很奇怪。首先,如果我写class Developer(Employee),我希望Developer.__dict__ 拥有Employee 的所有成员。这是怎么回事?
  • 是的,而且所有的imports和imports中的imports....

标签: python python-2.7 inheritance


【解决方案1】:

您似乎遇到的问题是,当您 import 一个模块时,它的所有代码都会运行,即使您使用 from module import name 语法只导入模块的一部分内容。这就是为什么运行 Subclass.py 文件会得到与运行 Base_class.py 相同的输出的原因。

如果您不希望在导入 Base_class 模块时运行测试代码,则应将其放在 if __name__ == "__main__": 块内。全局变量__name__ 通常是模块的名称(如"Base_class")。当您将模块作为脚本运行时,它是"__main__"。因此,测试该字符串可以让您仅在您的模块是主脚本时运行一些代码,而不是在它被其他模块导入时运行。

您可能还对子类如何查看其父类的属性感到困惑。这在 Python 中有点神奇。当您在实例上查找属性时,首先检查实例自己的字典,然后是类的字典,然后是其 MRO 中每个基类的字典(方法解析顺序,通常是父类链的顺序,除非您'正在做复杂的多重继承)。因此,Employee 的继承属性不会出现在 Developer.__dict__ 中,除非您在 Developer 类中为其显式设置新值。

据我所知,如果您创建一些 Developer 实例并调用它们将继承的一些方法,您的代码应该可以正常工作。看到的唯一错误是Employee 中的修饰方法与其他方法的缩进不同,但我怀疑(基于你说你得到的输出)这是将代码复制到堆栈溢出的问题,而不是真正的错误。您可能需要仔细检查是否没有在缩进中混合空格和制表符,这可能会导致难以看到的细微错误(并且在 Python 3 中不允许混合它们)。

【讨论】:

    【解决方案2】:

    您已将setRaiseAmt 声明为类方法,这意味着无论您是通过类还是实例调用它,它都会更新class 变量raiseAmount。不需要这个类方法;如果您想更改默认的加薪金额,直接进行即可:

    Employee.raiseAmount = ...
    

    如果要设置单个员工的值,也可以直接设置,但通过实例:

    emp1.raiseAmount = ...
    

    总是在实例的属性字典中创建(或更新)一个变量。当读取raiseAmount的值时,如果存在则获取实例属性的值,否则获取类属性的值。

    如果您必须提供 setter(例如,它是类分配的要求),请提供单独的类和实例方法:

    @classmethod
    def set_default_raise_amount(cls, amount):
        cls.raise_amount = amount
    
    def set_raise_amount(self, amount):
        self.raise_amount = amount
    

    【讨论】:

      【解决方案3】:

      导入Employee基类时,首先将Base_class.py文件读入内存并进行处理,然后将Employee类导入Subclass.py的命名空间

      要测试您是否成功子类化,您可以在 Subclass.py 中尝试实例化一个 Employee 类,但您需要创建一个构造函数。

      将这些添加到您的 Developer 课程中。

      from Base_class import Employee
      
      class Developer(Employee):
           def __init__(self):
                Super(Employee, self).__init__()
      
      test_dev = Developer('Bob', 'Marley', 1000)
      
      test_dev.fullName()
      

      【讨论】:

        【解决方案4】:

        当您从 Base_class.py 导入 Employee 时,它​​会将整个 Base_class.py 数据读入内存。因此,因为您在该文件中创建对象并在 Base_class.py 中打印它们,所以您将在设置继承时执行它们。

        您可能希望通过另一个文件(如 main.py 或其他文件)创建这些 Employee 对象。这将阻止您在导入 Employee 类时处理打印和对象创建请求。

        【讨论】:

        • 是的,我知道main.py 或类似的东西会实例化。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-05
        • 1970-01-01
        • 2012-12-10
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多