1

多くの場合、CSV ファイルを読み取り、それを使用して内部テーブルのような構造に次のような適切なオブジェクトを設定する必要があります。

column_types = {'Car Make' : str, 'Year' : int,
  'Quantity' : int, 'Weight' : float}
# read_from_file will call str()/int()/etc., passing it
# the string that it finds in each cell
t = Table.read_from_file('mytable.txt', column_types)
t[0]['Car Model']  # 'Nissan'
t[0]['Year'] # 2010
t[0]['Quantity'] # 40
t[0]['Weight'] # 2105.53

組み込みの変換では不十分な場合、事態はさらに複雑になります。たとえば、一部の表では、Quantity が 1000 単位で表されている場合があります。この目的のために、次のようなクラスを作成しましたIntegerFormat

class IntegerFormat(int): # this case is really simple, so I subclass built-in 
  def __init__(self, unit):
    self.unit = unit
  # create object from string
  def __call__(self, string):
    value = int(string) * self.unit

column_types = {'Car Make' : str, 'Year' : int,
  'Quantity' : IntegerFormat(1000)}
# no change to Table.read_from_file required
t = Table.read_from_file('mytable.txt', column_types)
t[0]['Quantity'] # 40000; now we know the correct units!

しかし、特定の列に対応するクラスがあまり単純ではない場合、問題が発生します。たとえば、クラスPerformanceはいくつかのパフォーマンス関連の特性を表し、「300 hp、0-60: mph 5.2 s」、「540 hp、1/4 マイル: 8 秒 @140 mph」などの文字列から作成する必要があります。特定の文字列パターンは、1 つのテーブル全体で同じであり、事前にわかっており、それを記述する明確な構文があります。

これで、以前のアプローチに従って次のように書くことができます。

class PerformanceFormat:
  def __init__(self, pattern):
    # convert pattern into some internal form and store it in self.pattern
    # ...
  def __call__(self, string):
    # process the string to obtain parameters that Performance.__init__ expects
    # create Performance object and return it
    # ...
    return Performance(hp, torque, quarter_mile_time)

しかし、PerformanceFormatは と非常に密接に結びついていPerformanceます: もしPerformanceが 1/4 マイルの最終速度 (単なる 1/4 マイルの時間ではなく) を考慮に入れるように変更された場合PerformanceFormat、 も書き直す必要があります。

すべての実際の構築機能を に移動し、文字列パターンの保存のみにPerformance制限できます。PerformanceFormatしかし、その場合、Table.read_from_file()関連するセルを読み取る必要があるときに、インスタンスを持っているだけでは十分ではありません。作成する必要があるPerformanceFormatのはクラス インスタンスであることをどうやって知るのでしょうか?Performance

私はこれを行うことができると思います:

column_types = {'Car Make' : str,
  'Quantity' : IntegerFormat(1000),
  'Performance' : (Performance, PerformanceType('hp: * torque: *')}

HerePerformanceTypeは、 に入力できる標準的な表現を作成しPerformance、2 つの間の結合を大幅に減らすことができます。

class Performance:
  def __init__(self, string, format):
    standard_representation = format(string)
    # ...

おそらくさらに良いのはPerformanceType、結合を完全に排除して、パターンを受動的に保存することです。

class Performance:
  def __init__(self, string, format):
    standard_representation = self.to_standard(string, format)
    # ...

それは素晴らしいことです。しかし、ここTable.read_from_fileでやっかいなことをしなければなりません: 列が単一の callable ではなくタプルによって記述される場合を別の方法で処理する必要があります。(具体的には、最初の要素を呼び出して、セルから読み取った値とタプルの 2 番目の要素の両方を渡す必要があります。)

より良い、よりクリーンなアプローチはありますか?

4

1 に答える 1

0

コンストラクターのキーワード引数に対応する、正規表現で名前付きグループを使用するアプローチのスケッチを次に示します。

class RegexFormat:
    def __init__(self, cls, pattern):
        self.cls = cls
        self.regex = re.compile(pattern)

    def __call__(self, string):
        return self.cls(**self.regex.match(string).groupdict())

class Performance:
    def __init__(self, hp=None, torque=None, quarter_mile_time=None)
        #....

column_types = {'Car Make' : str,
  'Quantity' : IntegerFormat(1000),
  'Performance' : RegexFormat(Performance, 
      r'hp: (?P<hp>\d+) torque: (?P<torque>\d+)')}
于 2012-09-20T06:41:44.650 に答える