Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 24, 2012 04:25:10

totoer
Зарегистрирован: 2012-10-24
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

Дело в том что я недавно начал изучать Python и у меня возникают вопросы на которые трудно найти ответ в документации. Задача состоит в следующем: отделить реализацию взаимодействия с хранилищем данных от логики. Задача усложняется тем, что различные наборы данных нуждаются в различных методах взаимодействия с БД, а абстрагировать ух как хочется. То есть задача сводится к реализации некоего метода представлявшего из себя что то среднее между потернами строителя и фасада. Но это все преамбула! Вопрос: Стоит ли мне оторвать руки и повесить на шею табличку “Он убивает котят каждой строкой своего кода!” или же все в порядке вещей? Да чуть не забыл, будем считать что все данные валидны.

def insert(self, values = {}, target = ''):
    inst = locals().get(target)()
        
    for parameter in values:
        inst.__dict__[param] = values[parameter]
...

Где: values - собственно говоря словарик в котором ключ есть свойство экземпляра класса с соответствующим значением, target - то самое целевое место куда эти данные должны угодить.

Заранее благодарю!

Офлайн

#2 Окт. 24, 2012 05:31:44

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

totoer
Задача состоит в следующем: отделить реализацию взаимодействия с хранилищем данных от логики.
Задача интересная, если она нужна Вам в целях академических. Если же Вам нужна именно практическая реализация, то советую не изобретать велосипед, а взять уже готовые решения, например http://www.sqlalchemy.org/, лучше все равно вряд ли получится.



Офлайн

#3 Окт. 24, 2012 13:53:22

totoer
Зарегистрирован: 2012-10-24
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

Спасибо за интересный вариант. К сожалению использовать slqalchemy не совсем возможно по одной простой причине БД не SQL. Собственно говоря мне было интересно узнать имею ли я право использовать конкретные две строчки кода.

inst = locals().get(target)()
inst.__dict__[param] = values[parameter]
Извините за то что не уточнил. Я понимаю что они усложняют понимание кода, но мне не совсем понятно приводят ли они к каким то побочным эффектом в механизме программы.

Офлайн

#4 Окт. 24, 2012 14:19:36

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

А какая конкретно задача решается этими строчками, может мы предложим вариант покошернее?



Офлайн

#5 Окт. 24, 2012 16:03:43

totoer
Зарегистрирован: 2012-10-24
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

Для начало надо сказать что приложение работает в среде google web engine соответственно использует её окружение включая БД. Зада состоит в разделении реализации логики от реализации взаимодействия с БД.
В общем случае код реализации интерфейса работы с БД выглядит так:

consumer.py

from producer import DataBaseInterface
class NewEmployee:
    ...
    def make(self, name, salary):
        values['name'] = name
        values['salary'] = str(salary)
        DataBaseInterface.insert(values, 'Employee')
        ...
class NewManager:
    ...
    def make(self, name, salary, departament):
        values['name'] = name
        values['salary'] = str(salary)
        values['departament'] = departament
        DataBaseInterface.insert(values, 'Manager')

producer.py
from google.appengine.ext import db
class Employee(db.Model):
    name = StringProperty()
    salary = InteregProperty()
class Manager(db.Model):
    name = StringProperty()
    salary = InteregProperty()
    departament = StringProperty()
class DataBaseInterface:
    ...
    def insert(self, values, target):
        #Допустим тут данные проходят валидность, я к тому что значения values и target на данном этапе можно считать валидными
        instModel = locals().get(target)()
        for parameter in values:
            instModel.__dict__[param] = values[parameter]
        instModel.put()

Таким образом можно скрыть, по моему мнению, реализацию работы с БД (Модели, методы модели и т.д.) за общим интерфейсом. Обшей концепцией является большая забота над consumer'ом чем над producer'ом. Это обусловлено тем что логика гораздо обширнее чем работа с БД, и абстрагировав большую часть работы с БД (в данном случае со вставкой) гораздо уменьшается количество кода и облегчает его понимание в consumer'е.

Так же этот подход сводит обширный интерфейс producer.py, который мог быть, к нескольким аккуратным методам. Короче упрощаем API работы с БД.

Отредактировано totoer (Окт. 24, 2012 16:11:23)

Офлайн

#6 Окт. 24, 2012 17:06:28

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

Имеет ли подход право на жизнь?

1. Для использования `__dict__` нужны очень везкие аргументы, обрати внимание на `setattr`, `getattr` и `vars`.
2. `locals`, серьёзно? Он же не будет тут работать, там будет только self, values и target. Тогда уж `globals` используй. Хотя оба варианта – дурной тон. Укажи явно поддерживаемые типы в каком-нибудь своём списочке. Как он будет пополняться – тысяча вариантов, для красоты можно приспособить декораторы и/или метаклассы, глянь Martian.
3. Если `insert` не будет методом класса или статическим (а судя по self, он не первое и не второе), то попытка его использования из consumer, указанным в примере образом, потерпит неудачу.
4. Наследуйся от `object`.
5. Познай *args и **kwargs.

..bw



Офлайн

