文章由来
最近在学习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
- 在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)
- getattr 函数由python的object基类进行提供,可以被所有类继承使用。
- 当使用obj.attr语法访问一个对象的属性时,
如果这个属性不存在,会自动调用getattr(obj, 'attr')。 - 在函数内部有一块代码为hasattr函数,作用是:请求过来的attrname在指定的mod相等的时候,该函数便返回true。
如果成立 ,则直接调用object类的getattr函数,便可以成功向上查找到所需要的Column()函数;如果false查不到则抛出指定异常。
总结
能力可以继承来,也可以通过基类中提供的钩子函数来间接的实现继承类的功能。这样我们可以便直接使用db.Column()而不需要导入sqlalchemy,就是利用了这个机制。- 这样flask-sqlalchemy就
通过魔术方法getattr把对sqlalchemy的访问代理到了自己的类中,让使用者可以更方便地访问sqlalchemy提供的功能。
头回发帖,请各位老铁多指教