1

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文件class SomeSchema中,在some_other_schema.py class SomeOtherSchema中。

使用上面的代码片段,我可以制作: from my_project.schemas.some_schema import Schema

并像使用它一样Schema.SomeSchema()

import我对包裹和s有点迷茫。如何制作一个干净的结构(每个文件一个模式)并且仍然能够使用 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 所说——类不是命名空间。知道了!
  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. 如果有人认为应该更改该主题 - 继续,给我一些更有意义的东西,我将不胜感激。

4

2 回答 2

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以获得新风格的类。

聚苯乙烯。在任何情况下,即使从技术上讲,您尝试做的事情在 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: name 'some_function' is not defined。

根据您的编辑进行编辑:

我不太确定你为什么把它弄得这么复杂。你的一些陈述也是错误的:

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

不,请了解 Python 模块的工作原理。

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

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

于 2013-10-26T08:03:04.490 回答
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.

顺便说一句,使用globals()locals()可以帮助调试变量绑定。

用户问题

你可以试试这个:

from model import User as modelUser
from foo.bar.schema import User as schemaUser
于 2013-10-26T15:32:59.853 回答