简体   繁体   English

Python包含,模块范围问题

[英]Python includes, module scope issue

I'm working on my first significant Python project and I'm having trouble with scope issues and executing code in included files. 我正在做我的第一个重要的Python项目,遇到范围问题和执行包含文件中的代码的麻烦。 Previously my experience is with PHP. 以前,我的经验是使用PHP。

What I would like to do is have one single file that sets up a number of configuration variables, which would then be used throughout the code. 我想做的是只有一个文件,该文件设置了许多配置变量,然后将在整个代码中使用它。 Also, I want to make certain functions and classes available globally. 另外,我想使某些函数和类在全局范围内可用。 For example, the main file would include a single other file, and that file would load a bunch of commonly used functions (each in its own file) and a configuration file. 例如,主文件将包括一个其他文件,并且该文件将加载一堆常用功能(每个都在其自己的文件中)和一个配置文件。 Within those loaded files, I also want to be able to access the functions and configuration variables. 在那些加载的文件中,我还希望能够访问函数和配置变量。 What I don't want to do, is to have to put the entire routine at the beginning of each (included) file to include all of the rest. 我不想做的是,必须将整个例程放在每个(包含的)文件的开头,以包含所有其余部分。 Also, these included files are in various sub-directories, which is making it much harder to import them (especially if I have to re-import in every single file). 另外,这些包含的文件位于各个子目录中,这使得导入它们变得更加困难(尤其是如果我必须在每个文件中都重新导入文件时)。

Anyway I'm looking for general advice on the best way to structure the code to achieve what I want. 无论如何,我正在寻找有关构建代码以实现我想要的最佳方法的一般建议。

Thanks! 谢谢!

In python, it is a common practice to have a bunch of modules that implement various functions and then have one single module that is the point-of-access to all the functions. 在python中,通常的做法是拥有一堆实现各种功能的模块,然后只有一个模块作为所有功能的访问点。 This is basically the facade pattern . 这基本上是门面图案

An example: say you're writing a package foo , which includes the bar , baz , and moo modules. 一个例子:假设您正在编写foo包,其中包括barbazmoo模块。

~/project/foo
~/project/foo/__init__.py
~/project/foo/bar.py
~/project/foo/baz.py
~/project/foo/moo.py
~/project/foo/config.py

What you would usually do is write __init__.py like this: 通常,您会这样写__init__.py

from foo.bar import func1, func2
from foo.baz import func3, constant1
from foo.moo import func1 as moofunc1
from foo.config import *

Now, when you want to use the functions you just do 现在,当您想使用功能时

import foo
foo.func1()
print foo.constant1
# assuming config defines a config1 variable
print foo.config1

If you wanted, you could arrange your code so that you only need to write 如果需要,您可以安排代码,以便只需要编写

import foo

At the top of every module, and then access everything through foo (which you should probably name "globals" or something to that effect). 在每个模块的顶部,然后通过foo (应将其命名为“ globals”或类似名称)访问所有内容。 If you don't like namespaces, you could even do 如果您不喜欢命名空间,甚至可以

from foo import *

and have everything as global, but this is really not recommended. 并且将所有内容都具有全局性,但实际上不建议这样做。 Remember: namespaces are one honking great idea! 请记住:名称空间是一个很棒的主意!

This is a two-step process: 这是一个两步过程:

  1. In your module globals.py import the items from wherever. 在您的模块中globals.py从任何地方导入项目。
  2. In all of your other modules, do "from globals import *" 在所有其他模块中,执行“从全局变量导入*”

This brings all of those names into the current module's namespace. 这会将所有这些名称带入当前模块的名称空间。

Now, having told you how to do this, let me suggest that you don't . 现在,告诉您如何执行此操作后, 让我建议您不要这样做 First of all, you are loading up the local namespace with a bunch of "magically defined" entities. 首先,您正在使用一堆“神奇定义的”实体加载本地名称空间。 This violates precept 2 of the Zen of Python , "Explicit is better than implicit." 这违反了Python Zen的规范2:“显式优于隐式”。 Instead of "from foo import *", try using "import foo" and then saying "foo.some_value". 而不是“ from foo import *”,请尝试使用“ import foo”,然后说“ foo.some_value”。 If you want to use the shorter names, use "from foo import mumble, snort". 如果要使用较短的名称,请使用“ from foo import mumble,snort”。 Either of these methods directly exposes the actual use of the module foo.py. 这两种方法都直接公开了模块foo.py的实际使用。 Using the globals.py method is just a little too magic. 使用globals.py方法太神奇了。 The primary exception to this is in an __init__.py where you are hiding some internal aspects of a package. 主要的例外是__init__.py,其中您隐藏了程序包的某些内部方面。

