Присваивать значения CSV атрибутам класса, обрабатывать выходные данные в csv с использованием абстрактных классов

#python #csv #class #abstract #abc

#python #csv #класс #аннотация #abc

Вопрос:

Этот вопрос немного сбивает с толку, так что потерпите меня, это также должно быть сделано с помощью чистого Python и без сторонних модулей.

Кажется, я не могу присвоить правильный тип данных значениям CSV и присвоить их атрибутам класса.

Я перепробовал все известные мне способы, несколько дней искал ответ…

Ошибка значения, когда FLOAT присваивается «строка [4]», и ошибка типа, если я не приведу переменную.

Я также пытался присвоить их новым переменным и привести тип данных. Я думаю, это связано с выводом функций rstrip() и strip().

 ValueError: could not convert string to float: ''
TypeError: '>' not supported between instances of 'str' and 'int'
 

Ожидаемый результат:

 ------- Resident ID: {self._id} -------
Gross: {self.gross}
Net: {self.net}
Tax: {self.tax}

------- Holiday ID: {self._id} -------
Gross: {self.gross}
Net: {self.net}
Tax: {self.tax}
Visa: {self._visa}
YTD: {self._year_to_date}
 
 from abc import ABC, abstractmethod
from datetime import date #To assign <timestamp> for export_summary()
from typing import List

class PayRecord(ABC):
    def __init__(self, id: int, hours:float, rates:float):
        self._id = id
        self._hours = hours
        self._rates = rates

    @abstractmethod
    def get_details(self): 
        pass

    @property
    def id(self):
        return self._id

    @property
    def gross(self):
        return (self._hours * self._rates)

    @property
    @abstractmethod
    def tax(self):
        return self.tax

    @property
    def net(self):
        return (self.gross - self.tax)
        
class ResidentPayRecord(PayRecord):
    def __init__(self, id: int, hours:float, rates:float):
        super().__init__(id, hours, rates)

    def get_details(self):
        return f"------- Resident ID: {self._id} -------nnGross: {self.gross}nNet: {self.net}nTax: {self.tax}n"

    @property
    def tax(self):
        return calc_res_tax(self.gross)

class WorkingHolidayPayRecord(PayRecord):
    def __init__(self, id: int, hours:float, rates:float, visa: str, year_to_date:float):
        super().__init__(id, hours, rates)
        self._visa = visa
        self._year_to_date = year_to_date

    @property
    def visa(self):
        return self._visa

    @property
    def year_to_date(self):
        return self._year_to_date

    @property
    def tax(self):
        return calc_wh_tax(self.gross, self._year_to_date)

    def get_details(self):
        return f"------- Holiday ID: {self._id} -------nnGross: {self.gross}nNet: {self.net}nTax: {self.tax}nVisa: {self._visa}nYTD: {self._year_to_date}"


def calc_res_tax(gross: float):

    A_eff = [0.19,0.2342,0.3477,0.345,0.39,0.47]
    b_Eff =[0.19,3.213,44.2476,41.7311,103.8657,352.788]
    if (gross > -1 and gross <= 72):
        resTax = A_eff[0] * gross - b_Eff[0]
        return resTax
    if (gross > 72 and gross <= 361):
        resTax = A_eff[1] * gross - b_Eff[1]
        return resTax
    if (gross > 361 and gross <= 932):
        resTax = A_eff[2] * gross - b_Eff[2]
        return resTax
    if (gross > 932 and gross <= 1380):
        resTax = A_eff[3] * gross - b_Eff[3]
        return resTax
    if (gross > 1380 and gross <= 3111):
        resTax = A_eff[4] * gross - b_Eff[4]
        return resTax
    if (gross > 3111 and gross <= 999999):
        resTax = A_eff[5] * gross - b_Eff[5]
        return resTax
    
