SQLAlchemy create_engine如何导入Engine类?

Jor*_*ips 3 python sqlalchemy

我是python的新手,正在尝试SQLAlchemy。我注意到,要创建引擎,我必须使用create_engine()通过导入的函数from sqlalchemy import create_engine

现在,该create_engine函数返回sqlalchemy.engine.base.Engine该类的实例。但是,我从未导入此类,仅导入了create_engine模块。那么,Python如何知道sqlalchemy.engine.base.Engine该类?

Mar*_*ers 6

您可能不了解导入的作用。

Python 在全球范围内导入模块。有一个名为的结构,sys.modules将导入的模块存储为字典:

>>> import sys
>>> sys.modules
{'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, ...}
Run Code Online (Sandbox Code Playgroud)

导入SQLAlchemy时,将导入package,即多个模块的结构,其中一个导入会触发更多导入。所有这些导入的模块都存储在同一个地方:

>>> import sqlalchemy
>>> [name for name in sys.modules if 'sqlalchemy' in name]
['sqlalchemy', 'sqlalchemy.sql', 'sqlalchemy.sql.expression', 'sqlalchemy.sql.visitors', 'sqlalchemy.util', 'sqlalchemy.util.compat', 'sqlalchemy.util._collections', 'sqlalchemy.util.langhelpers', 'sqlalchemy.exc', 'sqlalchemy.util.deprecations', 'sqlalchemy.sql.functions', 'sqlalchemy.sql.sqltypes', 'sqlalchemy.sql.elements', 'sqlalchemy.inspection', 'sqlalchemy.sql.type_api', 'sqlalchemy.sql.operators', 'sqlalchemy.sql.base', 'sqlalchemy.sql.annotation', 'sqlalchemy.processors', 'sqlalchemy.cprocessors', 'sqlalchemy.event', 'sqlalchemy.event.api', 'sqlalchemy.event.base', 'sqlalchemy.event.attr', 'sqlalchemy.event.registry', 'sqlalchemy.event.legacy', 'sqlalchemy.sql.schema', 'sqlalchemy.sql.selectable', 'sqlalchemy.sql.ddl', 'sqlalchemy.util.topological', 'sqlalchemy.sql.util', 'sqlalchemy.sql.dml', 'sqlalchemy.sql.default_comparator', 'sqlalchemy.sql.naming', 'sqlalchemy.events', 'sqlalchemy.pool', 'sqlalchemy.log', 'sqlalchemy.interfaces', 'sqlalchemy.util.queue', 'sqlalchemy.engine', 'sqlalchemy.engine.interfaces', 'sqlalchemy.sql.compiler', 'sqlalchemy.sql.crud', 'sqlalchemy.engine.base', 'sqlalchemy.engine.util', 'sqlalchemy.cutils', 'sqlalchemy.engine.result', 'sqlalchemy.cresultproxy', 'sqlalchemy.engine.strategies', 'sqlalchemy.engine.threadlocal', 'sqlalchemy.engine.url', 'sqlalchemy.dialects', 'sqlalchemy.types', 'sqlalchemy.schema', 'sqlalchemy.engine.default', 'sqlalchemy.engine.reflection']
Run Code Online (Sandbox Code Playgroud)

从磁盘加载模块并将其添加到该结构后,Python无需再次加载它。点在层次结构中分隔模块名称,因此所有以树开头的内容都以树结构形式sqlalchemy.存在于sqlalchemy包中。这里有很多sqlalchemy模块,这是一个很大的项目,并且它们都是由根包模块sqlalchemy/__init__.py加载(直接或间接)的。

另一件事import在当前名称空间中绑定一个名称。每个模块都是一个“全局”名称空间,该名称空间中的所有名称在该名称空间中均可见。您的Python脚本将作为__main__名称空间导入,并且脚本中的所有名称均可用。如果创建模块foo,则这是具有自己名称的独立命名空间。import加名从另一个模块的全局命名空间。而在Python中,名称只是引用 ; 这些名称各自引用的实际对象都生活在称为堆的内存堆中

线

from sqlalchemy import create_engine
Run Code Online (Sandbox Code Playgroud)

首先确保该对象sys.modules['sqlalchemy']存在,然后将该名称添加create_engine到您当前的名称空间中,以引用sqlalchemy.create_engine,就像create_engine = sys.modules['sqlalchemy'].create_engine执行该行一样:

>>> sys.modules['sqlalchemy'].create_engine
<function create_engine at 0x10188bbf8>
>>> from sqlalchemy import create_engine
>>> create_engine is sys.modules['sqlalchemy'].create_engine
True
Run Code Online (Sandbox Code Playgroud)

同样,Python中的所有名称都只是对内存中大量对象的引用

调用该create_engine()函数时,将执行该函数的代码,并且该函数可以访问其定义在其名称空间中的所有全局变量。在这种情况下,该函数在sqlalchemy.engine模块中定义(顶层sqlalchemy模块本身已导入它from sqlalchemy.engine import create_engine使你可以更方便的位置访问):

>>> create_engine.__module__
'sqlalchemy.engine'
>>> sys.modules['sqlalchemy.engine']
<module 'sqlalchemy.engine' from '/Users/mjpieters/Development/venvs/stackoverflow-3.6/lib/python3.6/site-packages/sqlalchemy/engine/__init__.py'>
>>> sorted(vars(sys.modules['sqlalchemy.engine']))
['BaseRowProxy', 'BufferedColumnResultProxy', 'BufferedColumnRow', 'BufferedRowResultProxy', 'Compiled', 'Connectable', 'Connection', 'CreateEnginePlugin', 'Dialect', 'Engine', 'ExceptionContext', 'ExecutionContext', 'FullyBufferedResultProxy', 'NestedTransaction', 'ResultProxy', 'RootTransaction', 'RowProxy', 'Transaction', 'TwoPhaseTransaction', 'TypeCompiler', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'base', 'connection_memoize', 'create_engine', 'ddl', 'default', 'default_strategy', 'engine_from_config', 'interfaces', 'reflection', 'result', 'strategies', 'threadlocal', 'url', 'util']
Run Code Online (Sandbox Code Playgroud)

该名称列表是与在同一模块中定义的所有名称create_engine。导入sqlalchemy模块时,该模块已经由执行的代码加载。该函数可以访问所有这些对象,并且可以返回任何此类对象。你会注意到,是一个Engine定义有名字:

>>> sys.modules['sqlalchemy.engine'].Engine
<class 'sqlalchemy.engine.base.Engine'>
Run Code Online (Sandbox Code Playgroud)

因此,该对象已加载到内存的Python。该函数所做的全部工作就是为您创建该类的实例并返回:

>>> engine = create_engine('sqlite:///:memory:')
>>> engine
Engine(sqlite:///:memory:)
>>> type(engine)
<class 'sqlalchemy.engine.base.Engine'>
Run Code Online (Sandbox Code Playgroud)

如果您想了解有关Python和名称的更多信息,建议您阅读Ned Batchelder 关于python名称和值的事实与神话的文章。