#7 Окт. 24, 2012 18:35:03

totoer
Зарегистрирован: 2012-10-24
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

bw
1. Для использования `__dict__` нужны очень везкие аргументы, обрати внимание на `setattr`, `getattr` и `vars`.
2. `locals`, серьёзно? Он же не будет тут работать, там будет только self, values и target. Тогда уж `globals` используй. Хотя оба варианта – дурной тон. Укажи явно поддерживаемые типы в каком-нибудь своём списочке. Как он будет пополняться – тысяча вариантов, для красоты можно приспособить декораторы и/или метаклассы, глянь Martian.
3. Если `insert` не будет методом класса или статическим (а судя по self, он не первое и не второе), то попытка его использования из consumer, указанным в примере образом, потерпит неудачу.
4. Наследуйся от `object`.
5. Познай *args и **kwargs.
Сори за неточности в коде писал не думая, как пример.
Я не совсем понял какой списочек конкретно вы имели в веду в пункте номер 2. Я не ошибусь, если скажу что вы имели в веду {“A”, A(), “B”: B()}?
Использование мета программирования для данной задачи я считаю монструозным, ведь это всего несколько методов одного класса во всей системе.
Спасибо большое за то что напомнили про *args и **kwargs, я уже несколько раз читал про них но не как не могу запомнить.
В случае с __setattr__ вы предлагаете изменить модели, добавив метод __setattr__? То есть:
class Empoyee(db.Model):
    def __setattr__(self, name, value):
        super(Empoyee, self).__setattr__(name, value)
Соответственно это касается и __getattr__. Мне кажется что это придаст слишком большую степень свободы модели что усложнит контроль валидности. Хотя может я и ошибаюсь.
Пожалуйста скажите чем же плохо использование подобных манипуляций с __dict__ и т.п.?
Извините за такое количество вопросов.

Офлайн

#8 Окт. 24, 2012 19:44:27

Soteric
От:
Зарегистрирован: 2010-09-19
Сообщения: 352
Репутация: +  20  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

Может быть пусть класс сам отвечает за то как себя сохранять?

class Person:
    def __init__(self, id=-1, name="", age=-1):
        self.id = id
        self.name = name
        self.age = age
    def insert(self):
        con = DB.getConnection()
        con.execute("INSERT INTO Persons VALUES(?, ?)", [self.name, self.age])
        con.close()
    def update(self):
        con = DB.getConnection()
        con.execute("UPDATE Persons SET name=?, age=? WHERE id=?", [self.name, self.age, self.id])
        con.close()
    @staticmethod
    def select(query, params):
        con = DB.getConnection()
        cur = con.execute(query, params)
        personData = cur.fetchone()
        con.close()
        id = personData[0]
        name = personData[1]
        age = personData[2]
        return Person(id, name, age)
    @staticmethod
    def getByName(name):
        return select("SELECT * FROM Persons WHERE name=?", [name])
    @staticmethod
    def getByAge(age):
        return select("SELECT * FROM Persons WHERE age=?", [age])



Отредактировано Soteric (Окт. 24, 2012 19:45:13)

Офлайн

#9 Окт. 24, 2012 19:46:09

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

Получается вы хотите писать:

values['name'] = name
values['salary'] = str(salary)
values['departament'] = departament
DataBaseInterface.insert(values, 'Manager')
вместо
manger = Manager(name='Jhon', salary=9000, department='IT')
manager.put()
GAE ORM уже содержит абстракцию - классы, представляющие какие-то сущности, которые можно сохранить в DB.

totoer
В случае с __setattr__ вы предлагаете изменить модели, добавив метод __setattr__
Наверное имелось в виду
http://docs.python.org/library/functions.html#setattr
http://docs.python.org/library/functions.html#getattr
Т.е. вместо манипуляций с __dict__
setattr(instModel, param, values[param])

В общем, целиком поддерживаю bw.

Офлайн

#10 Окт. 24, 2012 20:02:28

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

Имеет ли подход право на жизнь?

какое метапрограммирование зачем же так все усложнять просто вместо

inst.__dict__[name] = value
использовать
setattr(inst, name, value)
так яснее и все.
Но главное не это. Вот что вы делаете:

1 Создаете в классе с “логикой” хеш из имен и значений атрибутов инстанса.
2 Толкаете это вместе с именем класса который будет работать с бд в какой-то обрабатывающий класс
3. обрабатывающий класс начнет искать у себя имя переданного ему класса и создает инстанс этого класса
4 В созданный инстанс запихиваются элементы из переданного хэша
И это вот вы называете абстрагированием логики от бд. Я понимаю конечно пример и т.д но ведь можно было просто передать это все через какой нибудь __init__
также не понятно что вы хотели сказать вот этим
К сожалению использовать slqalchemy не совсем возможно по одной простой причине БД не SQL
Мне думается это все таки то что вам нужно, ага.
А может это я таки дурак и чего-то не понимаю, ведь паттернов строителя и фасада не знаю.
вот жеж слоупок я, а ладно оставлю

Отредактировано sergeek (Окт. 24, 2012 20:05:08)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version