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中使用,对吧?)。
感谢您提前回答。
修改 好的,我已经做了一些测试(我以为我已经完成了,但看起来不是......)。
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!在我的第一个片段中,是的,我应该使用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
回到包格式。有了这个:
### 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 SchemaUser
和class 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 吗?
如果有人认为应该更改主题 - 继续,给我一些更有意义的东西,我会很感激。
答案 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.py
,schema/class2.py
等;然后您可以将它们“收集”到schema/__init__.py
中,以便您可以直接从schema
导入它们:
# schema/__init__.py
from .class1 import Class1
from .class2 import Class2
__all__ = [Class1, Class2] # optional
一般说明:您可以以不同方式命名您的架构模块,例如schema1
,schema2
等;然后你可以像这样使用它们:
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