#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. О! Нет, я этого не делал, я тоже попробую, посмотрим.