0

我有一个需要拆分的输入文件。该文件可以有任意数量的行,但每行有 4 个内容。首先是地区代码,其次是在该地区销售的小说书籍数量,其次是在该地区销售的非小说书籍数量,最后是该地区的税收(例如:TX 493 515 0.055)。除了总结所有小说书籍、非小说书籍和总销售额之外,我已经弄清楚了我需要对程序做的所有事情。假设总共只有三行,每个地区的小说书销量分别为 493、500、489 册,显然它们各自位于不同的行中。这是我写的,想知道我做错了什么:

while (myFile != ""):

    myFile = myFile.split()
    sumFiction = 0
    for i in range(myFile):
        sumFiction = sumFiction + eval(myFile[1])

如果我拆分 (CO 493 515 0.055) 的文件,CO 不会是 myFile[0]、493 是 myFile[1] 等。任何帮助将不胜感激。

编辑:对不起,我应该更具体一点。我正在从一个文件中读取,假设这个文件有 3 行(但我的代码需要用于无限数量的行):

TX 415 555 0.55
MN 330 999 0.78
HA 401 674 0.99

首先是地区代码,然后是小说书籍的销量,然后是非小说书籍的销量,然后是该地区的税收。我需要弄清楚我已经完成的地区等销售的书籍总量。唯一我不知道的是如何总结所有三行出售的小说(例如:415、330、401)。到目前为止,这是代码:

def ComputeSales(fictionBooks,nonFictionBooks,areaTax):
    total = (fictionBooks * 14.95) + (nonFictionBooks * 9.95)
    tax = total * areaTax
    totalSales = total + tax

    return total,tax,totalSales

def main():
    #inFile = input("Please enter name of book data file:  ")
    #inFile = open(inFile,"r")
    inFile = open("pa7.books","r")
    myFile = inFile.readline()

    print()
    print("{0:14}{1:10}".format("","Units Sold"))
    print("{0:10}{1:11}{2:17}{3:12}{4:8}{5:11}".format(
                "Region","Fiction","Non-Fiction","Total","Tax","Total Sales"))
    print("---------------------------------------------------------------------")

    while (myFile != ""):
        myFile = myFile.split()
        sumFiction = 0
        #for i in range(myFile):
            #sumFiction = sumFiction + eval(myFile[1])

        total,tax,totalSales = ComputeSales(eval(myFile[1]),eval(myFile[2]),eval(myFile[3]))

        print("{0:2}{1:10}{2:13}{3:4}{4:14.2f}{5:10.2f}{6:16.2f}".format(
                   "",myFile[0],myFile[1],myFile[2],total,tax,totalSales))

        myFile = inFile.readline()

     print("---------------------------------------------------------------------")
    #print("{0:11}{1:13}{2:34}{3:2}{4:8}".format(
    #             "Total","15035","3155","$","272843.41"))
    print(sumFiction)

main()
4

2 回答 2

2

编辑:好的,我之前的回答是基于假设它myFile实际上是一个文件对象,而不是文件的一行。

你的主要问题似乎是你试图在另一个循环中做一个循环,这并没有什么意义:你只需要一个循环在这里,在文件的行上,并为每个循环加起来线。

main这是执行此操作的函数的编辑版本。我也有:

  • 切换到for文件的循环,因为它更自然。
  • 按照评论中的建议,使用float而不是eval,这样恶意或错误的数据文件只会使您的程序崩溃,而不是运行任意代码。
  • 切换到使用with语句打开文件:这保证即使您的程序中途崩溃,文件也会被关闭,这是一个很好的习惯,尽管在这里并没有太大的区别。
  • 切换到snake_case变量名的标准 Python 样式样式,而不是camelCase. (此外,ComputeSales通常是compute_sales;CamelCase名称通常仅用于类名。)
  • 将文件名更改为参数,以便您可以使用例如调用它main(sys.argv[1] if len(sys.argv) > 1 else "pa7.books")来支持命令行参数。

这里是:

