Установка атрибутов класса при построении из ** kwargs - PullRequest
1 голос
/ 28 мая 2010

Python Noob здесь,

В настоящее время я работаю с SQLAlchemy, и у меня есть это:

from __init__ import Base
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Integer, String
from sqlalchemy.orm import relationship

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    username = Column(String, unique=True)
    email = Column(String)
    password = Column(String)
    salt = Column(String)
    openids = relationship("OpenID", backref="users")

User.__table__.create(checkfirst=True)

#snip definition of OpenID class

def create(**kwargs):
    user = User()
    if "username" in kwargs.keys():
        user.username = kwargs['username']
    if "email" in kwargs.keys():
        user.username = kwargs['email']
    if "password" in kwargs.keys():
        user.password = kwargs['password']

    return user

Это в /db/users.py, поэтому он будет использоваться как:

from db import users
new_user = users.create(username="Carson", password="1234")
new_user.email = "email@address.com"
users.add(new_user) #this function obviously not defined yet

но код в create() немного глуп, и мне интересно, есть ли лучший способ сделать это, не требующий лестницу if, и который потерпит неудачу, если будут добавлены какие-либо ключи, которые не являются в объекте User уже. Как:

for attribute in kwargs.keys():
    if attribute in User:
        setattr(user, attribute, kwargs[attribute])
    else:
        raise Exception("blah")

таким образом, я мог бы поместить это в свою собственную функцию (если, как мы надеемся, она уже существует?), Поэтому мне не пришлось бы делать лестницу if снова и снова, и поэтому я мог бы изменить структуру таблицы без изменения этого кода. 1014 *

Есть предложения?

Ответы [ 3 ]

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

На самом деле декларативный базовый класс уже вставляет именно тот конструктор, который вы ищете, как описано в декларативных модулях документации . Так что просто User(username="Carson", password="1234") будет делать то, что вы хотите, а User(something_not_an_attribute='foo') вызовет исключение.

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

Мое предложение состоит в том, чтобы больше не упрощать его. Вы рискуете наступить на важные структуры объектов, если назначите произвольные атрибуты.

Единственное упрощение, которое я хотел бы сделать, - сбросить .keys(), когда вы используете его на диктанте; и проверка содержимого, и итерация уже используют ключи.

...

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

1 голос
/ 28 мая 2010

Если вам не нужно покрывать унаследованные атрибуты,

def create(**kwargs):
    keys_ok = set(User.__dict__)
    user = User()
    for k in kwargs:
        if k in keys_ok:
            setattr(user, k, kwargs[k])

Если вам нужно необходимо покрыть унаследованные атрибуты, inspect.getmembers может помочь (с пользовательским предикатом, чтобы избежать членов, чьи имена начинаются с подчеркивания, или других, которые вы хотите гарантировать не будет установлен таким образом).

Я бы также рассмотрел (по крайней мере) предупреждение, если set(kwargs) - set(keys_ok) не пусто, т. Е. Если некоторые из именованных аргументов, переданных create , не могут быть установлены в качестве аргументов в созданном пример; это не может быть хорошей вещью ...! -)

...