代码之家  ›  专栏  ›  技术社区  ›  Carson Myers

从**kwargs在构造期间设置类的属性

  •  1
  • Carson Myers  · 技术社区  · 15 年前

    这里是python noob,

    目前我正在使用sqlacalchemy,我有:

    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梯形图,如果添加了用户对象中没有的任何键,这将失败。像:

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

    这样我就可以把它放到它自己的函数中(除非希望已经存在了一个函数?)因此,我不必一次又一次地执行if梯形图,这样就可以在不修改此代码的情况下更改表结构。

    有什么建议吗?

    3 回复  |  直到 15 年前
        1
  •  2
  •   Ignacio Vazquez-Abrams    15 年前

    我的建议是不要再简化它了。如果您分配任意属性,就有可能踏上重要的对象结构。

    我要做的一个简化就是 .keys() 当您在dict上使用它时,包含检查和迭代都已经使用了键。

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

        2
  •  2
  •   Ants Aasma    15 年前

    实际上,声明性基类已经插入了您要查找的确切构造函数,如中所述 the declarative modules docs . 所以只是做 User(username="Carson", password="1234") 会做你想做的 User(something_not_an_attribute='foo') 将引发异常。

        3
  •  1
  •   Alex Martelli    15 年前

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

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