2017-07-03 56 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 __()'方法中。 –

相关问题