|ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell|
|Prev||Chapter 10. User Modules||Next|
As with Python classes (or almost all Python objects), Python modules have an attribute __dict__ which contains a basic "symbol table" for that object. In the case of a class, the class object has a symbol table containing references to each function and attribute of the class. In the case of a module, the symbol table contains those as well as class definitions.
When exporting a module into an Eiffel-compatible class, we're really concerned mostly with the functions in question (the attributes are handled by the set_attr* series of functions and generated getters, as noted earlier, and the classes can be handled by our earlier Python script as necessary). Focusing on the module itself, export and code generation can be accomplished in much the same way as it was with the user class: import the module and iterate through the __dict__ symbol table--for every item there that appears to be a function, create an analogous feature in the generated Eiffel class. This indeed can generate a single Eiffel class from a single Python module; shown below are the exported "error" attribute and the "compile" feature from the re module:
Example 10-4. Portions of the generated RE Eiffel class
class RE inherit PYTHON_USER_MODULE redefine module_name creation make feature module_name : STRING is "re"; ... error: PYTHON_OBJECT is require has_attr_string( "error" ) do Result := get_attr_string( "error" ) end ... compile( args : ARRAY[ ANY ] ) : PYTHON_OBJECT is do Result := call_function( "compile", python_object_factory.new_python_tuple( args ) ) end compile_python( args : PYTHON_TUPLE ) : PYTHON_OBJECT is do Result := call_function( "compile", args ) end
As it happens, this does our work for us. However, we can make it do even more. Typically, users of a module are interested not just in the functions and data attributes of the module but also in all the classes it exports.