1

Python3

答えを見つけようとしましたが、失敗しました。最初にスニペットを提示し、次になぜこのようにしたかったのか、何を達成したかったのかを説明します。たぶん、このアプローチは「悪いもの」のように見えるでしょう。したがって、この半二重のトピックは、最初にこのスニペットが機能しない理由を知りたいのですが、2 番目に、このアプローチが正しいかどうかを知りたいのです。

そう:

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ファイルはsome_other_schema.pyにありclass SomeSchemaます。 class SomeOtherSchema

上記のスニペットを使用すると、次のことができます。 from my_project.schemas.some_schema import Schema

そしてそれを次のように使用しますSchema.SomeSchema()

importパッケージとsについて少し迷っています。クリーンな構造 (ファイルごとに 1 つのスキーマ) を作成し、それでもスキーマ名前空間を使用できるようにするにはどうすればよいでしょうか? (C++ では、これらのクラスのそれぞれをSchema名前空間に配置するだけでした。そのため、上記のスニペットでこれを行いました。しかし! C++ で機能するものは、Python では使用しないでください。)

事前に回答いただきありがとうございます。

編集: わかりました、私はいくつかのテストを行いました(私はそれをやったと思っていましたが、そうではないようです..)。

  1. from my_project.schemas.some_schema import Schema2番目のインポートで別のfrom my_project.schemas.some_other_schema import Schema原因と一緒に使用すると、最初のインポートがシャドウイングされます。したがって、最初のインポート後に使用できる場合は、2 回目のインポートよりも優先x = Schema.SomeSchema()されるため、これを行うことはできません。class Schemaそうです、Erik が言ったように、クラスは名前空間ではありません。とった!
  2. 私の最初のスニペットでは、はい、使用する必要がありましたfnct = Namespace.some_function。奇妙なこと - それは動作します。私のピラミッド コードにも同じステートメントがありますが、1 つの違いがあります。デコレータ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クラスを配置する必要があるモジュールを 1 つ作成する必要があります。私がそれらをたくさん持っている場合、ファイルごとに1つずつ、SomeXSchemaを分割することで取り除きたいと思っていた読み取り不能なグリッチがあります。どうにかしてこれを達成できますか?たとえば、このクラスを呼び出したい: User. そして、これがTHINGです。多分私はそれを間違っていますか?名前空間で名前が付けられたクラスと名前空間Userで名前が付けられたクラスが必要です。私はすべきではないですか?たぶん、プレフィックスを使用する必要がありますか?のように?モジュール/パッケージを使用して回避したかったのです。: を使用する場合は、次のように使用する必要があります。のように使う方法はありません。schema Usermodel class SchemaUserclass ModelUserimport foo.bar.schemax = 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

あなたがやろうとしていることをやろうとすることで、あなたは上流に泳いでいます。

クラスは、コードの関連部分をグループ化する手段としてではなく、新しいデータ型を定義するためのものです。モジュールはそれに完全に適しています。質問のタイトルの「(vs適切なパッケージ構造)」の部分のために、それをよく知っていると思います。

モジュールはオブジェクトとしてインポートすることもできるので、目的を達成するために:

### 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# などのいくつかの言語では、関数をクラス内で static として宣言する必要があります。これらの言語では、何らかの奇妙な理由でクラス外でコードを記述できないためです。つまり、クラスは通常、他のクラス内に配置されません (場合によっては配置されますが、あなたのものとはまったく異なる理由/目的のためです)。

したがって、基本的に「クラス」は「タイプ」または「同様の動作を持つオブジェクトのセット」を意味します。その原則/定義を無視すると、定義上、悪いコードを書いていることになります。

PS。Python 2.x を使用している場合は、新しいスタイルのobjectクラスを取得するためにクラスを継承する必要があります。

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: 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を分割することで取り除きたい読みにくいグリッチがあります-ファイルごとに1つ。どうにかしてこれを達成できますか?

はい; schema1/class1.pyなどの個々のサブモジュールにクラスを配置できますschema/class2.pyschema/__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 を参照してください

于 2013-10-26T08:03:04.490 に答える
0

名前とバインディング

Python naming and bindingPython 名前空間がどのように機能するかを読んで理解できます。

スコープは、ブロック内の名前の可視性を定義します。ローカル変数がブロックで定義されている場合、そのスコープにはそのブロックが含まれます。定義が関数ブロックで発生する場合、含まれるブロックが名前の別のバインディングを導入しない限り、スコープは定義ブロック内に含まれるすべてのブロックに拡張されます。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 に答える