def calc_wh_tax(gross:float, year_to_date:float):
    rate = [0.15,0.32,0.37,0.45]
    if (year_to_date > -1 and year_to_date <= 37000):
        whTax = gross * rate[0]
        return whTax
    if (year_to_date > 37000 and year_to_date <= 90000):
        whTax = gross * rate[1]
        return whTax
    if (year_to_date > 90000 and year_to_date <= 180000):
        whTax = gross * rate[2]
        return whTax
    if (year_to_date > 180000 and year_to_date <= 9999999):
        whTax = gross * rate[3]
        return whTax    

def import_pay_records(file:str):
    records = []

    with open(file,"r") as f:
        next(f)
        for line in f:
            line = line.rstrip().split(',')
            id = int(line[0])
            hours = float(line[1])
            rates = float(line[2])
            visa = str(line[3])
            year_to_date = float(line[4])
            app = id,hours,rates,visa,year_to_date
            rec = [string for string in app if string != '']
            records.append(rec)
            create_pay_record(id,hours,rates,visa,year_to_date)


        return records

def create_pay_record(id:int, hours:float, rates:float, visa:str, year_to_date:float):
    
    r: ResidentPayRecord = ResidentPayRecord(id,hours,rates)
    wh: WorkingHolidayPayRecord = WorkingHolidayPayRecord(id,hours,rates,visa,year_to_date)

    print(r.get_details())
    print(wh.get_details())

def write_summary(file:str, records:List[PayRecord], to_console:bool):
    """The function must accept a list of PayRecord objects and write the Id, Gross, Net, and Tax amounts of a pay record to a comma delimited values (.csv) file"""
    pass

def main():
    records = import_pay_records("import\employee-payroll-data.csv")
    write_summary("export\export-data.csv",records,True)

if __name__ == '__main__':
    main()

 

Импорт данных:
Есть еще дубликаты, но это не имеет значения. Просто в качестве примера.

 EmployeeId,Hours,Rate,Visa,YearToDate
1,2,25,,
1,3,25,,
1,4,25,,
1,5,32,,
1,6,32,,
2,2,25,417,47520.0
2,2,25,417,47520.0
2,2,25,417,47520.0
 

Комментарии:

1. Не могли бы вы опубликовать один пример строки и строку после rstrip()?

2. В CSV должны быть повторяющиеся значения, однако в качестве примера.. При печати строки с помощью rstrip() и split(‘,’) вывод выглядит так, как ['1', '6', '32', '', ''] ['2', '2', '25', '417', '47520.0'] при печати из понимания списка, он удаляет лишние кавычки, вот и все. При печати «строки» без rstrip() и split() он выдает ValueError: could not convert string to float: ','

3. Я добавил данные импорта для справки.

4. Итак, проблема в том, что csv содержит некоторые пустые значения, верно? Например. «1,2,3,,,,» Тогда вам, вероятно, следует заменить эти пустые строки в вашем списке некоторым значением. Вы не можете преобразовать пустую строку «» в число с плавающей запятой, поскольку строка, очевидно, должна быть каким-то числом.

5. Да, вам нужно написать несколько строк кода на случай, если эти значения останутся пустыми. «» не может быть преобразован в float, потому что какое число должно быть? 0 , -1, …?

Ответ №1:

Проблемы, если некоторые поля пусты и float('') фактически вызывают это ValueError

Поэтому вы должны проверить наличие пустых значений, прежде чем пытаться преобразовать:

 year_to_date = float(line[4]) if line[4].strip() != '' else 0.0
 

Ответ №2:

После строки .split() замените пустые строки некоторым числом, например:

 line = [string if string else '0' for string in line]
 

Тогда каждый элемент списка может быть преобразован в float.

Кстати, CSV-файлы также можно читать с помощью модуля чтения pythons CSV (ссылка)

Комментарии:

1. Спасибо за помощь, но я не уверен, как это использовать, он все равно выдает ValueError: could not convert string to float: '' , я буду использовать решение выше, если у вас нет другого предложения! Несмотря на это, я все еще очень признателен, я буду иметь это в виду в следующий раз.

2. Вы написали line = [..] , я не писал это явно, но добавил. В любом случае оба решения должны работать нормально

3. О! Нет, я этого не делал, я тоже попробую, посмотрим.