0

分割する必要がある入力ファイルがあります。ファイルには任意の数の行を含めることができますが、各行には 4 つの内容があります。最初は地域コード、次はその地域で販売されたフィクション書籍の数、次はその地域で販売されたノンフィクション書籍の数、最後はその地域の税金です (例: TX 493 515 0.055)。フィクションの本、ノンフィクションの本、総売上高の合計を除いて、プログラムで行う必要があることはすべて把握しました。全部で 3 行しかなく、各地域で販売されたフィクションブックは 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

最初は地域コード、次にフィクションの書籍の販売額、ノンフィクションの書籍の販売額、その地域の税金です。私が行った地域などで販売された本の総量を把握する必要があります。私が理解できない唯一のことは、販売されたフィクション本の 3 行すべてを合計する方法です (例: 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:さて、私の以前の答えは、それが実際にはファイルの行ではなくファイルオブジェクトであると仮定することに基づいていました。

あなたの主な問題は、他のループ内でループを実行しようとしているように思われますが、これは実際には意味がありません。ここでは、ファイルの行にわたって 1 つのループだけが必要であり、それぞれの合計に加算されます。ライン。

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 よりも優れているため、Region の概念には、システム内で明示的な第一級の表現が必要です。

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 は、総売上高について知る必要があることをすべて知っています。地域はその合計を報告できる必要があります。

良い選択をしましょう!

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()

あなたが書いたものとこれを比較してください。どちらが分かりやすいですか?簡潔?次の場合、2 つの中で何を変更する必要がありますか。

  • 各地域に音楽販売を追加しましたか?
  • テキスト ファイルから MySQL データベースまたは Web サービス呼び出しに移動しましたか?

あなたのコンセプトを具現化してください。コードは明確、簡潔、表現力豊かにします。

于 2012-04-21T22:51:42.597 に答える