[Python-ideas] Forward-References & Out-of-order declaration
Chris Angelico
rosuav at gmail.com
Thu Aug 27 01:41:19 CEST 2015
On Thu, Aug 27, 2015 at 3:15 AM, Kale Kundert <kale at thekunderts.net> wrote:
> Just to provide a concrete example, sqlalchemy's ORM seems to really contort
> itself (at least from the user's perspective) to get around this problem. The
> reason in that case is that the dependencies between tables don't have to be
> directed acyclic graphs, e.g. it's common for two tables to depend on each other.
Fair point, but in my experience with SQLAlchemy, it's not that bad to
identify tables with string identifiers:
class Manufacturer(Base):
__tablename__ = 'manufacturers'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
stuff = relationship("Thing", backref="manufacturer")
class Thing(Base):
__tablename__ = 'things'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
makerid = Column(Integer, ForeignKey('manufacturer.id'), nullable=False)
(I might have the specifics a bit wrong, but it's something like this.)
> I've also run into this problem when working with my home-grown message-passing
> APIs, which can also form more complicated dependency graphs. So I do think
> that good code occasionally has to warp itself to fit into python's model.
Same sort of thing.
You're right that these violate (by necessity) the principle of "first
use is definition", but these are incredibly rare cases. Just in the
example above, and without any real code doing any real work, I have
seven names:
Manufacturer, Base, Column, Integer, relationship, Thing, String
Two of them have a cyclic relationship (Manufacturer and Thing). All
of the rest can still follow that principle (and in this case, most of
them would be listed in the top-of-file import block). There are
specific situations where the graph is more complicated, but I still
like being confident that the code will broadly follow that design
layout.
The two basic solutions still apply: either use string names to
identify not-yet-defined objects, or have a "pre-declare" syntax to
make things possible. In C, "struct foo;" is enough to let you declare
pointers to foo; in Python, you could have "Thing = Table()" prior to
defining Manufacturer, and then you could use an unquoted Thing to
define the relationship. Either way makes it clear that something
unusual is happening.
ChrisA
More information about the Python-ideas
mailing list