代码之家  ›  专栏  ›  技术社区  ›  cdiggins

如何/应该如何用Python/其他语言管理跨包模块中的全局数据?

  •  1
  • cdiggins  · 技术社区  · 16 年前

    我正在为一种编程语言设计包和模块系统( Heron )它可以编译和解释,从我所看到的来看,我非常喜欢Python方法。python有丰富的模块选择,这在很大程度上有助于它的成功。

    我不知道的是,如果一个模块包含在两个不同的编译包中,那么在python中会发生什么:数据是由单独的副本构成的还是共享的?

    与此相关的是一系列附带问题:

    1. 我假设包可以用python编译,对吗?
    2. 这两种方法(复制或共享模块数据)有什么利弊?
    3. 从python社区的角度来看,python模块系统是否存在众所周知的问题?例如,是否正在考虑增强模块/包的政治公众人物?
    4. python模块/包系统的某些方面对于编译语言来说不太好吗?
    3 回复  |  直到 16 年前
        1
  •  3
  •   Charles Merriam    16 年前

    嗯,你问了很多问题。下面是一些进一步的提示:

    1. a.python代码是编译成特定于python的指令,但不是编译成机器可执行代码。每当运行与现有.pyc时间戳不匹配的python代码时,就会自动创建“.pyc”文件。此功能可以关闭。您可以使用dis模块查看这些说明。 b.导入模块时,它将在自己的命名空间中执行(从上到下),并且该命名空间将全局缓存。从其他模块导入时,不会再次执行该模块。记住,def只是一个声明。您可能需要在代码中放入print(“编译此模块”)语句来跟踪它。

    2. 这要看情况而定。

    3. 最近有一些增强,主要是关于指定需要加载哪个模块。模块可以有相对路径,这样一个大型项目可以有多个同名的模块。

    4. Python本身不适用于编译语言。谷歌为“unladen swallow blog”提供了一个帮助,让你看到加速一种语言的艰难之处,“a=sum(b)”可以改变两次执行之间的含义。除了角情况外,模块系统在源代码和编译的库系统之间形成了一个很好的桥梁。这种方法工作得很好,而Python对C代码(swig等)的简单包装也有帮助。

        2
  •  3
  •   Roger Pate    16 年前

    模块是Python中唯一真正的全局对象,所有其他全局数据都基于模块系统(使用sys.modules作为注册表)。包只是具有特殊语义的模块,用于导入子模块。”将.py文件编译为.pyc或.pyo并不像大多数语言所理解的那样编译:它只检查语法并创建一个代码对象,在解释器中执行时,它会创建模块对象。

    PYP:

    print "Creating %s module." % __name__
    
    def show_def(f):
      print "Creating function %s.%s." % (__name__, f.__name__)
      return f
    
    @show_def
    def a():
      print "called: %s.a" % __name__
    

    交互式会话:

    >>> import example
    # first sys.modules['example'] is checked
    # since it doesn't exist, example.py is found and "compiled" to example.pyc
    # (since example.pyc doesn't exist, same would happen if it was outdated, etc.)
    Creating example module. # module code is executed
    Creating function example.a. # def statement executed
    >>> example.a()
    called: example.a
    >>> import example
    # sys.modules['example'] found, local variable example assigned to that object
    # no 'Creating ..' output
    >>> d = {"__name__": "fake"}
    >>> exec open("example.py") in d
    # the first import in this session is very similar to this
    # in that it creates a module object (which has a __dict__), initializes a few
    # variables in it (__builtins__, __name__, and others---packages' __init__
    # modules have their own as well---look at some_module.__dict__.keys() or
    # dir(some_module))
    # and executes the code from example.py in this dict (or the code object stored
    # in example.pyc, etc.)
    Creating fake module. # module code is executed
    Creating function fake.a. # def statement executed
    >>> d.keys()
    ['__builtins__', '__name__', 'a', 'show_def']
    >>> d['a']()
    called: fake.a
    

    你的问题:

    1. 从某种意义上说,它们是编译的,但如果您熟悉C编译器的工作方式,则不会像您所期望的那样进行编译。
    2. 如果数据是不可变的,那么复制是可行的,除了对象标识之外,复制应该与共享不可区分。( is 运算符和 id() 在蟒蛇中)。
    3. 导入可以执行代码,也可以不执行代码(它们总是将局部变量赋给对象,但不会造成任何问题),也可以修改sys.modules,也可以不修改sys.modules。您必须小心不要在线程中导入,通常最好在每个模块的顶部执行所有导入:这会导致一个级联图,因此所有导入都是一次完成的,然后uuMain_uuuuuuuu继续并执行真正的Work™。
      • 我不知道现在有什么政治公众人物,但已经有很多复杂的机械设备就位了。例如,包可以具有 __path__ attribute (实际上是一个路径列表)这样子模块就不必在同一个目录中,甚至可以在运行时计算这些路径!(例如下面的mungepath包。)您可以有自己的导入挂钩,在函数中使用import语句,直接调用uu import_uuuuuuu,我不会惊讶地发现2-3种其他独特的方法来处理包和模块。
    4. 导入系统的一个子集可以使用传统的编译语言,只要它类似于C's include。您可以在编译器中运行“第一级”执行(创建模块对象),并编译这些结果。但是,这也有很大的缺点,相当于为模块级代码和在运行时执行的函数分离执行上下文(有些函数必须在这两个上下文中运行!)(请记住,在python中,每个语句都是在运行时执行的,甚至是def和class语句。)
      • 我认为这是传统编译语言将“顶级”代码限制为类、函数和对象声明的主要原因,从而消除了第二个上下文。即使如此,在C/C++(和其他)中,全局对象也有初始化问题,除非仔细管理。

    mungepath/uu init_uuu.py:

    print __path__
    __path__.append(".") # CWD, would be different in non-example code
    print __path__
    from . import example # this is example.py from above, and is NOT in mungepath/
    # note that this is a degenerate case, in that we now have two names for the
    # 'same' module: example and mungepath.example, but they're really different
    # modules with different functions (use 'is' or 'id()' to verify)
    

    交互式会话:

    >>> import example
    Creating example module.
    Creating function example.a.
    >>> example.__dict__.keys()
    ['a', '__builtins__', '__file__', 'show_def', '__package__',
     '__name__', '__doc__']
    >>> import mungepath
    ['mungepath']
    ['mungepath', '.']
    Creating mungepath.example module.
    Creating function mungepath.example.a.
    >>> mungepath.example.a()
    called: mungepath.example.a
    >>> example is mungepath.example
    False
    >>> example.a is mungepath.example.a
    False
    
        3
  •  1
  •   jldupont    16 年前

    全局数据的作用域在解释器级别。

    1. “包”可以编译为一个包,它只是模块的集合,可以编译它们自己。
    2. 我不确定我是否理解既定的数据范围。