Dumping simple sequences into CSV

An ideal mapping is between the NamedTuple instances and rows in a CSV file. Each row represents a different NamedTuple. Consider the following Python class definition:

from typing import NamedTuple

class GameStat(NamedTuple):
player: str
bet: str
rounds: int
final: float

We've defined the objects in this application to have a simple, flat sequence of attributes. The Database architects call this First Normal Form. There are no repeating groups and each item is an atomic piece of data.

We might produce these objects from a simulation that looks like the following code:

from typing import Iterator, Type

def gamestat_iter(
player: Type[Player_Strategy], betting: Type[Betting], limit: int = 100
) -> Iterator[GameStat]:
for sample in range(30):
random.seed(sample) # Assures a reproducible result
b = Blackjack(player(), betting())
b.until_broke_or_rounds(limit)
yield GameStat(player.__name__, betting.__name__, b.rounds, b.betting.stake)

This iterator will create Blackjack simulations with a given player and betting strategy. It will execute the game until the player is broke or has sat at the table for 100 individual rounds of play. At the end of each session, it will yield a GameStat object with the player strategy, betting strategy, the number of rounds, and the final stake. This will allow us to compute statistics for each play, betting strategy, or combination. Here's how we can write this to a file for later analysis:

import csv
from pathlib import Path

with (Path.cwd() / "data" / "ch10_blackjack_1.csv").open("w", newline="") as target:
writer = csv.DictWriter(target, GameStat._fields)
writer.writeheader()
for gamestat in gamestat_iter(Player_Strategy, Martingale_Bet):
writer.writerow(gamestat._asdict())

There are three steps to create a CSV writer:

  1. Open a file with the newline option set to "". This will support the (possibly) nonstandard line ending for CSV files.
  2. Create a CSV writer. In this example, we created DictWriter because it allows us to easily create rows from dictionary objects. The GameStat._fields attribute provides the Python attribute names so the CSV columns will precisely match the attributes of the GameStat subclass of the NamedTuple class.
  3. Write a header in the first line of the file. This makes data exchange slightly simpler by providing some hint as to what's in the CSV file.

Once the writer object has been prepared, we can use the writer's writerow() method to write each dictionary to the CSV file. We can, to an extent, simplify this slightly by using the writerows() method. This method expects an iterator instead of an individual row. Here's how we can use writerows() with an iterator:

data = gamestat_iter(Player_Strategy, Martingale_Bet)
with (Path.cwd() / "data" / "ch10_blackjack_2.csv").open("w", newline="") as target:
writer = csv.DictWriter(target, GameStat._fields)
writer.writeheader()
writer.writerows(g._asdict() for g in data)

We've assigned the iterator to a variable, data. For the writerows() method, we get a dictionary from each row produced by the iterator.

Let's load a simple sequence from CSV.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset