Python名称空间元素可见性(与正确的包结构相对

时间:2013-10-26 07:45:56

标签: python pyramid python-import

Python3

试图找到答案却失败了。首先,我将介绍该片段,然后我将解释为什么我想这样做以及我想要实现的目标。也许它看起来像这种方法是“坏的”。 因此,这个半双主题,首先我想知道为什么这个片段不起作用,其次 - 我想知道这种方法是否正确。

所以:

class Namespace:
    def some_function():
        pass

    class SomeClass:
        fcnt = some_function

由于以下原因,这不起作用:

NameError: name 'some_function' is not defined

我想要实现的是代码和文件结构的可读性。

以上示例是我在Pyramid项目中使用的片段(不是这个,但看起来像这样)。

我的项目树看起来像这样:

my_project
├── models
│   ├── __init__.py
│   └── some_model.py
├── schemas
│   ├── __init__.py
│   ├── some_schema.py
│   └── some_other_schema.py
...
├── views
│   ├── __init__.py
│   └── some_view.py
└── __init__.py

我想要实现的是干净的架构/模型/视图导入。

some_schema.py 文件位于{strong> some_other_schema.py class SomeSchema中的class SomeOtherSchema

通过上面的代码片段我可以: from my_project.schemas.some_schema import Schema

并像Schema.SomeSchema()

一样使用它

我对包裹和import有点失落。如何创建一个干净的结构(每个文件一个模式)并仍然能够使用Schema命名空间? (在C ++中我只是将每个类放在Schema命名空间中,这就是我在上面的代码片段中执行此操作的原因。但是!在C ++中有用的可能不应该在python中使用,对吧?)。

感谢您提前回答。

修改 好的,我已经做了一些测试(我以为我已经完成了,但看起来不是......)。

  1. 在第二个导入阴影中使用from my_project.schemas.some_schema import Schema与另一个from my_project.schemas.some_other_schema import Schema导致第一个导致。因此,如果在第一次导入后我可以使用x = Schema.SomeSchema()而不是第二次导入后我将无法执行此操作,因为class Schema会被覆盖。是的,正如Erik所说 - 类不是名称空间。 GOT IT!
  2. 在我的第一个片段中,是的,我应该使用fnct = Namespace.some_function。什么是奇怪的 - 它的工作原理。我的金字塔代码中有相同的陈述,但有一点不同。 some_function@colander.deferred装饰者。实际上它看起来像这样:

    class Schema:
        @colander.deferred
        def deferred_some_function(node, kw):
            something  = kw.get("something", [])
            return deform.widget.SelectWidget(values=something,
                                          multiple=True)
    
        class SomeSchema(colander.MappingSchema):
            somethings  = colander.SchemaNode(colander.Set(),
                                          widget=Schema.deferred_some_function)
    

    我得到NameError: name 'Schema' is not defined

  3. 回到包格式。有了这个:

    ### another/file.py
    from foo.bar.schema import SomeSchema
    
    # do something with SomeSchema:
    smth = SomeSchema()
    smth.fcnt()
    

    我必须创建一个模块foo/bar/schema.py,其中我必须放置所有SomeXSchema类。如果我有很多它们,那么我就想通过拆分SomeXSchema来解决这个不可读的故障 - 每个文件一个。我能以某种方式完成这个吗?我想称这个类为例:User。这就是事情。也许我做错了?我想在User 名称空间中使用名为schema的类,在User 名称空间中使用名为model的类。不应该吗?也许我应该使用前缀?与class SchemaUserclass ModelUser一样?我想通过使用模块/包来避免它。 如果我使用:import foo.bar.schema那么我必须像x = foo.bar.schema.User()一样使用它吗?有没有办法像x = schema.User()一样使用它?对不起,我刚被卡住,我的大脑得到了修复。也许我需要一点休息才能焕然一新?

    另一个编辑(仅限第3点)

    我做了更多的研究。这里的答案是这样:

    ## file: myproject/schemas/__init__.py
    from .some_schema import SomeSchema
    from .some_other_schema import SomeOtherSchema
    

    然后使用就像这样:

    ## some file using it
    import myproject.schemas as schema
    s1 = schema.SomeSchema()
    s2 = schema.SomeOtherSchema()
    

    lege artis 吗?

  4. 如果有人认为应该更改主题 - 继续,给我一些更有意义的东西,我会很感激。

2 个答案:

答案 0 :(得分:2)

你正试图做你正在做的事情而向上游游泳。

类用于定义新数据类型,而不是将相关代码部分组合在一起的方法。模块完全适用于此,我认为你很清楚,因为问题标题中的“(正确的包结构)”部分。

模块也可以作为对象导入,以实现您想要的目标:

### foo/bar/schema.py
def some_function():
    pass
class SomeSchema:
    fcnt = some_function


### another/file.py
from foo.bar import schema

# do something with SomeSchema:
smth = schema.SomeSchema()
smth.fcnt()

...虽然将类直接导入范围也很常见(例如,导入后可以引用SomeSchema而不是schema.SomeSchema):

### another/file.py
from foo.bar.schema import SomeSchema

# do something with SomeSchema:
smth = SomeSchema()
smth.fcnt()

(另请注意,模块名称应为PEP8建议的小写,且只有类名称应使用PascalCase

顺便说一下,这适用于一般的编程,而不仅仅是Python。有一些语言,如Java和C#,要求函数在类中作为静态声明,因为它们不允许在类之外编写代码,但出于某些奇怪的原因,甚至这些语言都有模块/适当的命名空间来构造代码;即,课程通常不会被放入其他课程(有时是,但出于完全不同的原因/目标而不是你的课程)。

所以基本上“类”意味着“类型”或“具有相似行为的一组对象”;一旦你忽略了这个原则/定义,你就会按照定义编写错误的代码。

PS。如果您使用的是Python 2.x,则应该从object继承您的课程,以便获得new-style课程。

PPS。在任何情况下,即使从技术上讲,您尝试做的事情也不会在Python中干净利落:

class fake_namespace:
    def some_function():
        pass
    class RealClass:
        some_function  # <-- that name is not even visibile here;
                       # you'd have to use fake_namespace.some_function instead

...这就是我报告的异常的原因:NameError:名称'some_function'未定义。

根据您的编辑进行编辑:

我不确定你为什么这么复杂;你的一些陈述也是错误的:

  

如果我使用:import foo.bar.schema那么我必须像x = foo.bar.schema.User一样使用它吗?

没有。请了解Python模块的工作原理。

  

我想在Schema名称空间中使用名为User的类,在Model名称空间中使用名为User的类。不应该吗?也许我应该使用前缀?像类SchemaUser和类ModelUser

请注意,名称空间a.k.a.模块应为lowercase而不是PascalCase

  

如果我有很多这样的话,那就是我想通过拆分SomeXSchema来解决这个不可读的故障 - 每个文件一个。我能以某种方式完成这个吗?

是;你可以将你的课程放在单独的子模块中,例如schema1/class1.pyschema/class2.py等;然后您可以将它们“收集”到schema/__init__.py中,以便您可以直接从schema导入它们:

# schema/__init__.py
from .class1 import Class1
from .class2 import Class2

__all__ = [Class1, Class2]  # optional

一般说明:您可以以不同方式命名您的架构模块,例如schema1schema2等;然后你可以像这样使用它们:

from somewhere import schema1
from somewhere_else import schema2

s1_user = schema1.User()
s2_user = schema2.User()
# etc

有关Python模块如何工作的更多信息,请参阅http://docs.python.org/2/tutorial/modules.html

答案 1 :(得分:0)

名称和装订

您可以阅读Python naming and binding并了解Python命名空间的工作原理。

范围定义块中名称的可见性。如果在块中定义了局部变量,则其范围包括该块。如果定义发生在功能块中,则作用域将扩展到定义块中包含的任何块,除非包含的块为名称引入了不同的绑定。 The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods this includes generator expressions since they are implemented using a function scope.

BTW,使用globals()locals()可以帮助调试变量绑定。

用户问题

你可以试试这个:

from model import User as modelUser
from foo.bar.schema import User as schemaUser