Как написать этот фрагмент на Python? - PullRequest
2 голосов
/ 20 мая 2010

Я изучаю Python (у меня есть опыт работы с C / C ++).

Мне нужно написать что-то практичное на Python, пока я учусь. У меня есть следующий псевдокод (моя первая попытка написания скрипта на Python после вчерашнего чтения о Python). Надеюсь, фрагмент детализирует логику того, что я хочу сделать. Кстати, я использую Python 2.6 на Ubuntu Karmic.

Предположим, что скрипт вызывается как: script_name.py directory_path

import csv, sys, os, glob

# Can I declare that the function accepts a dictionary as first arg?
def getItemValue(item, key, defval)
  return !item.haskey(key) ? defval : item[key]


dirname = sys.argv[1]

# declare some default values here
weight, is_male, default_city_id = 100, true, 1 

# fetch some data from a database table into a nested dictionary, indexed by a string
curr_dict = load_dict_from_db('foo')

#iterate through all the files matching *.csv in the specified folder
for infile in glob.glob( os.path.join(dirname, '*.csv') ):
  #get the file name (without the '.csv' extension)
  code = infile[0:-4]
  # open file, and iterate through the rows of the current file (a CSV file)
  f = open(infile, 'rt')
  try:
    reader = csv.reader(f)
    for row in reader:
      #lookup the id for the code in the dictionary
      id = curr_dict[code]['id']
      name = row['name']
      address1 = row['address1']
      address2 = row['address2']
      city_id = getItemValue(row, 'city_id', default_city_id)

      # insert row to database table

  finally:
    f.close()

У меня есть следующие вопросы:

  1. Достаточно ли написан код на языке Pythonic (есть ли лучший способ его реализации)?

  2. Учитывая таблицу со схемой, подобной показанной ниже, как я могу написать функцию Python, которая извлекает данные из таблицы и возвращает их в словарь, индексированный по строке (name).

  3. Как я могу вставить данные строки в таблицу (на самом деле я хотел бы использовать транзакцию, если это возможно, и зафиксировать непосредственно перед закрытием файла)

Схема таблицы:

create table demo (id int, name varchar(32), weight float, city_id int);

Кстати, моя серверная база данных - postgreSQL

[Изменить]

Уэйн и др .:

