2017-05-11 56 views
-1
dir/ 
    | 
    |___ __init__.py 
    | 
    |___ Base_class.py 
    | 
    |___ Subclass.py 

__init__.py是空的(如所提到的here如何繼承一個python基類?


/* 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 
[email protected] 
70000 
False 
+3

當你導入'僱員'python' runs'它。因此,文件末尾的所有'print'語句都將被執行。 –

+0

@StephenRauch所有打印語句不是「員工」的一部分。我只輸入'Employee' – overexchange

+2

不,你不只是輸入Employee。評估整個文件....只是*你的*只是將'Employee'放入你的命名空間 –

回答

2

您似乎遇到的問題是,當您使用import模塊時,即使您使用from module import name語法僅導入模塊內容的一部分,它的所有代碼都會運行。這就是爲什麼如果您運行Base_class.py就會得到與運行Subclass.py文件相同的輸出。

如果您不想在導入Base_class模塊時運行測試代碼,則應將其置於if __name__ == "__main__":塊內。全局變量__name__通常是模塊的名稱(如"Base_class")。當您將模塊作爲腳本運行時,它是"__main__"。因此,對字符串進行測試可以讓您只在模塊是主腳本時運行一些代碼,而不是在其他模塊導入時運行。

您可能會對子類如何看到其父類的屬性感到困惑。這在Python中有點神奇。當你在一個實例上查找一個屬性時,首先檢查實例自己的字典,然後它是類的字典,然後是MRO中每個基類的字典(方法解析順序,除非你是順序的,否則通常是父類的鏈)複製多重繼承)。所以Employee的繼承屬性將不會顯示在Developer.__dict__中,除非您在Developer類上爲其明確設置了新值。

就我所見,如果你創建了一些Developer實例並調用它們將繼承的一些方法,你的代碼應該可以很好地工作。看到的唯一錯誤是Employee中的裝飾方法沒有縮進與其他方法相同,但我懷疑(根據輸出你說你得到),這是從代碼複製到堆棧溢出的問題,而是比一個真正的錯誤。您可能需要仔細檢查一下,您是否在縮進中混合了空格和製表符,這可能會導致難以察覺的細微錯誤(並且在Python 3中不允許混合它們)。

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 
1

當你導入員工基類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() 
0

當您從Base_class.py導入Employee時,它會將整個Base_class.py數據讀入內存。因此,您在該文件中創建對象並將其打印到Base_class.py中,您將在設置繼承時執行它們。

您可能想要通過另一個文件(如main.py或其他文件)創建這些Employee對象。這會阻止您在導入Employee類時處理打印和對象創建請求。

+0

是的,我知道'main.py'或類似的東西會實例化。 – overexchange