def main(filename="pa7.books"):
    sum_fiction = 0
    sum_nonfiction = 0
    sum_total = 0

    with open(filename) as in_file:
        for line in in_file:
            if not line.strip():
                 continue # skip any blank lines

            fields = line.split()
            region = fields[0]
            fiction, nonfiction, area_tax = [float(x) for x in fields[1:]]

            total, tax, total_sales = ComputeSales(fiction, nonfiction, area_tax)

            sum_fiction += fiction
            sum_nonfiction += nonfiction
            sum_total += total_sales

    print("{0:2}{1:10}{2:13}{3:4}{4:14.2f}{5:10.2f}{6:16.2f}".format(
           "", region, fiction, nonfiction, total, tax, total_sales))

    print("---------------------------------------------------------------------")
    print("{0:11}{1:13}{2:34}{3:2}{4:8}".format(
           "Total", sum_fiction, sum_nonfiction, "$", sum_total))

如果您不理解我建议的任何更改,请随时提问!

于 2012-04-21T19:23:31.160 回答
1

啊。这是丑陋的。美丽胜于丑陋。我不再主要是 Python 程序员,所以可能有更好的工具来解决这个问题。但是让我们从概念层面来解决这个问题。

这是标准的命令式编程,使问题过于复杂。它很容易迷失在实施噪音中,比如你遇到的问题。它使您无法只见树木不见森林。让我们尝试另一种方法。

让我们专注于我们需要做的事情,并让实施由此产生。首先我们知道我们需要从文件中读取。

从文件中读取

Scenario: Calculate totals within region database
Feature: Read from database

As a user, in order to be able to view the total sales of my books and differentiate them by fiction and nonfiction, I want to be able to read data from a file.

Given: I have a file that has region data, for example data.text
When: I load data from it
Then: I should have associated region data available in my program.

这是作为测试用例的 Python 实现:

import unittest

class RegionTests(unittest.TestCase):
    def testLoadARegionDatabase(self):
        """Given a region file,when I load it, then it should be stored in memory"""
        # Given region database
        regionDatabase = []
        # When I load it
        with open('./regions.txt','r') as f:
            regionDatabase = f.readlines()
        # Then contents should be available
        self.assertTrue(len(regionDatabase) > 0)

从文件中获取区域数据

从概念上讲,我们知道该文件中的每一行都是有意义的。从根本上说,每一行都是一个Region。我们在文件中存储了代码、虚构销售、非虚构销售和税率。区域的概念在我们的系统中应该有一个明确的、一流的表示,因为Explicit 比 Implicit 更好

Feature: Create a Region

As a user, in order to be able to know a region is information--including nonfiction sales, fiction sales, and tax rate-- I want to be able to create a Region.

Given: I have data for fiction sales, non-fiction sales, and tax rate
When:  I create a Region
Then:  Its sales, non-fiction sales, and tax-rate should be set accordingly

这是作为测试用例的 Python 实现:

def testCreateRegionFromData(self):
        """Given a set of data, when I create a region, then its non-fiction sales, fiction sales,and tax rate should be set"""
        # Given a set of data
        texas = { "regionCode": "TX", "fiction" : 415, "nonfiction" : 555, "taxRate" : 0.55 }
        # When I create a region
        region = Region(texas["regionCode"], texas["fiction"], texas["nonfiction"], texas["taxRate"])
        # Then its attributes should be set
        self.assertEquals("TX", region.code)
        self.assertEquals(415, region.fiction)
        self.assertEquals(555, region.nonfiction)
        self.assertEquals(0.55, region.taxRate)

这失败了。让我们让它过去吧。

class Region:
    def __init__(self, code, fiction, nonfiction,rate):
        self.code = code
        self.fiction = fiction
        self.nonfiction = nonfiction
        self.taxRate = rate

分析总计

现在我们知道我们的系统可以表示区域。我们想要一些可以分析大量地区并为我们提供销售汇总统计数据的东西。让我们称其为Analyst

Feature: Calculate Total Sales

As a user, in order to be able to know what is going on, I want to be able to ask an Analyst what the total sales are for my region

Given: I have a set of regions
When : I ask my Analyst what the total sales are
Then : The analyst should return me the correct answers

