在构造过程中从 **kwargs 设置类的属性

发布于 2024-09-04 00:39:50 字数 1618 浏览 7 评论 0原文

这里是Python菜鸟,

目前我正在使用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 protected]"
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 梯子,所以我可以更改表结构而不修改此代码。

有什么建议吗?

Python noob here,

Currently I'm working with SQLAlchemy, and I have this:

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

This is in /db/users.py, so it would be used like:

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

but the code in create() is a little stupid, and I'm wondering if there's a better way to do it that doesn't require an if ladder, and that will fail if any keys are added that aren't in the User object already. Like:

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

that way I could put this in its own function (unless one hopefully already exists?) So I wouldn't have to do the if ladder again and again, and so I could change the table structure without modifying this code.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

缪败 2024-09-11 00:39:50

我的建议是不要进一步简化它。如果您分配任意属性,您将面临踩踏重要对象结构的风险。

我要做的一个简化是当你在字典上使用 .keys() 时删除它;包含检查和迭代都已经使用了这些密钥。

...

再想一想,您可以拥有一个包含已知安全属性的类属性,然后在函数中检查此属性,并在实例上使用 setattr()

My suggestion would be to not simplify it any further. You risk stepping on important object structures if you assign arbitrary attributes.

The one simplification I would do is to drop .keys() when you use it on a dict; both containment checking and iteration already use the keys.

...

On second thought, you could have a class attribute that contains known safe attributes, and then check this attribute within the function, and use setattr() on the instance.

兮子 2024-09-11 00:39:50

实际上,声明性基类已经插入了您正在寻找的确切构造函数,如 声明性模块文档。因此,只需执行 User(username="Carson", password="1234") 即可完成您想要的操作,而 User(something_not_an_attribute='foo') 将引发异常。

Actually the declarative base class already inserts the exact constructor that you are looking for, as documented in the declarative modules docs. So just doing User(username="Carson", password="1234") will do what you want and User(something_not_an_attribute='foo') will raise an exception.

旧街凉风 2024-09-11 00:39:50

如果您不需要覆盖继承的属性,

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 > 不能在创建的实例中设置为参数;这可不是什么好事......!-)

If you don't need to cover inherited attributes,

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

If you do need to cover inherited attributes, inspect.getmembers can help (with a custom predicate to avoid members whose names start with underscore, or others you want to ensure can't be set this way).

I would also consider (at least) giving a warning if set(kwargs) - set(keys_ok) is not empty -- i.e., if some of the named arguments passed to create cannot be set as arguments in the created instance; that can't be a good thing...!-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文