2017-07-03 62 views
0

我在Python Crash Course中跟蹤一個項目,演示如何使用CSV文件。下面的代碼成功地填充了dates列表,我認爲它是datetime對象。例如,這是dates列表的第一個元素:datetime.datetime(2014, 1, 1, 0, 0)。下面是功能代碼:Python 3:datetime.strptime()返回一個整數列表而不是字符串

import csv 
from datetime import datetime 

filename = 'sitka_weather_2014.csv' 
with open(filename) as f: 
    reader = csv.reader(f) 

    # Move onto the next row as the first contains no data 
    next(reader) 

    dates = [] 
    for row in reader: 
     try: 
      date = datetime.strptime(row[0], "%Y-%m-%d") 
     except ValueError: 
      print(date, "missing data") 
     else: 
      dates.append(date) 

    print(dates[0]) 

這段代碼的輸出是:2014-01-01 00:00:00

現在,我想實施這個項目與幾個不同的文件,而且具有面向對象的設計原則練習。我設置了父類WeatherData,它有兩個屬性:一個名爲data的列表和一個名爲filename的字符串。 WeatherData類將使用CSV文件中的特定列填充data列表。接下來,我創建了一個名爲WeatherLocation的子類,它從WeatherData繼承。 WeatherLocation有三個屬性:

  • 列表稱爲highs存儲最高溫度
  • 列表叫lows存儲在低溫下
  • 稱爲dates列表存儲日期

如果我們看的set_data方法,我們將看到與上述代碼相同的邏輯被實現。當調用set_dates方法WeatherLocation時,傳遞相同的行號,並且fetching_dates設置爲True,因此執行if語句的正確部分。代碼如下所示:

import csv 
import os.path 
from datetime import datetime 


class WeatherData: 

    def __init__(self, filename): 
     self.data = [] 
     self.filename = self.give_file(filename) 

    def give_file(self, filename): 
     """Method checks for existence of file before setting the 'filename' 
     attribute to the argument 
     """ 
     if not os.path.isfile(filename): 
      print("The file " + filename + " could not be found") 
     else: 
      return filename 

    def set_data(self, row_number, fetching_dates=False): 
     """Sets the data attribute to a list of data selected by the program""" 
     if not self.filename: 
      print("You must call give_file() and provide it a filename" 
        + " before calling this method") 

     with open(self.filename) as f: 
      reader = csv.reader(f) 

      # Call next method so we can skip the header_column and get 
      # into the data 
      next(reader) 

      for row in reader: 
       if fetching_dates: 
        try: 
         date = datetime.strptime(row[row_number], "%Y-%m-%d") 
        except ValueError: 
         print(date, "missing data") 
        else: 
         self.data.append(date) 
       else: 
        try: 
         datum = int(row[row_number].strip()) 
        except ValueError: 
         print(datum, "missing data") 
        else: 
         self.data.append(datum) 

    def get_data(self): 
     return self.data 


class WeatherLocation(WeatherData): 
    def __init__(self, filename): 
     super().__init__(filename) 
     self.highs = self.set_highs() 
     self.lows = self.set_lows() 
     self.dates = self.set_dates() 

    def set_highs(self): 
     super().set_data(1) 
     return super().get_data() 

    def set_lows(self): 
     super().set_data(3) 
     return super().get_data() 

    def set_dates(self): 
     super().set_data(row_number=0, fetching_dates=True) 
     return super().get_data() 

sitka = WeatherLocation('sitka_weather_2014.csv') 
print(sitka.dates[0]) 

不幸的是,該代碼的輸出是46。我究竟做錯了什麼?

回答

2

問題是您的超類WeatherDatadata屬性,其中WeatherLocation繼承。每次您set_data您正在修改相同的data屬性。當您分配WeatherLocation子類中的值時(例如self.highs = self.set_highs()),您只返回對data屬性的引用。

當您print(sitka.dates[0])其獲取實例sitka的第一個元素dates,這實際上只是對sitka.dates的引用。 __init__首先調用self.set_highs()(並且首先要修改data),所以您確實打印出第一個高位。如果你print(sitka.data[0])你應該看到相同的值(例如46)。

如果您打印完整的數據列表(print(sitka.data)),您應該會按照該順序查看高點,低點和日期列表。

0

由於WeatherData.set_data()追加到列表self.data每次運行它,第一個元素sitka.dates[0]將是set_highs()的結果,因此它是一個整數。日期將晚於,因爲你最後撥打set_dates

self.highs = self.set_highs() // append integers to self.data 
self.lows = self.set_lows() // append integers to self.data 
self.dates = self.set_dates() // append datetimes to self.date 

你的類的設計,尤其是繼承的使用是相當混亂。您可能不想使用getter和setter方法,而是考慮重構並使用python屬性。

Python @property versus getters and setters

+0

同樣的變量名'row_number'會像'column_number'更好,只要你'print'的錯誤信息,你應該提出一個合適的異常,而不是。 –

+0

當您在超類中調用具有相同name_的方法時,您只需使用'super()'。所以'super()。set_data(3)'可以用'this.set_data(3)'替換,等等。您需要'super()'的代碼中的唯一位置在'__init __()'方法中。 –

相關問題