[Python-Dev] Breaking undocumented API

Eric Smith eric at trueblade.com
Thu Nov 11 21:44:23 CET 2010


On 11/10/2010 11:58 AM, Tres Seaver wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 11/09/2010 11:12 PM, Stephen J. Turnbull wrote:
>> Nick Coghlan writes:
>>
>>   >  >  Module writers who compound the error by expecting to be imported
>>   >  >  this way, thereby bogarting the global namespace for their own
>>   >  >  purposes, should be fish-slapped. ;)
>>   >
>>   >  Be prepared to fish-slap all of python-dev then - we use precisely
>>   >  this technique to support optional acceleration modules. The pure
>>   >  Python versions of pairs like profile/_profile and heapq/_heapq
>>   >  include a try/except block at the end that does the equivalent of:
>>   >
>>   >    try:
>>   >      from _accelerated import * # Allow accelerated overrides
>>   >    except ImportError:
>>   >      pass # Use pure Python versions
>>
>> But these identifiers will appear at the module level, not global, no?
>> Otherwise this technique couldn't be used.  I don't really understand
>> what Tres is talking about when he writes "modules that expect to be
>> imported this way".  The *imported* module shouldn't care, no?  This
>> is an issue for the *importing* code to deal with.
>
> Right -- "private" star imports aren't the issue for me, because the
> same user who creates them is responsible for the other end fo the
> stick.  I was ranting about library authors who document star imports as
> the expected usage pattern for their external users.
>
> Note that I still wouldn't use star imports in the "private
> acceleration" case myself.  I would prefer a pattern like:
>
> - ----------------------- $<  -----------------------------
> # spam.py
>
> # Pure python API implementation
> def foo(spat, blarg):
>      ...
>
> def bar(qux):
>      ...
>
> # Replace with accelearated C implemenataion
> try:
>      import _spam
> except ImportError:
>      pass # accelerated version not available
> else:
>      foo = _spam.foo
>      bar = _spam.bar
> - ----------------------- $<  -----------------------------
>
> This explicit name remapping catches unintentional erros (e.g., _spam
> renames a method) better than the star import.

But then you're saying that all implementations of _spam have to support 
the same API. What if CPython's _spam has foo, bar, and baz, but 
Jython's only has foo and bar, and IronPython's only has baz? Without 
getting into special casing or lots of try/catch blocks on individual 
names, I think import * is the best way to go.

Eric.


More information about the Python-Dev mailing list