-1

これは、Webスクレイピングプロジェクトで使用されるPythonクラス内のスニペットです。新たにスクレイピングされたデータのディクショナリを反復処理し、各レベルで以前にスクレイピングされたインデックスと比較し、後で処理するために別の深くネストされたdictに更新する必要がある値を追加したいと思います。これをクリーンアップし、同じ結果を達成するためにどのような戦略を使用できますか?

self.new_stats[tour] = {}
parsed_stats = parse_stat_year(CURRENT_STAT_YEAR, self.scraped_stats_index[tour])

for pname, stats_by_year in parsed_stats.items():
  if pname in self.raw_players_with_stats[tour]:
    player = self.raw_players_with_stats[tour][pname]

    if 'stats' in player:
      for y, stats_by_cat in stats_by_year.items():
        if str(y) in player['stats']:
          for cat, stat in stats_by_cat.items():
            if cat in player['stats'][str(y)]:
              for prop, val in stat.items():
                if (not prop in player['stats'][str(y)][cat]) or (player['stats'][str(y)][cat][prop] != val):
                  self.new_stats[tour].setdefault(pname,{}).setdefault(y,{}).setdefault(cat,{})[prop] = val
            else:
              self.new_stats[tour].setdefault(pname,{}).setdefault(y,{})[cat] = stat
        else:
          self.new_stats[tour].setdefault(pname,{})[y] = stats_by_cat
    else:
      self.new_stats[tour][pname] = stats_by_year

  elif pname in self.new_player_urls[tour]:
    self.new_stats[tour][pname] = stats_by_year
4

1 に答える 1

2

単体テストから始めて、リファクタリングを繰り返すたびに、コードが実際に機能することを確認します。

意味のあるデータ構造とメソッドを使用するので、コードはより自己記述的です。別のデータホルダークラスを展開したくない場合は、namedtupleが非常に役立つことがあります。

最後に、この大きくて醜いif...for...elseブロックを、次のような意味のある小さなチャンクに分解します。

# instead of this original code...

for pname, stats_by_year in parsed_stats.items():
  if pname in self.raw_players_with_stats[tour]:
    #...
  elif pname in self.new_player_urls[tour]:
    self.new_stats[tour][pname] = stats_by_year

# you get something like this

for player_name, stats_by_year in parser_stats.iteritems():
  if self.has_raw_player(player_name):
    self.process_new_raw_player(player_name, stats_by_year)
  elif self.is_player_new(player_name):
     self.insert_new_stat_for_player( player_name, stats_by_year )

読みやすく、テストしやすく、理解しやすい

そして、もしあなたに自由な時間があれば、私はそれをロバート・マーチンのクリーンコードを読むことに投資するでしょう。きっと報われるでしょう!

編集

このような長くて読みにくいワンライナーを片付ける

#...
self.new_stats[tour].setdefault(pname,{}).setdefault(y,{}).setdefault(cat,{})[prop] = val
#...

したがって、たとえば、次のようになります。

def insert_new_stat(self, tour, pname, y, cat, prop, val):
  player_stat = self.new_stats[tour].setdefault(pname, {})
  y_param = player_stat.setdefault(y, {}) # what is y??
  category_stats = ...
  prop_stats = ...
  ... = val

コードは確かに長くて冗長になりますが、暗黙的よりも明示的の方が優れています

于 2013-01-01T16:14:22.370 に答える