2016-05-27 3 views
2

Позвольте мне предисловие к этому, сказав, что я довольно новичок в Python, и прошу прощения, если это не подходящее место для этого вопроса.Упростить использование базы данных (psycopg2), создав модуль

Я использую модуль psycopg2 для управления базой данных PostgreSQL. Общее использование будет выглядеть примерно так:

# Example 1 

import psycopg2 

conn = psycopg2.connect(database="mydb", user="postgres") 
cur = conn.cursor() 

cur.execute ("SELECT * FROM mytable;") 
rows = cur.fetchall() 
for i, row in enumerate(rows): 
    print "Row", i, "value = ", row 

cur.close() 
conn.close() 

Это откроет соединение с MYDB базы данных , выберите все поля из таблицы туЬаЫх и распечатать их, а затем закрыть соединение.

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

  • core.db_init() - которая открывает соединение и состоит из первых двух строк коды выше.
  • core.db_query (query) - который выполняет требуемый SQL-запрос и состоит из третьей строки в указанном выше коде.
  • core.db_close() - который закрывает соединение и состоит из двух последних строк.

Я попытался создать модуль следующим образом:

# Module core.py 

import psycopg2 

def db_init(): 
    conn = psycopg2.connect(database="mydb", user="postgres") 
    cur = conn.cursor() 

def db_query(query): 
    cur.execute(query) 

def db_close(): 
    cur.close() 
    conn.close() 

Но я получаю ошибки пространства имен, когда я пытаюсь воссоздать пример 1 с помощью этого модуля:

# Example 2 

import core 

core.db_init() 
core.db_query("SELECT * FROM mytable;") 

rows = cur.fetchall() 
for i, row in enumerate(rows): 
    print "Row", i, "value = ", row  

core.db_close() 

Я даже не уверенный, что модуль - это то, что я хочу. Должен ли я использовать класс вместо этого? Опять же, я очень новичок в этом. Но если кто-то может помочь мне найти лучший способ сделать это, я буду очень благодарен.

+0

Хорошо написанный вопрос btw, есть все, что вы пробовали, какое ваше желаемое поведение было бы и примерно фактическая ошибка. Также приветствуем StackOverflow и особенно приветствуем Python:) Если какой-либо из приведенных ниже ответов решает вашу проблему, не забудьте пометить вопрос как «Ответ», чтобы он не попал в кучу оставшихся без ответа вопросов. – Torxed

ответ

2

Ваш главный вопрос, является то, что каждая переменная ограничена функцией вы написали ее в
Если иное не заявлено, как, например:.

def db_init(): 
    global conn 
    conn = psycopg2.... 

Лучше было бы преобразовать это в класс, основной пример может быть:

import psycopg2 

class MyDatabase(): 
    def __init__(self, db="mydb", user="postgres"): 
     self.conn = psycopg2.connect(database=db, user=user) 
     self.cur = self.conn.cursor() 

    def query(self, query): 
     self.cur.execute(query) 

    def close(self): 
     self.cur.close() 
     self.conn.close() 

db = MyDatabase() 
db.query("SELECT * FROM table;") 
db.close() 

Теперь SELECT запроса не будет делать, так как вы используете cur.execute().
Но я сохранил это для того, чтобы код был похож на то, что вы написали, вы захотите поменять его, чтобы возвращать значения, однако, если вы вызываете запрос, который должен возвращать значение и так далее.

Ваш подход, ориентированный на функции, будет иметь проблемы с «пространством имен», где переменные живут в локальной области действия этой функции и там для других функций не могут нормально обращаться к ним.

Вместо этого переменные класса могут получить доступ к своим переменным и есть не так уж и ограниченно.

Вы могли бы сделать глобальные переменные и объявить их как глобальные в функциях, но я думаю, что, как я уже говорил в комментарии:

Вы хотели бы сделать это в классе. База данных представляет собой объект, основанный на сеансе, так же, как классы являются сущностными сущностями. Обрабатывайте каждое соединение как живое существо посредством абстрактного его класса, иначе cur и conn станут облачными переменными, и вам нужно будет работать с ними в глобальном масштабе.

+1

Большое вам спасибо! В конце концов я использовал ваш подход к классу почти дословно. Я очень ценю, что вы нашли время, чтобы ответить на мой вопрос, даже если это было довольно noobish. Спасибо за теплый прием :) – fattybake

+0

@fattybake приветствую вас, и мое удовольствие. Дружелюбные люди, как вы, стоили того, чтобы потратить лишнюю минуту на ответы, заданные :) не отставайте и удачи в ваших начинаниях! – Torxed

0

Вы можете сделать это так, как хотите, хотя я бы рассмотрел возможность использования sqlalchemy или другого модуля для обработки этих деталей для вас.

Код, который вы вставили, не работает, потому что cursor не определен другими способами.

Рассмотрим это делать в одном вызове - например:

# Module core.py 

import psycopg2 

def execute_query(query): 
    conn = psycopg2.connect(database="mydb", user="postgres") 
    cur = conn.cursor() 
    results = cur.execute(query) 
    cur.close() 
    conn.close() 
    return results 

Обратите внимание, что это не является оптимальным, и если вы делаете много мелких запросов умерщвления соединения для каждого из них не самая лучшая идея.

+0

Спасибо за этот ответ! Я ценю, что вы пытались сохранить его как можно более похожим на мой метод. Вы определенно правы в том, что он является субоптимальным, потому что он будет открывать и закрывать соединение каждый раз, когда я пытаюсь что-либо сделать. Я закончил с решением Torxed, потому что это то, что я пытался сделать, хотя я не знал точно, что мне нужно. – fattybake

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