简体   繁体   English

`vars` 和 `setattr` 有什么区别?

[英]What is the difference between `vars` and `setattr`?

After failing to use vars to change db.Model(flask-sqlalchemy) value I solved it by using setattr instead, but after reading doc still don't get the difference between vars and setattr .在使用 vars 更改 db.Model(flask-sqlalchemy) 值失败后,我改用setattr解决了这个问题,但在阅读文档后仍然没有得到varssetattr之间的区别。

Here is what I have tried这是我尝试过的

Failed in varsvars失败

Code代码

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def set_option_parameters(var, option_keys, options):
    for option_key in options:
        if option_key in option_keys and options[option_key] is not None:
            vars(var)[option_key] = options[option_key]
            # setattr(var, option_key, options[option_key])

class Application(db.Model):
    id = db.Column(db.BigInteger(), primary_key=True, autoincrement=True)
    name = db.Column(db.VARCHAR(20), nullable=False)
    ...
    def __init__(self, options):
        option_keys = set(["name"])
        set_option_parameters(self, option_keys, options)

    def modification(self, options):
        modifiable = set(["name"])
        set_option_parameters(self, modifiable, options)

vars(var)[option_key] = options[option_key] works fine in initing a Application object , but failed in modification ( name didn't change). vars(var)[option_key] = options[option_key]在初始化Application对象时工作正常,但modification失败( name没有改变)。

Log/Test日志/测试

And I tried to print the application.__dict__ before db.session.commit() , it did be modified!我试图在db.session.commit()之前打印application.__dict__ ,它确实被修改了!

application = Application.query.filter_by(id=args["id"]).first()
# args["name"] is not None
app.logger.info(f"Before: {application.__dict__}")
application.modification(args)
app.logger.info(f"After: {application.__dict__}")
db.session.commit()

output输出

[2019-02-27 11:22:59,209] INFO in equipmentbaseapplicationhandler: Before:{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7f718ac2b588>, 'id': 9, 'name': 'old_name'}
[2019-02-27 11:22:59,209] INFO in equipmentbaseapplicationhandler: After:{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7f718ac2b588>, 'id': 9, 'name': 'new_name'}

BUT When I checked in mysql, it did not work但是当我检查 mysql 时,它不起作用

Successed in setattrsetattr成功

Then I changed to setattr(var, option_key, options[option_key]) in function set_option_parameters .然后我在函数set_option_parameters更改为setattr(var, option_key, options[option_key])

it works good in both init and modification, and the output of application.__dict__ is the same! init 和application.__dict__都很好用, application.__dict__的输出是一样的!

From the docs for vars :来自vars的文档

Objects such as modules and instances have an updateable dict attribute;模块和实例等对象具有可更新的dict属性; however, other objects may have write restrictions on their dict attributes (for example, classes use a types.MappingProxyType to prevent direct dictionary updates).但是,其他对象可能对其dict属性有写限制(例如,类使用 types.MappingProxyType 来防止直接字典更新)。

Looking through the SQLAlchemy source code (for instance, here ), it is a common pattern to return a copy of some_model.__dict__ when accessed, rather than returning the __dict__ itself.查看 SQLAlchemy 源代码(例如, 这里),在访问时返回some_model.__dict__的副本是一种常见模式,而不是返回__dict__本身。 So you are likely updating a copy rather than the original.因此,您可能正在更新副本而不是原件。 Otherwise, it's possible that the dict is getting overwritten by the attributes themselves, even if the dict changes.否则,即使 dict 更改,dict 也可能被属性本身覆盖。

setattrs is the correct pattern, and is more explicit. setattrs是正确的模式,而且更加明确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM