python-flask-sqlalchemy之getattr函数封装

93 阅读2分钟

文章由来

最近在学习python的sqlalchemy+flask-sqlalchemy时,学到了一个用法是: db = SQLAlchemy(app) 函数内部: db.Column() 这个用法, 但是发现通过ide工具进去查看函数定义在from flask_sqlalchemy import SQLAlchemy 内部是找不到关于Column函数的定义的,让我很困惑。 于是乎,便有了接下来的源码探索(小山山基础知识不扎实)

问题解决

import sqlalchemy as sa
import sqlalchemy.event as sa_event
import sqlalchemy.exc as sa_exc
import sqlalchemy.orm as sa_orm
  1. 在flask-sqlalchemy的类中有一块这个代码的导入 ,并通过as关键字将sqlalchemy命名为了sa ,在SQLAlchemy类的底部有一块代码内容为getattr函数的重写
def __getattr__(self, name: str) -> t.Any:
    if name == "relation":
        return self._relation

    if name == "event":
        return sa_event

    if name.startswith("_"):
        raise AttributeError(name)

    for mod in (sa, sa_orm):
        if hasattr(mod, name):
            return getattr(mod, name)

    raise AttributeError(name)
  1. getattr 函数由python的object基类进行提供,可以被所有类继承使用。
  2. 当使用obj.attr语法访问一个对象的属性时,如果这个属性不存在,会自动调用getattr(obj, 'attr')
  3. 在函数内部有一块代码为hasattr函数,作用是:请求过来的attrname在指定的mod相等的时候,该函数便返回true。 如果成立 ,则直接调用object类的getattr函数,便可以成功向上查找到所需要的Column()函数;如果false查不到则抛出指定异常。

总结

  1. 能力可以继承来,也可以通过基类中提供的钩子函数来间接的实现继承类的功能。这样我们可以便直接使用db.Column()而不需要导入sqlalchemy,就是利用了这个机制。
  2. 这样flask-sqlalchemy就通过魔术方法getattr把对sqlalchemy的访问代理到了自己的类中,让使用者可以更方便地访问sqlalchemy提供的功能。

头回发帖,请各位老铁多指教

013DB59E.png