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
答案 0 :(得分:2)
您似乎遇到的问题是,当您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
中的修饰方法与其他方法没有缩进相同,但我怀疑(根据你说你得到的输出),这是将代码复制到Stack Overflow,而不是真正的bug。您可能需要仔细检查是否没有为缩进混合空格和制表符,这可能会导致难以看到的细微错误(在Python 3中不允许混合它们)。
答案 1 :(得分:1)
您已将setRaiseAmt
声明为类方法,这意味着无论您是通过类还是实例调用它,它都会更新类变量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
答案 2 :(得分:1)
导入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()
答案 3 :(得分:0)
从Base_class.py导入Employee时,它会将整个Base_class.py数据读入内存。因此,因为您在该文件中创建对象并在Base_class.py中打印它们,所以在设置继承时将执行它们。
您可能希望通过另一个文件(如main.py或其他)创建这些Employee对象。这将阻止您在导入Employee类时处理打印和对象创建请求。