【问题标题】:Pass Variable On Import导入时传递变量
【发布时间】:2010-09-15 18:46:09
【问题描述】:

假设您在第一次导入模块/类时有一些耗时的工作要做。此功能取决于传入的变量。它只需要在加载模块/类时完成。然后类的所有实例都可以使用结果。

例如,我使用的是 rpy2:

import rpy2.robjects as robjects

PATH_TO_R_SOURCE = ## I need to pass this
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time

class SomeClass:
  def __init__(self, aCurve):
    self._curve = aCurve

  def processCurve(self):
    robjects.r['someRFunc'](robjects.FloatVector(self._curve))

我是否坚持创建一个我调用来完成工作的模块级函数?

import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...

【问题讨论】:

    标签: python import


    【解决方案1】:

    拥有模块初始化函数并非闻所未闻。 Pygame 为 sdl 初始化函数执行此操作。所以是的,你最好的选择可能是

    import someModule
    someModule.init(NECESSARY_DATA)
    x = someModule.someClass(range(1, 5))
    

    【讨论】:

    • 关于如何在模块中设置初始化函数的任何信息?这与 __init__.py 文件相同吗?根据您上面所写的内容,它看起来并非如此。如果您的模块中只有常规函数而不是类,这可能吗?
    • 这不像__init__.py 文件。示例中的 init 函数只是一个普通函数,用于初始化模块中的全局状态。
    • 找不到描述 init 方法的好链接。您能否分享一个描述模块初始化如何工作的链接。谢谢!
    • @NightFurry:这不是什么特殊的技术。它只是模块中的一个函数,您在程序开始时调用一次。如果合适的话,你可以在模块加载时调用它,但它实际上只是一个普通函数。
    【解决方案2】:

    我必须为我的项目做类似的事情。如果您不想依赖调用脚本来运行初始化函数,您可以添加自己的 Python 内置函数,然后在运行时可用于所有模块。

    小心为你的内置函数命名一些独特的东西,不太可能导致命名空间冲突(例如myapp_myvarname)。

    运行.py

    import __builtin__
    __builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
    import someClass
    

    someClass 模块 .py

    import rpy2.robjects as robjects
    import __builtin__
    
    if hasattr(__builtin__, "myapp_PATH_TO_R_SOURCE"):
        PATH_TO_R_SOURCE = __builtin__.myapp_PATH_TO_R_SOURCE
    else:
        PATH_TO_R_SOURCE = ## Some default value or Null for Exception handling
    robjects.r.source(PATH_TO_R_SOURCE, chdir = True)
    
    ...
    

    这适用于可能具有默认值但您希望在导入时允许覆盖的变量。如果没有设置__builtin__ 变量,它将使用默认值。

    编辑:有些人认为这是“猴子补丁”的一个例子。如需不带猴子补丁的更优雅的解决方案,see my other answer

    【讨论】:

    • 谢谢!这对于在导入期间执行代码的模块很有用,并且您希望设置执行所需的变量。 init 函数在这种情况下没有帮助,因为 init 只能在导入完成后调用。
    • 这对我有用,但对于 python 3,需要 import builtin
    • 我真的很喜欢这个!对我来说,使用 Python 3,我需要使用内置函数(复数),但它就像 @Aaron D 用 builtin 解释的那样工作
    【解决方案3】:

    如果只有一个配置项要设置,那么我发现覆盖 python __builtin__ 可以正常工作,但它是 "Monkey patching" 的一个示例,有些人不赞成。

    对项目中的多个配置项非常有用的更简洁的方法是创建一个单独的配置模块,首先由包装代码导入,并在运行时设置项目,然后再导入功能模块。这种模式经常在其他项目中使用。

    myconfig/__init__.py:

    PATH_TO_R_SOURCE   = '/default/R/source/path'
    OTHER_CONFIG_ITEM  = 'DEFAULT'
    PI                 = 3.14
    

    mymodule/__init__.py:

    import myconfig
    
    PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
    robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time
    
    class SomeClass:
      def __init__(self, aCurve):
        self._curve = aCurve
    
    if myconfig.VERSION is not None:
      version = myconfig.VERSION
    else:
      version = "UNDEFINED"
    
    two_pi = myconfig.PI * 2
    

    您可以在运行时从包装器更改模块的行为:

    run.py:

    import myconfig
    
    myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
    myconfig.PI = 3.14159
    # we can even add a new configuration item that isn't present in the original myconfig:
    myconfig.VERSION="1.0"
    
    import mymodule
    print "Mymodule.two_pi = %r" % mymodule.two_pi
    print "Mymodule.version is %s" % mymodule.version
    

    输出:

    > Mymodule.two_pi = 6.28318
    > Mymodule.version is 1.0
    

    【讨论】:

    • 这个也很不错!多优雅。没有猴子。我希望您不介意我已经编辑了您的其他答案以指向该答案的链接。
    • 我想补充一点,您可以简单地创建名为myconfig.pymymodule.py 的文件。这将与更少的复杂性一样工作。 有趣的事实: 你可以让myconfig.py 完全空白。要检查是否设置了变量,您还可以使用 tryexcept AttributeError(除非您不喜欢使用 try-except 那种东西)。
    【解决方案4】:

    无法在导入时传递变量。

    一些想法:

    • 使模块使用检查从调用模块中获取变量;不是很pythonic
    • 为模块使用 Init 函数,这是最好的方法

    【讨论】:

      【解决方案5】:

      可以实现您的目标的其他几个选项(尽管 init() 函数可能更简洁):

      • 使用环境变量
      • 使用单独的模块 M 来保存此变量,导入程序将设置该变量。然后导入的模块可以知道在哪里找到 M,或者可以依赖 sys.meta_path 来获取它。

      【讨论】:

        【解决方案6】:

        不,您并没有被模块级功能所困扰,它可能是最好的选择。您还可以使用内置的 staticmethodclassmethod 装饰器使其成为 someSclass 上的一个方法,可以在实例化之前调用。

        只有在someClass 以外的所有内容都可以在没有初始化的情况下使用并且我仍然认为模块级函数更好时,这才有意义

        【讨论】:

        • 问题是当有模块不能使用类时,例如flask with blueprint,每个控制器只能函数不能类,不能将功能封装在类中。
        【解决方案7】:

        我能想到两种解决方案,它们都是非常类似于变通解决方案的解决方案。首先是放弃导入并像这样运行您的脚本

        sys.argv[1] = "argument 1"
        sys.argv[2] = "argument 2"
        execfile("/path/to/dependency.py")  #depreciated in python 3.x
        

        第二种是将你的参数放入一个外部临时文件中,然后从依赖项中的那个文件中读取。

        【讨论】:

          【解决方案8】:

          您能从实现延迟加载的代理中受益吗?

          查看活动状态“Lazy Module Imports”配方。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-28
            • 2021-12-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多