在构造过程中从 **kwargs 设置类的属性
这里是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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我的建议是不要进一步简化它。如果您分配任意属性,您将面临踩踏重要对象结构的风险。
我要做的一个简化是当你在字典上使用
.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.实际上,声明性基类已经插入了您正在寻找的确切构造函数,如 声明性模块文档。因此,只需执行
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 andUser(something_not_an_attribute='foo')
will raise an exception.如果您不需要覆盖继承的属性,
如果您确实需要覆盖继承的属性,inspect.getmembers 可以提供帮助(使用自定义谓词来避免名称以下划线开头的成员,或者您希望确保不能设置的其他成员)方式)。
如果
set(kwargs) - set(keys_ok)
不为空,我也会考虑(至少)发出警告 - 即,如果某些命名参数传递给create
> 不能在创建的实例中设置为参数;这可不是什么好事......!-)If you don't need to cover inherited attributes,
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 tocreate
cannot be set as arguments in the created instance; that can't be a good thing...!-)