2016-09-27 6 views
2

Я переношу некоторый код из PHP, который выполняет итерации через некоторые результаты базы данных и строит двумерный массив выигрышей и потерь для команд в бейсбольной лиге. Вот код, о котором идет речь в PHPМатематические операции над многомерными Python dicts

foreach ($results as $result) { 
     $home_team = $result['Game']['home_team_id']; 
     $away_team = $result['Game']['away_team_id']; 

     if (!isset($wins[$home_team][$away_team])) $wins[$home_team][$away_team] = 0; 
     if (!isset($wins[$away_team][$home_team])) $wins[$away_team][$home_team] = 0; 
     if (!isset($losses[$home_team][$away_team])) $losses[$home_team][$away_team] = 0; 
     if (!isset($losses[$away_team][$home_team])) $losses[$away_team][$home_team] = 0; 

     if ($result['Game']['home_score'] > $result['Game']['away_score']) { 
      $wins[$home_team][$away_team]++; 
      $losses[$away_team][$home_team]++; 
     } else { 
      $wins[$away_team][$home_team]++; 
      $losses[$home_team][$away_team]++; 
     } 
    } 

$results является массив, который содержит результаты запроса к базе данных

(ред добавить код Python, я имею в-PRoFESS)

Теперь у меня есть это, но в Python. results содержит коллекцию SQLAlchemy результата объектов

from sqlalchemy import Column, create_engine, ForeignKey, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 


Base = declarative_base() 
engine = create_engine('postgresql://stats:[email protected][email protected]/ibl_stats') 
Session = sessionmaker() 
Session.configure(bind=engine) 
session = Session() 


class Game(Base): 
    __tablename__ = 'games' 

    id = Column(Integer, primary_key=True) 
    week = Column(Integer) 
    home_score = Column(Integer) 
    away_score = Column(Integer) 
    home_team_id = Column(Integer, ForeignKey('franchises.id')) 
    away_team_id = Column(Integer, ForeignKey('franchises.id')) 


class Franchise(Base): 
    __tablename__ = 'franchises' 

    id = Column(Integer, primary_key=True) 
    nickname = Column(String(3)) 
    name = Column(String(50)) 
    conference = Column(String(10)) 
    division = Column(String(10)) 
    ip = Column(Integer) 

# Loop through our standings building up the breakdown results 
results = session.query(Game).all() 
wins = dict() 
losses = dict() 

for result in results: 
    home_team = result.home_team_id 
    away_team = result.away_team_id 

    if result.home_score > result.away_score: 
     wins[home_team][away_team] += 1 
     losses[away_team][home_team] += 1 
    else: 
     wins[away_team][home_team] += 1 
     losses[home_team][away_team] += 1 

Так что, когда я запускаю этот код, я получаю следующее сообщение об ошибке:

(venv)[email protected]:/vagrant/scripts$ python playoff_odds.py 
Traceback (most recent call last): 
    File "playoff_odds.py", line 45, in <module> 
    wins[home_team][away_team] += 1 
KeyError: 1 

Я сделал некоторые поиски раньше, и он начинает получать в понятие «autovivification» , что-то PHP по умолчанию, но Python этого не делает.

Итак, как мне дублировать одно и то же поведение в коде Python?

+0

Я бы начал писать Python. Доступ к Python вложенным dicts можно получить точно так же, как вы делаете в своем PHP. '$ result ['Game'] ['home_team_id']' будет просто 'result ['Game'] ['home_team_id']' в Python. Почему бы тебе не поехать. Если вы столкнетесь с определенной проблемой, * тогда * будет время попросить о помощи. – SiHa

+0

Другими словами, сначала попробуйте что-то :) – Mai

+0

Да, извините, я забыл добавить в версию Python то, над чем я работаю. –

ответ

2

Python's built-in dict class can be subclassed to implement autovivificious dictionaries simply by overriding the missing() method, но это только часть решения. Если бы вы были просто реализовать Tree пример в ссылке Википедии и сделать что-то вроде:

wins = Tree() 

wins['team_a']['team_b'] += 1 

Вы бы работать в: TypeError: unsupported operand type(s) for +=: 'Tree' and 'int', потому что пример кода будет wins['team_a']['team_b'] будет автоматически был набран Tree, а также.

Принимая во внимание:

wins = Tree() 

wins['team_a']['team_b'] = 1 

бы присвоить значение 1 правильно (как это переназначение, а не операция по существующей типизированной значения).

Решение будет подклассифицировано для реализации автовивитации и, гарантируя, что элементы листа являются целыми числами, на которых вы можете работать.Ниже следует решить эту проблему для вас, или, по крайней мере, чтобы вы начали:

Следующая должно помочь, или, по крайней мере, чтобы вы начали:

from collections import defaultdict 

def autovivify(levels=1, final=dict): 
    return (defaultdict(final) if levels < 2 
     else defaultdict(lambda: autovivify(levels - 1, final))) 

wins = autovivify(2, int) 
losses = autovivify(2, int) 

wins['team_a']['team_b'] += 1 
losses['team_b']['team_a'] += 1 

wins['team_b']['team_c'] += 1 
losses['team_c']['team_b'] += 1 

wins['team_a']['team_c'] += 1 
losses['team_c']['team_a'] += 1 

wins['team_a']['team_b'] += 1 
losses['team_b']['team_a'] += 1 

print(wins['team_a']) # outputs defaultdict(<type 'int'>, {'team_b': 2, 'team_c': 1}) 

Источник:http://blogs.fluidinfo.com/terry/2012/05/26/autovivification-in-python-nested-defaultdicts-with-a-specific-final-type/

The autovivify функции будет гарантировать, что первое задание (team_a) даст вам другое дерево автоподготовки, а второе (team_b) даст вам целое число. Оттуда ваш += 1 будет продолжать увеличивать начальное значение 0.

1

Я думаю, что я бы, вероятно, использовал namedtuples здесь, но это трудно сказать только из этого фрагмента.

Если вы хотите материал о том, как писать более Pythonic код, я рекомендую проверить видео Раймонда Hettinger, особенно

«Лучшие практики для прекрасного вразумительного кода» и «Превращая код в красивую, идиоматической Python» :

http://pyvideo.org/speaker/raymond-hettinger.html

1

Этот вопрос имеет множество интерпретаций. Например, я бы моделировать результаты со следующим словарем:

>>> result = {'Game':{'home_team':{'score':20,'id':1}, 'away_team':{'score':15,'id':2}}} 
>>> print result['Game'] 
{'home_team': {'score': 20, 'id': 1}, 'away_team': {'score': 15, 'id': 2}} 
>>> print result['Game']['home_team'] 
{'score': 20, 'id': 1} 
>>> print result['Game']['away_team']['score'] 
15 

Есть много способов, чтобы имитировать ваш код, выше только один из них. Конечно, код не делает то, что делает PHP-код, просто показывает способ доступа к данным.

Смежные вопросы