Just a couple of philosophical comments...
Whenever I find that the web2py platform is "forcing" me to code in large volumes and produce ugly, quirky code which I know will be hard to maintain, I stop myself and take another look at how I'm trying to accomplish my task. I have this philosophy that using a platform like web2py (or Python, or Linux, or anything) involves a certain mindset. Those who created and maintain the platform envisioned working with it in a certain way. I call that the "swimming downstream" way of working. When I find I am "swimming upstream" I realize that I'm not using the platform as intended.
In this case, for instance, you want to instantiate one table but NOT another table which is linked to this table. That seems like a logic error to me. It looks like a FEATURE that lazy table instantiation will create BOTH tables in this case -- certainly the linked table and its definition should be available wherever its linker table exists. Standing on your head to get around this is "swimming upstream".
There are numerous ways to make your site more efficient, if efficiency turns out to be a problem. Believe me, I get it. I, too, am guilty of "premature optimization" more often that I like to admit. But the best course of action is to steam ahead and get your application working the easiest way possible (downstream swimming). Then, and only then, locate any performance trouble spots and apply optimization. Lazy tables are only one such optimization.
You heard mention of putting tables in a module. I have about 50 tables in my app, some with 50 fields. To instantiate all of them all of the time would be somewhat of a burden. So I have opted to put table creation in modules. If that isn't enough, I'll worry about that when I have a problem.
Swim downstream. It's the only way!
-- Joe