Globals are also semi-evil in that it can be very difficult to figure out who is modifying (or corrupting) them. 全局变量也是半邪恶的,因为很难弄清楚是谁在修改(或破坏)它们。 If you have well-defined routines for getting/setting globals, then debugging them can be much simpler. 如果您有定义明确的例程来获取/设置全局变量,则调试它们会更加简单。

I know that PHP has this "everything is one, big, happy namespace" concept, but it's really just an artifact of poor language design. 我知道PHP具有这个“一切都是一个大的,快乐的命名空间”的概念,但这实际上只是糟糕的语言设计的产物。

As far as I know program-wide global variables/functions/classes/etc. 据我所知,程序范围内的全局变量/函数/类/等。 does not exist in Python, everything is "confined" in some module (namespace). 在Python中不存在,所有内容都“限制”在某个模块(名称空间)中。 So if you want some functions or classes to be used in many parts of your code one solution is creating some modules like: "globFunCl" (defining/importing from elsewhere everything you want to be "global") and "config" (containing configuration variables) and importing those everywhere you need them. 因此,如果您希望在代码的许多部分中使用某些函数或类,则一个解决方案是创建一些模块,例如:“ globFunCl”(​​定义/从其他位置导入您想成为“全局”的所有内容)和“ config”(包含配置)变量),然后将其导入您需要的任何位置。 If you don't like idea of using nested namespaces you can use: 如果您不喜欢使用嵌套名称空间的想法,可以使用:

from globFunCl import *

This way you'll "hide" namespaces (making names look like "globals"). 这样,您将“隐藏”名称空间(使名称看起来像“全局变量”)。

I'm not sure what you mean by not wanting to " put the entire routine at the beginning of each (included) file to include all of the rest ", I'm afraid you can't really escape from this. 我不确定您不想“ 将整个例程放在每个(包含的)文件的开头以包括其余的所有内容 ”是什么意思,恐怕您真的无法摆脱这一点。 Check out the Python Packages though, they should make it easier for you. 不过,请查看Python软件包 ,它们应该会使您更轻松。

This depends a bit on how you want to package things up. 这取决于您要如何打包。 You can either think in terms of files or modules . 您可以根据文件模块来考虑 The latter is "more pythonic", and enables you to decide exactly which items (and they can be anything with a name: classes, functions, variables, etc.) you want to make visible. 后者是“更pythonic的”,使您能够准确地决定要使哪些项目可见(它们可以是任何名称,包括类,函数,变量等)。

The basic rule is that for any file or module you import, anything directly in its namespace can be accessed. 基本规则是,对于您导入的任何文件或模块,都可以直接访问其命名空间中的任何内容。 So if myfile.py contains definitions def myfun(...): and class myclass(...) as well as myvar = ... then you can access them from another file by 因此,如果myfile.py包含def myfun(...):class myclass(...)以及myvar = ...则可以通过以下方式从另一个文件访问它们:

import myfile
y = myfile.myfun(...)
x = myfile.myvar

or 要么

from myfile import myfun, myvar, myclass

Crucially, anything at the top level of myfile is accessible, including imports. 至关重要的是,可以访问myfile顶层的所有内容, 包括导入文件。 So if myfile contains from foo import bar , then myfile.bar is also available. 因此,如果myfile from foo import bar包含,则myfile.bar也可用。

Others have talked about the right way to do this from Python. 其他人则在谈论使用Python实现此目的的正确方法。

Let me add, however, that having users change a source file to configure your application -- while common in the PHP world -- isn't very Pythonic. 但是,让我补充一点,让用户更改源文件来配置您的应用程序(虽然在PHP世界中很常见)不是Python风格。 Consider using the ConfigParser standard library module or the ConfigObj third-party module (which supports complex datatypes such as nested dicts, lists, etc) to parse a configuration file instead. 考虑使用ConfigParser标准库模块或ConfigObj第三方模块(它支持复杂的数据类型,例如嵌套字典,列表等)来解析配置文件。

Having a config.py module which is responsible for parsing this configuration file, and which other code in your application imports and queries for settings, is appropriate -- but having the user edit this config.py on installation really isn't. 拥有一个负责解析此配置文件的config.py模块,以及应用程序中导入和查询设置的其他代码是合适的-但实际上让用户在安装时编辑此config.py是不合适的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM