将 CSV 值分配给 class 属性,使用抽象 classes 处理输出到 csv

Assign CSV values to class attributes, process output to csv using abstract classes

这个问题有点令人困惑所以请耐心等待,它也必须使用纯 Python 并且没有第三方模块来完成。

我似乎无法将正确的数据类型分配给 CSV 值并将它们分配给 class 属性。

我已经尝试了所有我知道的方法,四处寻找了几天的答案...

FLOAT赋值给"line[4]"时的值错误,不转换变量时的TypeError。

我也试过将它们分配给新变量并转换数据类型。我认为这是由于 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} -------\n\nGross: {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} -------\n\nGross: {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

在 .split() 行之后,用一些数字替换空字符串,例如:

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

然后每个列表元素都可以转换为浮动。

顺便说一下,CSV 文件也可以用 pythons CSV Reader 模块读取 (Link)

如果某些字段为空并且 float('') 实际上引发的问题 ValueError

因此您应该在尝试转换之前测试空值:

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