SQLAlchemy引擎连接函数返回类型标注为object是否正确?
我编写了一个获取SQLAlchemy Engine连接的函数,正常执行时返回sqlalchemy.engine.base.Engine类的实例,但目前把返回类型标注为object。请问这样的标注是否正确?函数代码如下:
def get_engine_connection( username: str, password: str, database: str, host: str = "localhost", port: str = "3306", ) -> object: try: engine = create_engine( f"mysql+pymysql://{username}:{password}@{host}:{port}/{database}", echo=False, poolclass=NullPool, ) return engine except Exception as error: print(error)
回答
从语法上来说,把返回类型标注为object是合法的——因为Python里所有对象都是object的子类,Engine实例自然也符合这个类型。但这种标注完全违背了类型提示的初衷,非常不推荐这么做,原因有两点:
类型提示失去作用
类型标注的核心目的是让代码更清晰,帮助IDE提供智能提示、让类型检查工具(比如mypy)提前发现问题。如果标成object,其他开发者(包括未来的你)根本不知道这个函数实际返回的是什么类型,也没法提前知道可以调用Engine的connect()、execute()等方法,IDE也不会给出任何代码补全提示。隐藏了异常后的返回风险
你的函数在捕获异常后只打印错误,没有显式返回值,这时候函数会默认返回None——而None也是object的子类,这会导致调用者预期拿到Engine实例,结果可能拿到None,后续调用Engine方法时直接触发AttributeError,却没法通过类型检查提前发现这个问题。
正确的做法
1. 标注具体的Engine类型
首先导入Engine类型,把返回类型改成Engine,同时建议在异常捕获后重新抛出错误,让调用者处理异常:
from sqlalchemy import Engine from sqlalchemy import create_engine from sqlalchemy.pool import NullPool def get_engine_connection( username: str, password: str, database: str, host: str = "localhost", port: str = "3306", ) -> Engine: try: engine = create_engine( f"mysql+pymysql://{username}:{password}@{host}:{port}/{database}", echo=False, poolclass=NullPool, ) return engine except Exception as error: print(error) raise
2. 标注可选类型(处理可能返回None的情况)
如果坚持保留原有的异常处理逻辑(只打印不抛出),那么函数可能返回None,这时候应该用Optional[Engine]标注,明确告知调用者返回值可能为空:
from typing import Optional from sqlalchemy import Engine from sqlalchemy import create_engine from sqlalchemy.pool import NullPool def get_engine_connection( username: str, password: str, database: str, host: str = "localhost", port: str = "3306", ) -> Optional[Engine]: try: engine = create_engine( f"mysql+pymysql://{username}:{password}@{host}:{port}/{database}", echo=False, poolclass=NullPool, ) return engine except Exception as error: print(error) return None
总结:标注成object不是语法错误,但完全浪费了类型提示的价值,建议根据函数实际的返回情况,标注Engine或Optional[Engine]。
内容的提问来源于stack exchange,提问作者Rodrigo Praxedes

