python带模块里延迟导入名字,python模块,#!/usr/bin/e


#!/usr/bin/env python# -*-coding: utf8-*-# Title: lazynames.py# Author: Gribouillis for the python forum at www.daniweb.com# Created: 2012-09-25 12:20:15.556784 (isoformat date)# License: Public Domain# Use this code freely.""" module: lazynames -    Usage:        This module allows a python module to import symbols lazily        by declaring a "name getter function" like module A below:            # module A            import lazynames            @lazynames.set_getter(__name__):            def func(module, attribute):                return attribute.upper()        The client module B below imports symbols from A which        are not defined in A             # module B            from A import foo, bar, baz            print(foo, bar, baz) # prints FOO BAR BAZ        When foo, bar, baz are imported, module A uses its        "name getter function" to create values for these names.        Optionaly, the values can be stored in module A, so that        they would be created only once:            @lazynames.set_getter(__name__)            def func(module, attribute):                value = attribute.upper()                setattr(module, attribute, value)                return value        The following operations are possible:            lazynames.set_getter("my.mod")(func)                Sets a name getter function for the module named "my.mod".                Module my.mod must already exist in sys.modules for this                to work.                This can be used more than once for the same module.                lazynames.set_getter("my.mod") can also be used as a                function decorator as shown above.                The "name getter function" can be called __getattr__ as                it behaves like a __getattr__ function: an expression                like my.mod.foo calls the name getter function with                argument "foo" if the name "foo" does not already exist                in module my.mod. The name getter function should raise                AttributeError to indicate that it can not create a value                for a given name.                By default, set_getter won't set a name getter for the                __main__ module, unless a special flag is passed:                    lazynames.set_getter("__main__", allow_main = True)(func)                This means that if the example module A above is used                as a script instead of being imported, the name getter                won't be set.            lazynames.get_getter("my.mod")                returns the current name getter function of module my.mod                if it has been defined, otherwise return None"""from collections import namedtuplefrom functools import partialimport sysall = ["get_getter", "set_getter", "LazyModule"]Record = namedtuple("Record", "module getter")REGISTERED = dict()class LazyModule(object):    def __init__(self, dict):        self.__dict__ = dict    def __getattr__(self, attr):        record = REGISTERED[self.__name__]        try:            return getattr(record.module, attr)        except AttributeError:            if attr.startswith("__"):                raise            else:                return record.getter(self, attr)def get_getter(name):    return REGISTERED[name].getter if name in REGISTERED else Nonedef set_getter(name, allow_main = False):    return partial(_register, name = name, allow_main = allow_main)def _register(getter_func, name = "__main__", allow_main = False):    if getter_func is None:        _unregister(name)    elif allow_main or name != "__main__":        mod = (REGISTERED[name].module if name in REGISTERED                else sys.modules[name])        record = Record(module = mod, getter = getter_func)        REGISTERED[name] = record        sys.modules[name] = LazyModule(mod.__dict__)    return getter_funcdef _unregister(name):    try:        record = REGISTERED.pop(name)    except KeyError:        pass    else:        sys.modules[name] = record.module

评论关闭