Чтобы уточнить, что я хочу, это набор строк. Каждая строка может быть проиндексирована по ключу (что означает, что контейнер строк - это словарь (справа)? Хорошо. Теперь, когда мы получили строку с помощью ключа, я также хочу иметь возможность доступа к «столбцам» в строка - это означает, что сами данные строки представляют собой словарь. Я не знаю, поддерживает ли Python синтаксис многомерного массива при работе со словарями, - но следующее утверждение поможет объяснить, как я намерен концептуально использовать данные, возвращаемые из базы данных. набор данных ['joe'] ['weight'] сначала извлечет данные строки, проиндексированные ключом 'joe' (который является словарем), а затем проиндексирует этот словарь для ключа 'weight'. Я хочу знать, как создать такой словарь словарей из найденных данных на Pythonic, как вы делали раньше.

Упрощенным способом было бы написать что-то вроде:

import pyodbc

mydict = {}
cnxn = pyodbc.connect(params)
cursor = cnxn.cursor()
cursor.execute("select user_id, user_name from users"):

for row in cursor:
   mydict[row.id] = row

Правильно ли это / можно ли написать более питонским способом?

Ответы [ 3 ]

5 голосов
/ 20 мая 2010

, чтобы получить значение из словаря, вам нужно использовать .get метод dict:

>>> d = {1: 2}
>>> d.get(1, 3)
2
>>> d.get(5, 3)
3

Это устранит необходимость в функции getItemValue. Я не буду комментировать существующий синтаксис, поскольку он явно чужд Python. Правильный синтаксис для троичного в Python:

true_val if true_false_check else false_val
>>> 'a' if False else 'b'
'b'

Но, как я говорю ниже, вам это совсем не нужно.

Если вы используете Python> 2.6, вы должны использовать оператор with вместо try-finally:

with open(infile) as f:
    reader = csv.reader(f)
    ... etc

Видя, что вы хотите иметь row в качестве словаря, вы должны использовать csv.DictReader, а не просто csv. reader. Тем не менее, это не нужно в вашем случае. Ваш SQL-запрос может быть просто создан для доступа к полям row dict. В этом случае вам не нужно создавать отдельные элементы city_id, name и т. Д. Чтобы добавить значение по умолчанию city_id к row, если оно не существует, вы можете использовать .setdefault метод:

>>> d
{1: 2}
>>> d.setdefault(1, 3)
2
>>> d
{1: 2}
>>> d.setdefault(3, 3)
3
>>> d
{1: 2, 3: 3}

и для id, просто row[id] = curr_dict[code]['id']

При нарезке вы можете пропустить 0:

>>> 'abc.txt'[:-4]
'abc'

Как правило, библиотека Python предоставляет методы fetchone, fetchmany, fetchall для курсора, которые возвращают объект Row, который может поддерживать диктоподобный доступ или возвращать простой кортеж. Это будет зависеть от того, какой модуль вы используете.

2 голосов
/ 20 мая 2010

двоеточие требуется после def s:

def getItemValue(item, key, defval):
    ...

логические операторы: В Python ! -> not; && -> and и || -> or (см. http://docs.python.org/release/2.5.2/lib/boolean.html для булевых операторов). В python нет оператора ? :, есть выражение return (x) if (x) else (x), хотя я лично редко использую его в пользу простых if.

booleans / None: True, False и None имеют заглавные буквы перед ними.

проверка типов аргументов: В Python вы обычно не объявляете типы параметров функции. Вы могли бы пойти, например, assert isinstance(item, dict), "dicts must be passed as the first parameter!" в функции, хотя этот вид "строгой проверки" часто не рекомендуется, так как это не всегда необходимо в python.

ключевые слова Python: default не является зарезервированным ключевое слово Python и допустимо в качестве аргументов и переменных (только для справки.)

рекомендации по стилю: PEP 8 (руководство по стилю Python) гласит, что модуль import s обычно должен быть только один на строку, хотя есть некоторые исключения (я должен признаюсь, я часто не следую import sys и os в отдельных строках, хотя обычно я следую этому.)

режимы открытия файлов: rt недействителен в python 2.x - он будет работать, хотя t будет игнорироваться. См. Также http://docs.python.org/tutorial/inputoutput.html#reading-and-writing-files. Это действительный в Python 3, хотя, поэтому я не думаю, что будет больно, если вы захотите включить текстовый режим, вызывая исключения для двоичных символов (используйте rb если вы хотите читать не-ASCII символы.)

работа со словарями: Python раньше использовал dict.has_key(key), но вы должны использовать key in dict сейчас (который в значительной степени заменил его, см. http://docs.python.org/library/stdtypes.html#mapping-types-dict.)

расширенных файловых расширений: code = infile[0:-4] можно заменить на code = os.path.splitext(infile)[0] (который возвращает, например, ('root', '.ext') с точкой в ​​расширении (см. http://docs.python.org/library/os.path.html#os.path.splitext).

EDIT: убрал несколько объявлений переменных в одной строке и добавил некоторое форматирование. Также исправлено, что rt не является допустимым режимом в Python, когда в Python 3 он есть.

2 голосов
/ 20 мая 2010

Это выглядит в основном достаточно Pythonic для меня.

Хотя троичная операция должна выглядеть следующим образом (я думаю, что это вернет ожидаемый результат):

return defval if not key in item else item[key]

Да, вы можете передавать словарь (или любое другое значение) практически в любом порядке. Единственное отличие состоит в том, что вы используете * args, ** kwargs (названные по соглашению. Технически вы можете использовать любое имя, которое хотите), которые ожидают быть в таком порядке и последние один или два аргумента.

Для вставки в БД вы можете использовать модуль odbc:

import odbc
conn = odbc.odbc('servernamehere')
cursor = conn.cursor()
cursor.execute("INSERT INTO mytable VALUES (42, 'Spam on Eggs', 'Spam on Wheat')")
conn.commit()

Вы можете прочитать или найти множество примеров на модуле odbc - я уверен, что есть и другие модули, но этот должен хорошо работать для вас.

Для поиска вы бы использовали

cursor.execute("SELECT * FROM demo")
#Reads one record - returns a tuple
print cursor.fetchone()
#Reads the rest of the records - a list of tuples
print cursor.fetchall()

чтобы превратить одну из этих записей в словарь:

record = cursor.fetchone()
# Removes the 2nd element (at index 1) from the record
mydict[record[1]] = record[:1] + record[2:]

Хотя это практически кричит о генераторе, если вы хотите весь шебанг одновременно

mydict = dict((record[1], record[:1] + record[2:] for record in cursor.fetchall())

, который должен дать вам все записи, аккуратно упакованные в словарь, используя имя в качестве ключа.

НТН

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...