这是作为测试用例的 Python 实现。

def testAnalyzeRegionsForTotalNonFictionSales(self):
    """Given a set of Region, When I ask an Analyst for total non-fiction sales, then I should get the sum of non-fiction sales"""
    # Given a set of regions
    regions = [ Region("TX", 415, 555, 0.55), Region("MN", 330, 999, 0.78), Region("HA", 401, 674, 0.99) ]
    # When I ask my analyst for the total non-fiction sales
    analyst = Analyst(regions)
    result = analyst.calculateTotalNonFictionSales()
    self.assertEquals(2228, result)

这失败了。让我们让它过去吧。

class Analyst:
    def __init__(self,regions):
        self.regions = regions

    def calculateTotalNonFictionSales(self):
        return sum([reg.nonfiction for reg in self.regions])

您应该能够从这里推断小说的销售情况。

决定,决定

当涉及到总销售额时,需要做出一个有趣的设计决策。

  • 我们是否应该让分析师直接阅读一个地区的小说和非小说属性并总结它们?

我们可以这样做:

def calculateTotalSales(self):
    return sum([reg.fiction + reg.nonfiction for reg in self.regions])

但是,如果我们添加“历史剧”(小说和非小说)或其他属性会发生什么?然后每次我们更改 Region 时,我们都必须更改我们的 Analyst,以便将 Region 的新结构考虑在内。

,这是一个糟糕的设计决定。Region 已经知道它需要知道的关于其总销售额的所有信息。地区应该能够报告其总数。

做出好的选择!

Feature: Report Total Sales
Given: I have a region with fiction and non-fiction sales
When : I ask the region for its total sales
Then: The region should tell me its total sales

这是作为测试用例的 Python 实现:

def testGetTotalSalesForRegion(self):
        """Given a region with fiction and nonfiction sales, when I ask for its total sales, then I should get the result"""
        # Given a set of data
        texas = { "regionCode": "TX", "fiction" : 415, "nonfiction" : 555, "taxRate" : 0.55 }
        region = Region("TX", 415, 555, 0.55)
        # When I ask the region for its total sales
        result = region.totalSales()
        # Then I should get the sum of the sales
        self.assertEquals(970,result)

分析师应该告诉,不要问

def calculateTotalSales(self):
        return sum([reg.totalSales() for reg in self.regions])

现在您拥有编写此应用程序所需的一切。另外,如果您以后进行更改,您可以使用自动回归套件。它可以准确地告诉你你破坏了什么,并且测试明确地指定应用程序是什么以及它可以做什么。

结果

这是生成的程序:

from region import Region
from analyst import Analyst

def main():
   text = readFromRegionFile()
   regions = createRegionsFromText(text)
   analyst = Analyst(regions)
   printResults(analyst)

def readFromRegionFile():
    regionDatabase = []
    with open('./regions.txt','r') as f:
            regionDatabase = f.readlines()
    return regionDatabase

def createRegionsFromText(text):
    regions = []
    for line in text:
        data = line.split()
        regions.append(Region(data[0],data[1], data[2], data[3]))
    return regions

def printResults(analyst):
    totSales = analyst.calculateTotalSales()
    totFic = analyst.calculateTotalFictionSales()
    totNon = analyst.calculateTotalNonFictionSales()
    for r in analyst.regions:
        print("{0:2}{1:10}{2:13}{3:4}{4:14.2f}{5:10.2f}".format(
           "", r.code, r.fiction, r.nonfiction, r.totalSales(), r.taxRate))

    print("---------------------------------------------------------------------")
    print("{0:11}{1:13}{2:34}{3:2}{4:8}".format(
           "Total", totFic, totNon, "$", totSales))

if __name__ == "__main__":
    main()

把你写的和这个比较一下。哪一个更容易理解?简洁的?如果:

  • 您为每个地区添加了音乐销售?
  • 您从文本文件转移到 MySQL 数据库或 Web 服务调用?

让你的概念体现出来。使您的代码清晰、简洁且富有表现力。

于 2012-04-21T22:51:42.597 回答