(機械翻訳)守るピラミッドのデザイン

時には、app: `Pyramid`デザインのさまざまな面での課題が提起されています。ここでの議論に文脈を与えるために、ここではいくつかの設計上の決定とトレードオフについて詳しく説明します。場合によっては、フレームワークが改善され、改善するための今後の手順について説明します。他の人たちは、気づいたとおりに挑戦します。明らかに、みんなをいつも楽しませることはできません。

ピラミッドは、それを行う方法の一つ以上を提供します

Pythonの普及した文化のキヤノンは、"TIOOWTDI "("それを行う唯一の方法があります"、Perlの"TIMTOWTDI "への少し舌の頬の参照、"それを行うには複数の方法があります」)。

:app: Pyramid`は、「TIMTOWTDI」システムです。たとえば、URLを:term: `view callable:via:term:` url dispatch`または:term: traversal`に解決する方法は複数あります。 :term: `必須設定、:term: コンフィギュレーションデコレーション、:term: ZCML`(オプション:term: pyramid_zcml`)。これは、複数の異なる種類のパーシスタンスおよびテンプレートシステムで動作します。等々。しかし、これらの重複する方法の大半は理由と目的がないわけではありません。私たちは多数の聴衆を抱えており、WebフレームワークレベルのTIMTOWTDIは実際にはもっと潜在的で危険なセットPython Webコミュニティの上位レベルで重複しています。

:app: Pyramid`は長年の人々のチームによって書かれたmod: repoze.bfg`のように人生を始めました。 「term: traversal`とterm: view lookup`の考え方はZopeから完全に盗まれました。 :app: `Pyramid`によって提供される承認サブシステムは、Zopeの派生物です。アプリケーションをフォークすることなく*拡張することができるという考えは、Zopeの派生物でもあります。

:app: `Pyramid`の作者が、彼らが慣れ親しんだやり方で、顧客のためにパンとバターのCMS型システムを構築できるようにするには、これらの機能の実装が必要でした。 Zope自身のために保存されている他のシステムは、そのような機能を持っていませんでした.Zope自体は、時代の兆しを見せ始めていました。私たちは、初期の設計ミスの結果によって妨げられていました。 Zopeの文書化の欠如もまた回避するのが難しかった。 Zopeアプリケーションで作業するために賢い人材を雇うことは難しかった。なぜなら、1つの消耗品の場所で"すべて"を説明する包括的な文書セットがなく、大きすぎて正しく文書化するために自己矛盾していたからです。 mod: `repoze.bfg`が開発される前は、著者たちは明らかに法案に適合する他のフレームワークについて検討しました。しかし、Zope以外のフレームワークはありませんでした。そこで我々はmod: `repoze.bfg`のビルドに着手しました。

しかし、私たちの研究の結果、* 1つの*フレームワークに必要な機能がすべて含まれていなかったにもかかわらず、既存のフレームワークは多く、優れたアイデアを持ち、時には非常に魅力的なアイデアを持っていたことが明らかになりました。特に、:term: `URL dispatch`はURLをコードにマッピングするためのより直接的なメカニズムです。

だから、私たちのニーズに合ったZopeを除いて、フレームワークを見つけることはできませんでしたが、ZopeのアイデアをBFGに取り込んでいる間に、他のフレームワークで魅力的だった機能も模倣しました。 url dispatch`)。 BFGの最初の一般公開後、時間がたつにつれて、システム内の様々なZope-ismsにアレルギーのある人々をサポートする機能が追加されました。たとえば、term: 必須の設定`と:term: :term: `ZCML`のみを使用するのではなく、:term: interface`オブジェクトの必要な使用を排除することです。すぐにわれわれは非常に汎用的なシステムを持っていて、Zope以外のユーザーや元のZopeユーザーにアピールするようになっていたことが明らかになりました。

この一般化の結果、BFGはPylons 1のフィーチャセットでそのフィーチャセットの90%を共有したことが明らかになり、ターゲット市場は非常に似ていました。彼らはとても似ていたので、2つのシステムの選択は、そうでなければ党派ではない開発者の不満の練習であった。また、PylonsとBFGの開発コミュニティが、2つのフレームワークがどれほど似ているかを考慮して、同じユーザーセットに対して競争することは奇妙でした。そこで、PylonsチームとBFGチームが協力して合併計画を立てました。 BFGには欠けている機能(特に、用語: `view handler`クラス、フラッシュメッセージング、その他のマイナーな欠落ビット)が追加され、Pylonsユーザーに親しみを与えました。結果はapp: `Pyramid`です。

PythonのWebフレームワークのスペースは、現在、有名なバルカン化されています。 app: `Pyramid`のコンポーネントが合併すれば、PylonsとBFGユーザーの少なくとも二つの現在非常に異なるユーザーにアピールすることを本当に望んでいます。 PylonsとBFGの最高のコンセプトを単一のコードベースに統合し、先祖からの悪いコンセプトを残しておくことで、無駄に競合することなく、より良い取り組みを強化し、より多くのコードを共有し、 。私たちは、競合他社と互換性のない特定の低レベルのスタック上に構築された、競合しているが信じられないほど類似しているアプリケーションやライブラリに代表される、*はるかに大きな*重複の努力をもたらすパック・メンタリティをショートカットすることを望んでいます。また、信頼できるPython Webフレームワークの選択を少なくとも1つ減らします。また、ZopeやTurboGearsのような他のコミュニティから必要な機能を提供することでユーザーを引きつけ、親しみやすい方法で柔軟に対応できるようにしたいと考えています。少なくとも、より高いレベルで無意味な複製を防ぐことを目指すならば、これらの目標を達成するための機能のオーバーラップが予想され、避けられません。私たちが十分に仕事をしていれば、さまざまな観客が、仮想WebフレームワークDMZのいくつかの間でお互いに発砲するのではなく、共存し協力することができます。

ピラミッドはZopeコンポーネントアーキテクチャ("ZCA ")レジストリを使用します

:app: Pyramid`は:term: Zope Component Architecture`(ZCA)"コンポーネントレジストリ"を:term: アプリケーションレジストリ`として使用します。これはいくつかの論争のポイントです。 :app: `Pyramid`は:term: Zope`系統であるため、開発者がZCAレジストリを使用するのは当然です。しかし、ZCAレジストリの使用には問題と結果があります。私たちができる限り最善の方法で対応しようとしています。ここでは、app:PyramidのZCAレジストリの使用と、その使用法のトレードオフについてのイントロスペクションです。

問題

ZCAコンポーネントレジストリ内のデータにアクセスするために使用される可能性のあるグローバルAPIは、あまり直感的ではありません。同様に、ZCAグローバルAPIを使用するコードの偶然のソースコードリーダーに対する概念的な負荷はいくぶん高いです。 :func: `zope.component.getUtility`グローバルAPIを使って典型的な"無名ユーティリティ"ルックアップを実行するコードを読んでいるZCA初心者を考えてみましょう:

1
2
3
from pyramid.interfaces import ISettings
from zope.component import getUtility
settings = getUtility(ISettings)

このコードが実行されると、 `` settings``はPython辞書になります。しかし、民間人はコードを読むだけでそれを知ることはまずありません。上記のコードには明らかな問題がいくつかあります。

まず、&quot;ユーティリティ&quot;とは何ですか?さて、この議論の目的のために、そして上記のコードの目的のために、あまり重要ではない。あなたが本当に知りたいのであれば、 `this <http://muthukadan.net/docs/zca.html#utility> `_。しかし、そのようなコードの読者は、それを解析するためには概念を理解する必要があります。これは問題番号1です。

次に、「ISETTINGS」のことは何ですか?それは:term: `interface`です。それはここで重要ですか?実際には、マーカーとしてのIDに基づいたルックアップのキーとして単に使用しています。これは辞書APIを持つオブジェクトを表しますが、これはあまり重要ではありません。それは2番の問題です。

第三に、 `` getUtility``関数は何をしますか?これは、 &quot;ISettings&quot; &quot;utility &quot;の検索を実行しています。これは、ユーティリティでもあります。この質問に答えるために:term: `interface`と&quot; utility &quot;という概念の理解に依存していることに注意してください。また、答えは循環的で、実際には*悪い兆候であることにも注意してください。

四番目に、 `` getUtility``はデータを取得するためにどこにありますか?まあ、&quot;コンポーネントレジストリ&quot;もちろん。コンポーネントレジストリとは何ですか?問題番号4。

第五に、あなたが購入したと仮定すると、いくつかの魔法のレジストリがぶら下がっています。 * Homina homina * ... &quot;around &quot;?これは、この文脈で最良の答えのようなものです(より具体的な答えは、内部の知識を必要とします)。複数のレジストリがありますか?はい。したがって、レジストリで登録が見つかりますか?まあ、もちろん&quot;現在の&quot;レジストリ。 app: `Pyramid`に関して、現在のレジストリはスレッドローカル変数です。ローカルのスレッドに問い合わせるAPIを使用すると、非ローカルで動作する方法を理解できます。

あなたは今、ちょうどぶらぶらしているレジストリがあるという事実を買いました。しかし、どのようにレジストリにデータが取り込まれますか?なぜ、 `` config.add_view``のような指令を呼び出すコードを介して。しかし、この特別なケースでは、 `` ISettings``の登録はフレームワーク自体によって行われます。これは、どのユーザ設定でも存在しません。これは非常に理解しにくいです。 6番の問題

Pythonプログラマーの熟練者であるにもかかわらず、ZCAの使用のために:app: `Pyramid`フレームワークを拡張したコードの読者が負担しなければならない認知負荷があることは明らかですWebアプリケーションのドメインこれは準最適です。

改善

最初に、:app: Pyramid *は、アプリケーション開発者がZCAの概念やそのAPIを理解することを期待していません。 * app:Pyramidアプリケーションの作成中に*アプリケーション*開発者がZCAの概念やAPIを理解する必要がある場合、いくつかの軸で失敗しました。

その代わりに、フレームワークは、ZCA APIを使用する専用API関数の背後にZCAレジストリの存在を隠します。たとえば、現在のリクエストに存在するuseridを返す `` pyramid.security.authenticated_userid``関数や、現在のリクエストにuseridが存在しない場合は `` None``を返します。アプリケーション開発者は次のように呼び出します。

1
2
from pyramid.security import authenticated_userid
userid = authenticated_userid(request)

彼らは現在、現在のユーザーIDを持っています。

しかし、そのフードの下では、 `` authenticated_userid``の実装はこれです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def authenticated_userid(request):
    """ Return the userid of the currently authenticated user or
    ``None`` if there is no authentication policy in effect or there
    is no currently authenticated user. """

    registry = request.registry # the ZCA component registry
    policy = registry.queryUtility(IAuthenticationPolicy)
    if policy is None:
        return None
    return policy.authenticated_userid(request)

このようなラッパーを使用して、我々はアプリケーション開発者からZCA APIを常に隠すように努めています。アプリケーション開発者はZCA APIについて知る必要はありません。彼らは引数としてドメインにいくつかのオブジェクトを混ぜたPython関数を呼び出す必要があり、結果を返さなければなりません。以下の結論は、app: `Pyramid`を使って書かれたアプリケーションの読者は、ZCA APIを理解する必要はないということです。

アプリケーション開発者やコードリーダーからZCA APIを隠すことは、ドメイン特化を強化する一形態です。アプリケーション開発者は、Webフレームワークがどのように機能するかについての細かく詳細なメカニズムを理解する必要はありません。人々は彼らが働いているドメインに近い概念を扱いたいと思っています。例えば、Web開発者は*ユーティリティ*ではなく*ユーザー*について知りたいと思っています。 :app: `Pyramid`は、エンドユーザに公開されている機能ではなく、実装の詳細としてZCAを使用します。

しかし、アプリケーション開発者とは異なり、トラバーサルやビュールックアップのようなあらかじめ定義されたフレームワークプラグインを使ってapp: `Pyramid`機能をオーバーライドしたい人を含め、*フレームワーク開発者*はZCAレジストリAPIを理解しなければなりません。

:app: Pyramid`フレームワークの開発者は、ZCAレジストリAPIの概念的な負荷の問題を心配していました。 <https://github.com/repoze/repoze.component> `_ named:mod: repoze.component`が実際に開発されました。このパッケージには完全に機能し、十分にテストされたレジストリ実装がありますが、そのAPIはZCAレジストリAPIよりもはるかに優れていますが、その作業はほとんど放棄されています:app: `Pyramid`では使用されていません。私たちは、最終的により良い適合が証明されたため、app: `Pyramid`内でZCAレジストリを使い続けました。

注釈

ZCAのレジストリを使用することは、インターフェイスのZCAの概念が多くのシナリオで有用なインターフェイス階層の使用を提供しているため、mod: `repoze.component &#39;でレジストリ実装を使用することに賛成ですコンテキストタイプの継承として)。この機能を可能にするインターフェイスのようなものだったマーカータイプが登場したのは、ホイールを再開発したようなものでした。

フレームワークの開発者とエクステンダーにZCAレジストリAPIを理解させることはトレードオフです。我々(the:app: `Pyramid`開発者)は、ZCAレジストリが私たちに与えてくれた機能を好きです。私たちは、これが何をし、どのように機能するのかを理解する重要性を昔から持っています。 app: `Pyramid`の著者は、ZCAを深く理解し、他のコードと同じように簡単に使用するコードを読むことができます。

しかし、我々は、フレームワークを拡張したいかもしれない開発者は、元の開発者と同じようにZCAレジストリAPIに慣れていないことを認識しています。ですから、第三者に親切であることを目的に、app: `Pyramid`フレームワーク開発者たちは、砂の中にいくつかの線を引いています。

すべてのコアコードでは、 &quot;zope.component.getUtility&quot;や &quot;zope.component.getAdapter&quot;などのZCAグローバルAPI関数を使用しました。これはルールの代わりに例外です。だから代わりに:

1
2
3
from pyramid.interfaces import IAuthenticationPolicy
from zope.component import getUtility
policy = getUtility(IAuthenticationPolicy)

:app: `Pyramid`コードは通常次のようになります:

1
2
3
4
from pyramid.interfaces import IAuthenticationPolicy
from pyramid.threadlocal import get_current_registry
registry = get_current_registry()
policy = registry.getUtility(IAuthenticationPolicy)

後者はより冗長ですが、それは間違いなく何が起こっているかをより明白にします。 :app: `Pyramid`コアコードは、ZCAのグローバルAPIではなく、このパターンを使用します。

根拠

ZCAレジストリを使用するapp: `Pyramid`の決定:

  • 歴史。この質問に対する答えの重要な部分は「歴史」です。 app: Pyramid`のデザインの多くは:term: Zope`から直接盗まれました。 Zopeは、ZCAレジストリを使用して多くのトリックを行います。 :app: Pyramid`はこれらのトリックを模倣しています.ZCAレジストリはそのトリックセットでうまくいくので、:app: Pyramid`は同じ目的でそれを使います。例えば:app: Pyramid`はa:term: request`をa:term: view callable`にマップします:term: traversal`はZopeからほぼ完全に取り除かれます。 ZCAレジストリは、マッピングを表示するこの要求がどのように行われているかという点で重要な役割を果たします。
  • 特徴。 ZCAコンポーネントレジストリは、基本的にスーパーディクショナリのようなものとみなされるものを提供します。これにより、単一のキーに基づいて値を取得するよりも複雑なルックアップが可能になります。このルックアップ機能の中には、コンテキストがオブジェクトのクラスである場合にのみ見られるビューを登録することや、コンテキストがいくつか:term: `interface`を実装している場合など、エンドユーザにとって非常に便利です。
  • 特異性。 &quot;アプリケーション構成&quot;がコンポーネントのレジストリにある:app: `Pyramid`アプリケーションに存在する場所は1つだけです。コンポーネントレジストリは、アプリケーション*の設定に基づいて、実行時にフレームワークによって作成された質問に答えます。注:&quot;アプリケーション&quot;は&quot;プロセス&quot;と同じではありません。同じ:app: `Pyramid`アプリケーションの複数の独立して設定されたコピーは、同じプロセス空間で実行することができます。
  • 合成性。 ZCAコンポーネントのレジストリには必須のものがあります。あるいは、設定ファイル(ZCML、オプション:term: `pyramid_zcml`パッケージを使用)を使用してレジストリを読み込むための既存のメカニズムがあります。私たちは設定ファイル駆動のレジストリの人口を利用するために、フロントエンドを最初から書く必要はありませんでした。
  • プラガブル性。 ZCAレジストリを使用することで、広く定義され広く理解されているプラ​​グインアーキテクチャによるフレームワーク拡張が可能になります。フレームワークの開発者とエクステンダーがZCAレジストリを理解している限り、app: `Pyramid`をほぼ任意に拡張することができます。たとえば、複数のビューを一度に登録するディレクティブを作成するのは比較的簡単で、アプリケーション開発者はそのディレクティブを、自分が記述し​​たコードで&quot;マクロ&quot;として使うことができます。これは、他の(Zope以外の)フレームワークとは多少異なる点です。
  • テスト容易性。フレームワークコードでZCAレジストリを慎重に使用することで、コードを少し簡単にテストできます。テストのためにモックオブジェクトを登録するためにMonkeypatchingや他の機能を使用する代わりに、ZCA登録を介して依存関係を注入し、モックオブジェクトを見つけるためにコード内のルックアップを使用します。
  • 速度。 ZCAレジストリは、app: `Pyramid`が使用する複合ルックアップシナリオの特定のセットに対して非常に高速です。これらの目的のために何年もの間最適化されています。 ZCAレジストリには、この目的のためのオプションのCコードが含まれています。このコードでは、明らかにバグはありません(またはごくわずかです)。
  • 生態系。多くの既存のZopeパッケージは、ZCAレジストリを使用しているため、app: `Pyramid`でほとんど変更を加えずに使用できます。

結論

:app: Pyramid`を使って*アプリケーションを開発するだけの場合は、ここで不平を言うことはあまりありません。 ZCAレジストリAPIを理解する必要はありません。 documented:app: `Pyramid APIを代わりに使用してください。しかし、APIのドキュメントを読まないアプリケーション開発者がいるかもしれません。代わりに未加工のソースコードを読んだり、APIドキュメントを読まなかったので、関数、クラス、メソッドが*:* form:the:app: Pyramid APIであっても分かりません。その結果、内部を使用するコードを作成し、概念のコーナーに自分自身を描き、実装の詳細を使用したZCAに取り組む必要がありました。これがあなたなら、あなたのために多くの同情を持つことは非常に難しいです。 ZCAレジストリをどのように使用しているかに精通している必要があるか、またはドキュメント化されたAPIのみを使用する必要があります。そのため、APIとして文書化しています。

:ref: hooks_chapter`で説明されているように、より曖昧なフックのいくつかを使用するか、:app: Pyramid`コアコードで作業します)あなたは、少なくともいくつかのZCAの概念を理解する必要があることに直面するでしょう。いくつかの場所でそれは恥ずかしがりに使用され、永遠になります。奇妙なことはわかっていますが、それについての読書をする時間があれば、それは有用で基本的に理解できます。

Pyramid &quot;ZCMLの使用を奨励

:term: ZCML`は:term: Zope Component Architecture`レジストリを設定するために使用できる設定言語です:app: `Pyramid`がアプリケーション設定に使用します。ピラミッドには &quot;ZCMLが必要&quot;と主張する人が多いです。

それはしません。 In:app: Pyramid 1.0、ZCMLはコアの一部としては出荷されません。代わりに:term: `pyramid_zcml`アドオンパッケージに含まれています。これは完全にオプションです。 app: `Pyramid`やその他のフレームワークの宣言的なフロントエンドからアプリケーションを構成するために、ZCMLは必要ありません。

ピラミッドはトラバーサルを行い、トラバースを好まない

In:app: Pyramid、:term:` traversal`は、リソースツリーの:term: `resource`オブジェクトへのURLパスを解決する行為です。一部の人々はこの概念に不快であり、間違っていると信じています。ありがたいことに:app: `Pyramid`を使用していて、リソースツリーの観点からアプリケーションをモデル化したくない場合は、まったく使用する必要はありません。代わりに:term: `URL dispatch`を使用して、URLパスをビューにマップします。

一部の人々がトラバーサルが一方的に間違っていると考える考えは理解できる。間違っていると信じている人々は、ほとんどすべてのデータをリレーショナルデータベースに入れています。リレーショナルデータベースは当然階層的ではないので、ツリーのようなものを横断することはできません。

しかし、トラバーサルを一方的に間違っているとみなす人々は、多くのパーシステンスメカニズム*が階層的であることを考慮に入れていません。例には、ファイルシステム、LDAPデータベース、:term: `ZODB`(または他のタイプのグラフ)データベース、XMLドキュメント、Pythonモジュールの名前空間などがあります。フロントエンドを階層的なデータストアにモデル化してグラフとしてモデル化すると便利です。トラバーサルを使用して、ツリー内のリソース(たとえばZODBの場合)や、 (ファイルシステムからのファイルのためのラッパーの場合のように)それらのために立ち入ってください。

また、多くのウェブサイト構造は、それらを駆動するデータがそうでなくても、自然に階層的です。例えば、新聞のウェブサイトは、しばしば非常に階層的である:セクション内のセクション内のセクション、無限にある。 URLがこの構造を示し、構造が不定である場合(ネストされたセクションの数は固定数ではなく&quot;N &quot;となります)、リソースツリーはバックエンドリレーショナルデータベースです。この状況では、リソースツリーは単なるサイト構造に過ぎません。

トラバーサルは、URLマッチングの固定された順序付けに依存しないため、URLディスパッチよりもアプリケーションの合成性が優れています。 URLパターンマッチングの正しい順序付けをしようとするよりも、予想以上にリソースへのビューのマッピングを中心に、異種の機能を組み立てることができます(後で追加します)。

しかし、そのポイントは最終的には間違いです。トラバースを使用したくない場合は、そうする必要はありません。代わりにURLディスパッチを使用してください。

ピラミッドはURLディスパッチを行いますが、私はURLディスパッチが嫌いです

in:app: Pyramid、:term:` url dispatch`は、URLパスを:term: `view`に解決する行為です。ルート定義は順番に調べられます。一致する最初のパターンは、URLをビュー呼び出し可能に関連付けるために使用されます。

一部の人々はこの概念に不快であり、間違っていると信じています。これらは通常、「Zope」という言葉に深く浸透している人々です。 Zopeは、term:コードをURLにマップする traversal`以外のメカニズムを提供していません。これは主に、Zopeが階層オブジェクトストアである:term: `ZODB`の使用を事実上必要とするためです。 Zopeはリレーショナルデータベースもサポートしていますが、通常、データベースに呼び出されるコードはZODBオブジェクトグラフのどこかに存在します(少なくとも、オブジェクトグラフのノードに関連する:term: `view)、到達するためにはトラバーサルが必要ですこのコード。

私は、たとえあなたがトラバーサルを使用したいとしても、URLディスパッチが最終的には有用であると主張します。実際には、app: Pyramid`(参照:ref: hybrid_chapter`)に* URLディスパッチとトラバースを組み合わせることができます。そのような使い方の一例:オブジェクトグラフ(または任意の管理インターフェース)の上にZope 2の&quot;Zope Management Interface &quot; UIのようなものをエミュレートしたい場合は、 `` config.add_route( &#39; `` manage`、 `` / manage / * traverse &#39;``) `` `` view``の設定に `` route_name``引数を使ってコード内の&quot;管理&quot;ビューを関連づけます。例えば `` config.add_view ( &#39;.some.callable&#39;、context = &quot;。some.Resource &quot;、route_name = &#39;manage&#39;) ``です。このように物事を結ぶと、誰かが `` / manage / ob1 / ob2` &#39;のように歩いていくと、管理インターフェースが表示されるかもしれませんが、 `` / ob1 / ob2``まで歩いていくとデフォルトのオブジェクトビューを表示します。あなたが賢い(そして恐らくmasochisticな)場合でも、これらのハイブリッド構成で引き出すことができる他のトリックがあります。

また、URLディスパッチ機能を備えている場合、従来のリレーショナルデータベース構造を使用する必要があるアプリケーションを作成する必要がある場合は、URLディスパッチを使用すると、ビューとURLパスの間の1回限りの関連付けが便利になることがあります。場合によっては、オブジェクトグラフにノードを追加するだけで、コードの一部のエントリポイントを効果的に表現することができます。あなたは単にルートを使用して、それを使って完了することができます。ルートが一致すると、そのルートに関連付けられたビューが呼び出されます。一致するルートがない場合、:app: `Pyramid`はトラバーサルを使用します。

しかし、そのポイントは最終的には間違いです。 :app: Pyramid`を使用していて、本当にURLディスパッチを使用したくない場合は、まったく使用する必要はありません。代わりに:term: `traversal`を使用して:term: Zope`のようにURLパスをビューにマップするだけです。

ピラミッドビューは任意のキーワード引数を受け入れない

多くのWebフレームワーク(Zope、TurboGears、Pylons 1.X、Django)は:term: view callable`のバリエーションが任意のキーワードや位置引数を受け入れることを許します。これらの引数は request.POST `、 `` request.GET``、またはルートマッチ辞書を使用します。例えば、Djangoのビューは `` rl ^ polls /(?P)のような関連する &quot;urlconf&quot;内の情報と一致する位置引数を受け取ります。 <poll_id> d +)/ $ ``

1
2
def aview(request, poll_id):
    return HttpResponse(poll_id)

Zopeは同様に、トラバーサルによって見つかったリソースオブジェクトのメソッドに任意のキーワードと位置引数を追加することができます:

1
2
3
4
5
from persistent import Persistent

class MyZopeObject(Persistent):
     def aview(self, a, b, c=None):
         return '%s %s %c' % (a, b, c)

公開された呼び出し可能オブジェクトの結果としてこのメ​​ソッドが呼び出されると、要求内の位置引数とキーワード引数の名前と一致するキーがZope要求オブジェクトのGETとPOSTの名前空間で検索され、メソッドは(可能であれば)呼び出されます引数リストには、そこに記載されている値が入っています。 TurboGearsとPylons 1.Xも同様に動作します。

すぐに:app: Pyramid`はこれらの機能を持たないように設定されています。デフォルトでは、app: `Pyramid`ビューのcallablesは常に `request``だけを受け取り、他の引数は受け付けません。その根拠は、積極的に行われた場合、この引数指定はコストがかかる可能性があり、app: `Pyramid`はその主要な目的の1つとしてパフォーマンスを持ちます。したがって、デフォルトでは、view引数リストに展開するための魔法を提供するのではなく、ビューの呼び出し可能な本体内のリクエストオブジェクトを調べることで情報を取得することにしました。

しかし、:app: Pyramid 1.0a9のように、ユーザコードは、ビュー呼び出し可能関数が呼び出されると予想される方法に影響を与え、任意の引数で呼び出される呼び出し外のシステムを構成することができます。参照:ref: `using_a_view_mapper`を参照してください。

Pyramidはあまりにも少ない &quot;Rails

設計上、:app: `Pyramid`は、特に有名なWebフレームワークではありません。これは、比較的簡潔な機能セットを持っています。 ORMや特定のデータベースバインディングは組み込まれていません。フォーム生成フレームワークは含まれていません。管理Webユーザーインターフェイスはありません。テキスト索引作成機能は組み込まれていません。コードの整理方法は決まっていません。

このような批判的な機能は、app: `Pyramid`の上に*作られたアプリケーションとフレームワークに存在します。上位のシステムは、:app: `Pyramid`をベースに構築されています。

参考

参照:ref: `apps_are_extensible`も参照してください。

Pyramidは多すぎる&quot;Rails

:app: `Pyramid`は、他のWebフレームワークが提供していない機能を提供します。これらは、単純な注文Webアプリケーションを構築している場合には意味をなさない可能性のあるユースケース向けの機能です。

  • term: traversal`を使ってURLをコードにマップするオプションの方法です。これはa:term: `resource tree`の散歩を意味します。
  • :meth: `pyramid.config.Configurator.include`を使用して複数のソースからPyramidアプリケーション設定を集める機能。
  • クラスオブジェクトの代わりに:term: interface`オブジェクトを使用して作成されたビューとサブスクライバ登録(例::ref: use_resource_interfaces`)
  • 宣言的な:term: `authorization`システムです。
  • 複数の独立したI18N:term: `translation string`ファクトリ。それぞれが独自のドメインを指定できます。

これらの機能は、app: Pyramid`の作成者にとって重要です。 :app: `Pyramid`の著者は、しばしばCMSスタイルのアプリケーションを構築するよう依頼されます。そのようなアプリケーションは、複数のデプロイメントを持つため、しばしば枠組み的です。各デプロイメントでは、サブアプリケーションの構成が若干異なりますが、フレームワークとサブアプリケーションはしばしば拡張可能である必要があります*。アプリケーションには複数のデプロイメントが存在するため、アプリケーションごとに1つずつ複数のフォークを維持することは非常に望ましくないため、プラグインと拡張性は重要です。 :term: `traversal`を使用するシステムを、term: URL dispatch`を使用するシステムで同じことをするよりも簡単に拡張できるので、各デプロイメントは:term: resource tree`を使用しますドメインモデルオブジェクトの永続的なツリーのうちの1つを使用し、term: `traversal`を使用してツリー内のリソースにmap:term: call callable`コードをマッピングします。リソースツリーには、リソースがさまざまなユーザーセットによって所有され、アクセス可能なため、非常にきめ細かなセキュリティ宣言が含まれています。インタフェースはユニットテストと実装の代用性を容易にするために使用されます。

カスタムWebアプリケーションでは、通常、単一の標準的なデプロイメントが存在するため、複数のコードフォークの可能性はありません。拡張性は必要ありません。コードはちょうどその場所で変更されます。セキュリティ要件は、しばしばそれほど細かくはありません。上記の機能を使用すると、そのようなアプリケーションでは過度の負荷となることがよくあります。

これらの機能が気に入らなければ、app: `Pyramid`を使うことはできません。彼らはすべてオプションで、多くの時間があなたの前で彼らについて知る必要がないことを確認するのに費やされてきました。上記の機能を無視することによって純粋に別注されている:app: `Pyramid`を使って&quot; Pylons 1.X style &quot;アプリケーションをビルドすることができます。これらの機能は、後で普及し、複数の場所に展開する必要があるため、拡張性が必要な別注のWebアプリケーションを作成した後に便利です。

ピラミッドが大きすぎます

&quot;The:app:` Pyramid`圧縮されたtarballは2MB以上です。

いいえ、ドキュメント、テストコード、スキャフォールディングで出荷します。パッケージツリーのサブディレクトリに含まれるものの内訳を次に示します。

docs /

3.6MB

ピラミッド/テスト/

1.3MB

ピラミッド/足場/

133KB

ピラミッド/(「ピラミッド/テスト」と「ピラミッド/スキャフォールド」を除く)

812KB

パッケージ内の約34K行のPythonコードのうち、テストやPythonファイルの足場を除いて、通常の動作中に実際に実行する可能性のあるコードは、約10K行を占めます。

ピラミッドに依存性が多すぎる

時間の経過とともに、ピラミッドが持っていたパッケージ依存性の数を減らすことについて、多くの進歩を遂げました。ピラミッド1.2には15種類ありました。ピラミッド1.3と1.4には12個のピラミッドがありました。この執筆時点での現在のリリース、Pyramid 1.5にはわずか7しかありません。この数字はそれほど小さくなる可能性は低いです。

Pyramid 1.3で完成したPython 3への移植は、より良いパッケージングの決定を下すことによって、多くの依存関係を解消するのに役立ちました。 1.5のPyramidコアにおけるChameleonとMakoのテンプレートシステムの依存関係を削除することで、残りの部分の大半が解放されました。

Pyramid &quot;Cheats &quot;で速度を得る

苦情はさまざまな時に他のWebフレームワークの著者によって提出されました:app: Pyramid &quot; cheats &quot;がパフォーマンスを得る1つの主張されている不正行為のメカニズムは、mod: `zope.interface`によって提供されるCの拡張機能を(高速で)使用する(推移的に)ものです。別の主張されている不正行為のメカニズムは、無関係の機能呼び出しの宗教的回避です。

より良いパフォーマンスを得るために不正行為があるようなことがあれば、私たちは可能な限りチートしたい。我々は:app: `Pyramid`を積極的に最適化します。これはコストがかかります。コアコードには、読みやすくするためのセクションがあります。改善として、我々はこれらのセクションを自由にコメントした。

ピラミッドの用語が間違っている(&quot;MVC &quot;)

&quot;私はMVCのWebフレームワークのユーザーで、混乱しています:app:` Pyramid`はコントローラをビューと呼びます!コントローラはありません。

このキャンプにいるなら、既存のMVCフレームワークがその用語をどのように使用しているかを期待するかもしれません。たとえば、モデルはORMモデルであり、コントローラはURLにマップするメソッドを持つクラスであり、ビューはテンプレートです。 :app: `Pyramid`にはこれらの概念があり、既存のMVCフレームワークとほぼ同じように機能します。私たちはMVC用語を使用しません。ウェブフレームワークでの使用を歴史的な現実に合わせることができないからです。

人々は、似たような用語を使用してWebアプリケーションに共通のデスクトップGUIプラットフォームと同じプロパティを与え、共通のWebフレームワーク内のさまざまなコンポーネントがどういった方法でハングアップしているかを示すフレームを提供したいと思っています。しかし、作者の意見では、&quot;MVC はウェブとよくよくマッチしません。モデルビューコントローラーWikipediaのエントリー<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller> `_:

MVCはさまざまな種類がありますが、制御フローは一般的に次のとおりです。

ユーザーは何らかの方法でユーザーインターフェイスとやり取りします(たとえば、マウスボタンを押します)。

コントローラは、多くの場合、登録されたハンドラまたはコールバックを介してユーザインタフェースからの入力イベントを処理し、そのイベントを適切なユーザアクションに変換します。

コントローラは、モデルにユーザアクションを通知します。その結果、モデルの状態が変更される可能性があります。 (たとえば、コントローラがユーザのショッピングカートを更新する)[5]

ビューは、適切なユーザーインターフェイスを生成するためにモデルをクエリします(たとえば、ビューにはショッピングカートのコンテンツが一覧表示されます)。ビューはモデルから独自のデータを取得することに注意してください。

コントローラは、(いくつかの実装では)それ自体をレンダリングするための一般的な命令をビューに発行することができる。他のものでは、画面の更新を必要とする状態の変化のモデル(Observer)によって自動的に通知が通知されます。

ユーザーインターフェイスは、さらにユーザーの操作を待って、サイクルを再開します。

作者にとっては、このウィキペディアの定義を編集した人が、現在のWebフレームワークで「MVC」という用語の使用を説明するために可能な最も一般的な用語でコンセプトを酷使しているかのように思えます。このような幅広い定義が、MVCパターンの原作者がこれまでに同意するとは思っていません。しかし、* MVCのWebフレームワークのほとんどは、この誤ったジェネリック定義でさえも満たされていないようです。

たとえば、テンプレート(ビュー)は、「ビューがモデルから独自のデータを取得することに注意してください」と主張されているように、モデルを直接クエリしますか?おそらくそうではありません。私の &quot;制御部&quot;はこれを行う傾向があり、データを &quot;ビュー&quot;(テンプレート)で使いやすくするためにマッサージします。 &quot;コントローラ&quot;がJSONを返すときはどうしますか?あなたのコントローラはJSONを生成するためにテンプレートを使用していますか?もしそうでなければ、&quot;view &quot;は何ですか?ほとんどのMVCスタイルのGUI Webフレームワークには、モデルの変更時にビューが検出できるようにする何らかの種類のイベントシステムがあります。ウェブには、そのような機能は現在の形ではありません。効果的にプルのみです。

したがって、現実と欲望を誤解しないようにするために、「MVC」の丸穴にウェブであるスクエアペグを詰め込もうとするのではなく、リソースと見解という2つのことがあります。リソースツリーはサイト構造を表し、ビューはリソースを表します。テンプレートは実際には任意のビューの実装の詳細です。ビューは応答を返すためのテンプレートを必要としません。 &quot;コントローラ&quot;はありません。それだけでは存在しません。 &quot;model &quot;は、リソースツリーまたは( &quot;SQLAlchemy&quot;モデルのように)フレームワークとは別の&quot;ドメインモデル&quot;によって表現されます。これはウェブの現在の制約を考えると、より合理的な用語が好きなようです。

ピラミッドアプリケーションは拡張可能です。私はアプリケーションの拡張性を信じていない

Any:app: Pyramid`アプリケーションは特定の制約に従って書かれています*拡張可能です*。この機能については、:app: `Pyramid`のドキュメンテーションのchapter:ref: extend_chapter`と:ref: advconfig_narr`で説明します。 app: `Pyramid`の中で、:term: Zope Component Architecture`を使うことで可能になりました。

この文脈では、「拡張可能」とは、

  • デプロイヤーが元のアプリケーションのソースを変更することなく、アプリケーションの動作をアプリケーションの特定のデプロイメント*でオーバーライドまたは拡張することができます。
  • 元の開発者は、基本的なアプリケーションの動作を上書きまたは拡張できるように、アプリケーション作成時に拡張プラグインポイントを予測する必要はありません。
  • 元の開発者は、アプリケーション固有のプラグポイントのセットを予期することを任意に選択することができます。プラグポイントは、デプロイヤによってフックされることがあります。 ZCAが提供する機能を使用することを選択した場合、元の開発者は、このようなプラグポイントを導入する仕組みについて深刻に考える必要はありません。

多くの開発者は、拡張可能なアプリケーションを作成する価値がないと信じているようです。代わりに、それぞれの展開で特定のアプリケーションのソースを変更して、動作を上書きする方がより合理的であることを示唆しています。バージョン管理の分岐とマージに関する多くの議論が一般的に続いています。

すべてのアプリケーションを拡張可能にする必要はないことは明らかです。 Webアプリケーションの大部分は単一の配備しか持たないため、拡張する必要は全くありません。しかし、いくつかのWebアプリケーションには複数のデプロイメントがあり、他のものには*多くのデプロイメントがあります。例えば、一般的なコンテンツ管理システム(CMS)は、特定の展開のために拡張される必要がある基本機能を有することができる。そのCMSは、多くの組織で多くの場所に展開できます。このCMSのいくつかの展開は、サードパーティによって集中的に展開され、グループとして管理されます。システムの各ソフトウェアブランチを上流のソースと同期させ続けるよりも、あらかじめ定義されたプラグポイントを使用して、展開ごとにそのようなシステムを拡張する方が簡単です。上流の開発者は、同じコードベースへの変更が邪魔にならないようにコードを変更する可能性があります。このような変更を展開のライフサイクル全体にわたって繰り返していることは困難で時間がかかることがありますが、侵入の少ない方法で特定の展開のアプリケーションを変更できるようにすることはしばしば役に立ちます。

app: `Pyramid`アプリケーションの拡張性について全く考えたくなければ、あなたはそうする必要はありません。あなたは完全に拡張性を無視することができます。しかし、:ref: `extends_chapter`で定義された一連の規則に従えば、アプリケーションを拡張可能にする必要はありません。 あなたがフレームワークで書くアプリケーションは、基本レベルで自動的に拡張可能です。デプロイヤーがそれを拡張するために使用するメカニズムは必然的に粗いでしょう。通常、ビュー、ルート、およびリソースはオーバーライドすることができます。しかし、ほとんどのマイナーな(そしていくつかの主要な)カスタマイズでは、必要なオーバーライドプラグポイントが必要な場合があります。アプリケーションがデプロイメントが必要とするものを正確に実行できない場合は、デプロイヤーがビュー、ルート、またはリソースをオーバーライドして、元の開発者が必ずしも予期しない方法ですばやく実行できるようにすることがよくあります*。このような機能の利点を示すいくつかのシナリオの例を以下に示します。

  • デプロイメントに異なるスタイルが必要な場合、デプロイヤーはメインテンプレートとCSSを、オーバーライドを定義する別のPythonパッケージでオーバーライドすることができます。
  • デプロイメントが何か別のことをするためにアプリケーションページを必要とする場合や、より多くの情報や異なる情報を公開する必要がある場合、デプロイヤーはページを別のPythonパッケージにレンダリングするビューをオーバーライドする可能性があります。
  • デプロイメントに追加機能が必要な場合、デプロイヤーはオーバーライドパッケージにビューを追加できます。

上流パッケージの基本設計が変更されない限り、これらのタイプの変更は、上流パッケージの多くのリリースにわたって再訪する必要なくしばしば生き残ります。

アプリケーションを外部に拡張することは万能薬ではなく、分岐やマージに似た一連のリスクを伴います。アップストリームの大きな変更により、いくつかの変更を再訪して更新することがあります。しかし、アプリケーションを外部に拡張すると、テキストマージが行われないため、アップストリームパッケージを更新するときに、しばしばアップストリームパッケージの些細な変更が伴う無意味なテキストマージの競合に対処する必要はありません。あなたの修正は、それが価値があるものであっても、正式な、明確に定義された1つの場所に含まれます。

新しい機能やバグ修正を得るために、アプリケーションを分岐して継続的にマージすることは、明らかに便利です。 :app: `Pyramid`アプリケーションを使って、アプリケーションと同じように便利に行うことができます。しかし、app:Pyramidで書かれたアプリケーションをデプロイすると、アプリケーションが先にプラグポイントを定義しなくても、この必要性を避けることができます。競合するWebフレームワークのプロモーターは、選択したフレームワークで書かれたアプリケーションが比較的基本的な方法で拡張できないため、ブランチングやマージのためにこの機能を却下する可能性があります。

while:app: Pyramid`アプリケーションは、あなたが特定の拡張性を念頭に置いていなくても基本的に拡張可能ですが、あなたが中程度の冒険をしているならば、さらに進歩を遂げることができます。 :term: `Zope Component Architecture`についてもっと学ぶならば、オプションでそれを使って、アプリケーション開発中に他のドメイン固有の設定プラグポイントを公開することができます。公開するプラグポイントは、app: `Pyramid`自身によって自動的に提供されるプラグポイントほど粗くする必要はありません。例えば、事前に焼いた目的(例えば ` restview``など)のために一連のビューを設定する独自の指示文を作成し、 `` includeme &#39;&#39;で宣言するときに他の人がその指示文を参照できるようにすることができます``のカスタマイズパッケージに含まれています。これにはコストがかかります。デプロイヤのカスタムプラグポイントを定義するアプリケーションの開発者は、ZCAを理解する必要があります。あるいは、独自の同様の拡張性システムを開発する必要があります。

最終的に、app: `Pyramid`によってアプリケーションに貸し出される拡張性機能が良いか悪いかについての議論は、ほとんど無意味です。特定の:app: `Pyramid`アプリケーションが提供する拡張機能を利用する必要はありません。特定の配備セットの変更に影響を与えるためです。アプリケーションの拡張性のプラグポイントを完全に無視し、他のWebフレームワークを使用して作成されたアプリケーションを展開する場合と同様に、バージョンコントロールの分岐とマージを使用してアプリケーションの展開の変更を管理できます。

Zope 3は&quot;TTW &quot;認証チェックをデフォルトで強制します。ピラミッドはしません

チャレンジ

:app: Pyramid`はterm: view`の実行時間でのみ自動権限チェックを行います。 Zope 3はコンテキストオブジェクトをセキュリティプロキシで囲みます。これにより、Zope 3は属性アクセス中にセキュリティチェックを行います。私はこれが好きなのです。

  1. セキュリティプロキシマシンを使用すると、特定のHTML要素(フォームフィールドなど)を条件付きで表示するビューを持つことができます。また、アクセスするユーザーがコンテキストオブジェクトに対して所有するアクセス許可に応じて特定の属性が変更されないようにできます。
  2. また、Twisted Webを使用してREST APIを介してリソースを公開したいと考えています。 PyramidがZope3のセキュリティプロキシを介して属性アクセスに基づいて権限を実行した場合、私はapp:PyramidとTwistedベースのシステムの両方で認証ポリシーを適用することができます。

防衛

:app: `Pyramid`はZope 2に慣れ親しんでいる人たちが開発しました.Zope 2には、Web経由のセキュリティモデルがあります。このTTWセキュリティモデルは、Zope 3のセキュリティプロキシの前身でした。時間の経過とともに、:app: `Pyramid`開発者(Zope 2で働いている)がこのようなサイトを作ったので、コード解釈中の権限チェックが少数のプロジェクトで非常に有用であることがわかりました。しかし、多くの場合、TTW認可チェックは通常、委任要件がないプロジェクトの開発速度を遅くしました。特に、信頼できないユーザーがアプリケーションで実行される任意のPythonコードを書くことを許可していない場合、Webセキュリティチェックによる負担はあまりにもコストがかかり、正当化することができませんでした。私たちは(総称して)信頼できない開発者が長年に渡ってコードを書くことを許可されたアプリケーションを作成していないので、このモデルをデフォルトで新しいWebフレームワークにドロップするのが理にかなっていたようです。

また、すべてのWebアプリケーションに同じツールキットを使用する傾向があるため、2つの異なるWebフレームワークで同一の制限付き実行コードセットを使用できるようになることは決して懸念されていません。

Zope 3のセキュリティー・プロキシがウイルス性であることを考慮すると、デフォルトでセキュリティー・プロキシーを無効にすることの妥当性については、セキュリティー・プロキシー内に単一のオブジェクトをラップして、プロキシのセキュリティチェックが行われます。特定のアプリケーションの:app: Pyramid`トラバーサをオーバーライドすることができます(ref: changing_the_traverser`を参照)。 Zope3のような振る舞いをするには、トラバーサルされた各オブジェクト(:term: context`と:term: root`を含む)に対してZope3-security-proxy-wrappedオブジェクトを返す別のトラバーサーを接続することができます。これは、Zope3のような環境を多くの努力なしに作り出す効果があります。

Pyramidは、mod: `webob.exc`ではなく、独自のHTTP例外クラス階層を使用します。

バージョン 1.1 で追加.

:mod: pyramid.httpexceptions`で定義されているHTTP例外クラスは:mod: webob.exc`で定義されたものと非常によく似ています(例::class: 〜pyramid.httpexceptions.HTTPNotFound`または:class: 〜pyramid.httpexceptions.HTTPForbidden`)。それらは同じ名前でほぼ同じ動作をしており、すべて同じような実装ですが、同一のアイデンティティではありません。ここに彼らは別のアイデンティティを持っている理由です。

  • それらを別々にすることで、HTTP例外クラスがclass: `pyramid.response.Response`のサブクラス化を行うことができます。これは、ピラミッドルータの仕組みのせいで、応答の生成をわずかに高速化します。 monkeypatching:class: `webob.response.Response`でも同じスピードアップが得られるかもしれませんが、通常は、monkeypatchingが悪いと間違っていることが判明します。
  • それらを別々にすることで、代替の `` __call__``ロジックを提供することができます。これによりレスポンスの生成も高速化されます。
  • それらを分離することで、例外クラスは `` RequestClass``(:class: pyramid.request.Request)の適切な値を提供することができます。
  • それらを別々にすると、Pyramid 1.1以降ではサポートしていないPython 2.4に関連するmod: `webob.exc`という下位互換性コードについて考えることができなくなりました。
  • モジュール内の2つのクラス(:class: 〜pyramid.httpexceptions.HTTPNotFound`と:class:〜pyramid.httpexceptions.HTTPForbidden`)を `` notfound``のために内部的にPyramidで使用できるように変更します「禁じられた」例外を含む。
  • それらを別々にすることで、Pyramid固有のドキュメントを提供するために例外クラスのドキュメントストリングに影響を与えることができます。
  • それらを別々にすることで、応答オブジェクトが( `` self.message``に関連して)例外として使われるとき、Python 2.6の下で愚かな非推奨警告を静かにすることができます。

ピラミッドはZopeよりも単純なトラバーサル機構を持っています

Zopeのデフォルトトラバース:

  • 開発者がトラバース中にトラバーサル名のスタックを変更することを許可します(パス要素の追加と削除が可能です)。
  • 現在トラバースされているオブジェクトからパス内の次の要素を取得し、 `` __bobo_traverse__``、 `` __getitem__``、そして最終的に `` __getattr__``にフォールバックするためにアダプテーションを使用しようとします。

Zopeのデフォルトのトラバーサでは、開発者は &#39;REQUEST [&#39;TraversalNameStack&#39;] を変更することによって、トラバース中にトラバース名のスタックを変更することができます。 Pyramidのデフォルトのトラバーサ( ` pyramid.traversal.ResourceTreeTraverser``)はこれを行う方法を提供していません。要求属性としてスタックを保持せず、それが実行されても、移動中のリソースオブジェクトに要求を渡しません。この機能は時に便利でしたが、Zope(CMFやPloneのような)の上に構築されたフレームワークでは悪用され、しばしばトラバーサルがビューに一致しなかったときに何が起こったのかを正確に伝えることが難しくなりました。私はそれがデフォルトトラバーサーに特定の蜂蜜の鍋を構築するよりもむしろtraverserを置き換えるように機能を望んでいる人々の方が良いと感じました。

Zopeは、複数のメカニズムを使用して、名前に基づいてリソースツリー内の次の要素を取得しようとします。現在のリソースを `` ITraversable``に適合させようと試みます。失敗した場合は、リソース( `` __bobo_traverse__``、 `` __getitem__``、 `` __getattr__``)。 Zopeを使って、 `` repoze.zope2``で出版社を再実装しようとしている私の経験は、私が次のように信じてくれました。

  • *デフォルトのトラバーサーはできるだけシンプルでなければなりません。 Zopeのパブリッシャーは、1つのトラバーサルメソッドが失敗したときに試みたフォールバックのために、追跡して複製することは多少困難です。それはまた遅いです。
  • トラバーサルマシンの要素だけでなく、トラバーサ全体*も置き換え可能でなければなりません。ピラミッドには小さなものがたくさんあるのではなく、いくつかの大きな要素があります。トラバーサ全体が交換可能な場合は、デフォルトのトラバーサの一部を交換可能にする反パターンです。そうすることは&quot;ノブのつまみ&quot;パターンであり、残念なことにZopeでは風土病です。ノブのノブのパターンでは、大きなコンポーネントの交換可能なサブコンポーネントは、大きなコンポーネントを置き換えるのに使用できるのと同じ構成メカニズムを使用して構成可能になります。たとえば、Zopeでは、アダプターを登録することによってデフォルトのトラバーサーを置き換えることができます。しかし、1つまたは複数のアダプタを登録することによって、デフォルトのトラバーサがどのようにトラバースするかを制御することもできます(または代わりに)。より大きなコンポーネントを完全に置き換えたり、大きなコンポーネントのデフォルトの実装でノブを回すことができた結果、大きなコンポーネントをいつでも上書きする必要があるかどうかは誰も理解できません。これは時間が経つにつれて、より大きな「交換可能な」コンポーネントとフレームワーク自体の錆びた状態になります。なぜなら、人々はノブを回すだけでデフォルトコンポーネントの可用性に依存するからです。デフォルトのコンポーネントは事実上フレームワークの一部になり、フレームワークは交換可能にするという目標を完全に打ち消します。ピラミッドでは、通常、コンポーネントが置換可能な場合、それ自体にはノブはありません(ソリッドステートになります)。そのコンポーネントによって制御される振る舞いに影響を与えたい場合は、そのコンポーネントに接続されたノブを回すのではなく、そのコンポーネントを置き換えます。

マイクロフレームワークでは、より小さなHello Worldプログラム

自己記述された&quot;microframeworks &quot;が存在する。 ボトル<http://bottlepy.org/docs/dev/index.html> `_と Flask <http://flask.pocoo.org/> `_は人気が高まっている2つです。ボボ<https://bobo.readthedocs.io/en/latest/> `_はマイクロフレームワークとは言いませんが、その意図するユーザー基盤はほとんど同じです。他にも多くのものが存在する。我々は(公式のプロジェクトのようなものではなく、教えのツールとしてのみであっても) `Pyramid <http://static.repoze.org/casts/videotags.html> `_。このビデオはPyramidの前身であるBFGを使用していますが、結果のコードはPyramidでも利用可能です<https://github.com/Pylons/groundhog> `_)。 Microframeworksは小さなフレームワークで、共​​通の機能を1つ備えています。それぞれの機能を使用すると、1つのPythonファイルに完全に機能するアプリケーションを作成できます。

いくつかの開発者とマイクロフレームワークの著者は、ピラミッドの ​​&quot;hello world&quot;単一ファイルプログラムは、好きなマイクロフレームワークの同等のプログラムより長い(約5行で)ことを指摘しています。帯電したとして有罪。

この損失は試行の欠如のためではありません。ピラミッドは、マイクロファイルワークが優位性を主張しているのと同じ状況、すなわちシングルファイルアプリケーションでも役に立ちます。しかし、ピラミッドは、現在のマイクロフレームワークとのコード・パリティの &quot;hello world&quot;ラインを達成するために、より大きなアプリケーションを信頼できる形でサポートする能力を犠牲にすることはありません。代わりにPyramidの設計は、素朴な宣言的構成スキームに関連するいくつかの一般的な落とし穴を回避しようとしています。以下のサブセクションでその根拠を説明します。

アプリケーションプログラマはモジュールスコープコードパスを制御しません(インポート時の副作用は悪です)

一連のPythonファイルを含むディレクトリ構造を想像してみてください。

.
|-- app.py
|-- app2.py
`-- config.py

`` app.py``の内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from config import decorator
from config import L
import pprint

@decorator
def foo():
    pass

if __name__ == '__main__':
    import app2
    pprint.pprint(L)

`` app2.py``の内容:

1
2
3
4
5
import app

@app.decorator
def bar():
    pass

`` config.py``の内容:

1
2
3
4
5
L = []

def decorator(func):
    L.append(func)
    return func

これらのファイルを保持しているディレクトリに対して `` cd``を実行し、上記のディレクトリ構造とコードで `` python app.py``を実行すると、どうなりますか?おそらく、私たちの `` decorator``デコレータは `` app.py``内の `` foo``関数と `` app2.py``内の装飾関数 `` bar``の二回使用されるでしょう``。デコレータが使用されるたびに、 `` config.py``の `` L``が追加されているので、2つの要素を持つリストが印刷されると思いますよね?悲しいことに、

[chrism@thinko]$ python app.py
[<function foo at 0x7f4ea41ab1b8>,
 <function foo at 0x7f4ea41ab230>,
 <function bar at 0x7f4ea41ab2a8>]

視覚的検査によって、その結果(リストの3つの異なる機能)は不可能と思われる。 2つの関数しか定義しなかったので、それらの関数をそれぞれ1回だけ飾ったので、 `` decorator``デコレータは2回しか実行されないと考えています。しかし、私たちが信じることは、実際には間違っています。なぜなら、私たちの `` app.py``モジュールのモジュールスコープのコードが* 2回*実行されたからです。このコードは、スクリプトが `` __main__``( `` python app.py``を介して)で実行されると一度実行され、 `` app2.py``が `` app &#39;&#39;と同じファイルをインポートすると再び実行されます``。

これは、マイクロフレームワークとの比較とどう関係していますか?現在の作物の多くのマイクロフレームワーク(BottleやFlaskなど)では、モジュールスコープで定義されたオブジェクトにコンフィギュレーションデコレータをアタッチすることが推奨されています。これらのデコレータは、任意の複雑な登録コードを実行します。これは、外部Pythonモジュールで定義されたグローバルであるシングルトンレジストリにデータを読み込みます。これは上記の例に似ています:上の例の&quot;グローバルレジストリ&quot;はリスト &quot;L&quot;です。

同じパターンを Groundhog &#39;で使うとどうなるか見てみましょう<https://github.com/Pylons/groundhog> `_マイクロフレームワーク。上記の ` app.py``の内容を以下のように置き換えてください:

1
2
3
4
5
6
7
8
9
from config import gh

@gh.route('/foo/')
def foo():
    return 'foo'

if __name__ == '__main__':
    import app2
    pprint.pprint(L)

上記の `` app2.py``の内容を以下のように置き換えてください:

1
2
3
4
5
import app

@app.gh.route('/bar/')
def bar():
    'return bar'

上記の `` config.py``の内容を以下のように置き換えてください:

1
2
from groundhog import Groundhog
gh = Groundhog('myapp', 'seekrit')

&quot;gh Groundhogアプリケーションのルーティングテーブルに登録されるルートはいくつですか?あなたが3つ答えた場合、あなたは正しいですか?カジュアルリーダー(および正常な開発者)は何人登録する予定ですか?あなたは正しいですか?ダブル登録は問題になりますか?Groundhogフレームワークの `` route``メソッドは、このアプリケーションをサポートしています。実際にはアプリケーションを遅くするでしょう。それは他のフレームワーク、別のアプリケーション、または別のデコレータで問題になるのでしょうか?誰が知っていますか?アプリケーション全体を理解し、フレームワーク全体と実行時間を予測できる必要があります。意図しないコードの二重実行の影響はどのようなものになりますか。

外部レジストリの配置を行うデコレータの使用を奨励すると、意図しない結果になります。アプリケーション開発者は、Pythonモジュールスコープコードを実行するすべてのコードパスの所有権をアサートする必要があります。モジュールスコープコードは、デコレータベースのマイクロフレームワークの現在の作物によって1回だけ実行されると推定されます。複数回実行すると、奇妙なことが起こり始めるでしょう。この不変量を維持するのはアプリケーション開発者次第です。残念ながら、実際には、これは不可能な作業です。なぜなら、Pythonプログラマ*はモジュールスコープのコードパスを所有していないからです。あなたがそうするという考えにあなたを売ろうとする者は、間違っているだけです。あなたのコードのテストを実行するために使用したいと思うかもしれないテストランナーは、上記のようなバグを明らかにする不思議な命令で任意のコードをインポートすることがよくあります。 APIドキュメント生成ツールも同じです。 Pythonの `` reload``コマンドを使うことや、 `` sys.modules``からオブジェクトを削除する方が安全だと思う人もいます。それぞれのオブジェクトは、インポート時に副作用があるコードに対して使用すると面白い効果があります。

したがって、グローバルレジストリを変更するマイクロフレームワークプログラマーは、前の段落のように、モジュールスコープコードが複数回実行された場合に発生する可能性のあることについて、お茶リーフを読んでいく必要があります。 Pythonプログラマがモジュールスコープのコードパスを使用して任意のコード(特に外部レジストリを埋め込むコード)を実行できると仮定すると、この仮定は現実に挑戦され、アプリケーション開発者はしばしば厄介なデバッグプロセスを踏まなければなりません。必然的にあいまいな症状の根本的な原因を突き止める。解決方法は、アプリケーションのインポート順序を並べ替えるか、モジュールスコープから関数本体にインポートステートメントを移動することがよくあります。これを行うための根拠は、修正に伴うコミットメッセージで決して適切に表現されることはありません。また、開発チームの残りの利益のために十分に簡潔に文書化することはできません。特に、 `` pdb``を使ってモジュールスコープコードを実行している間に学んだレッスンをまだ内部化していない他の人たちと一緒にプロジェクトに取り組んでいるなら、もう一度やり直してください。デコレータベースのマイクロフレームワークで提供されているドキュメントでは、あなたに警告していないため、あなたやあなたのチームが登録したことさえ知りませんでした。

外部データ構造(マイクロフレームワークの作成者など)を占有する熱心なデコレータベースの構成に多額の投資をしている人は、上記で概説した一連の状況は異常であり、人工的であると主張するかもしれません。彼らはそれが決して起こらないと主張するでしょう。アプリケーションが1つまたは2つまたは3つのモジュールを超えて成長することを決して意図していない場合は、おそらくそれが当てはまります。しかし、コードベースが拡大し、より多くのモジュールに分散されるにつれて、モジュールスコープコードが複数回実行される状況がますます起こりやすくなり、予期しにくくなります。モジュールスコープコードの二重実行が決して起こらないと主張する責任はありません。そうなる;運と時間とアプリケーションの複雑さの問題です。

マイクロフレーム作成者がその状況が考案されていないと認める場合、モジュールスコープコードの二重実行(または三重実行など)の結果として実際の損害は決して起こらないと主張するかもしれない。あなたはこの主張を信じないことが賢明でしょう。複数の実行の潜在的な結果は、アプリケーションとフレームワークコードの間の微妙な関係やコード実行の時系列が関係しているため、予期するには多すぎます。フレームワークの作者があらゆる状況で何が起こるかを知ることは、文字通り不可能です。しかし、いくつかの限られた状況に対して全知の贈り物が与えられたとしても、フレームワークの作者は、新機能をコーディングする際に、二重実行異常を念頭に置いていることはほとんどありません。彼らは機能を追加することを考えており、1%の多重実行の場合に起こりうる問題に対して保護しません。しかし、1%の症例では、プロジェクトの痛みの50%が発生する可能性があるため、発生していないといいでしょう。

責任あるマイクロフレームワークは、実際には問題の背後にある道を提供します。デコレータベースの設定を完全に廃止することができます。あなたに次のことを要求する代わりに:

1
2
3
4
5
6
7
8
gh = Groundhog('myapp', 'seekrit')

@gh.route('/foo/')
def foo():
    return 'foo'

if __name__ == '__main__':
    gh.run()

デコレータの構文を廃止し、ほとんどすべての命令を実行することができます:

1
2
3
4
5
6
7
8
def foo():
    return 'foo'

gh = Groundhog('myapp', 'seekrit')

if __name__ == '__main__':
    gh.add_route(foo, '/foo/')
    gh.run()

これはPyramidのドキュメントで推奨されている一般的な操作モードです。いくつかの既存のマイクロフレームワーク(特にフラスコ)はそれを可能にします。なし(ピラミッド以外)*それを奨励する*。アプリケーションが2〜3または4〜10のモジュールを超えて成長することを決して期待しない場合は、どのモードを使用するかはあまり関係ありません。ただし、アプリケーションが大きくなる場合は、必須の構成によって予測性が向上します。

注釈

鋭い読者は、Pyramidにも構成デコレータがあることに気付くかもしれません。ああ!これらのデコレータに同じ問題はありませんか?いいえ。これらのデコレータは、実行時に外部のPythonモジュールを生成しません。彼らは、それらが接続されている関数(およびクラスとメソッド)のみを変更します。これらの突然変異は、予測可能かつ構造化されたインポートフェーズを有するスキャンプロセス中に後に見つけ出さなければならない。モジュールローカライズされた突然変異は、実際には二重輸入の最良の状況です。モジュールがインポート時に自分自身とその内容を変更するだけであれば、それが2回インポートされてもOKです。なぜなら、各デコレータ呼び出しは、レジストリのような共有リソースではなく、添付されたオブジェクトの独立したコピーをモジュール。これは、二重登録が決して実行されないという効果を有する。

経路には相対的な順序が必要

以下の単純な「Groundhog <https://github.com/Pylons/groundhog> `_アプリケーション:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from groundhog import Groundhog
app = Groundhog('myapp', 'seekrit')

@app.route('/admin')
def admin():
    return '<html>admin page</html>'

@app.route('/:action')
def do_action(action):
    if action == 'add':
       return '<html>add</html>'
    if action == 'delete':
       return '<html>delete</html>'
    return app.abort(404)

if __name__ == '__main__':
    app.run()

このアプリケーションを実行し、 `` / admin``のURLにアクセスすると、&quot;admin &quot;ページが表示されます。これが意図した結果です。ただし、ファイル内の関数定義の順序を並べ替えるとどうなりますか?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from groundhog import Groundhog
app = Groundhog('myapp', 'seekrit')

@app.route('/:action')
def do_action(action):
    if action == 'add':
       return '<html>add</html>'
    if action == 'delete':
       return '<html>delete</html>'
    return app.abort(404)

@app.route('/admin')
def admin():
    return '<html>admin page</html>'

if __name__ == '__main__':
    app.run()

このアプリケーションを実行し、 `` / admin``というURLにアクセスすると、アプリケーションは404エラーを返します。これはおそらくあなたが意図したものではありません。関数定義の順序を並べ替えるときに404エラーが表示される理由は、マイクロフレームワークのルーティングデコレータを介して表現されたルーティング宣言に* ordering *があり、その順序付けが重要であるということです。

我々が期待した結果を得た最初のケ​​ースでは、最初にパターン `` / admin`を追加した後、デコレータを介してルーティングパターンを追加することでパターン `` /:action``を追加しましたモジュールスコープで`` / admin``の `` PATH_INFO``を持つリクエストがアプリケーションに入ると、Webフレームワークは私たちのモジュールで定義された順番で、それぞれのアプリケーションのルートパターンをループします。その結果、 `` / admin``ルーティングパターンに関連付けられたビューが最初に一致するため、呼び出されます。すべてが世界と正しかった。

2番目のケースでは、期待した結果が得られなかったので、最初にパターン `` /:action``を追加した後、パターン `` / admin``を追加しました。 `` / admin``の `` PATH_INFO``を持つリクエストがアプリケーションに入ると、Webフレームワークは私たちのモジュールで定義された順番で、それぞれのアプリケーションのルートパターンをループします。結果として、 `` /:action``ルーティングパターンに関連付けられたビューは最初に一致するため呼び出されます。 404エラーが発生します。これは私たちが望むものではありません。私たちがビュー機能を定義した順序のために起こったばかりです。

これは、Groundhogルートがインポート順にルーティングマップに追加され、リクエストが入ったときに同じ順序で一致するためです。この記事の時点で、GroundhogのようなBottleは、Pythonで定義されている順序でルートを照合します実行時間。一方、フラスコは輸入注文に基づいてルートマッチングを注文しません。代わりに、アプリケーションに追加するルートを&quot;complexity &quot;に基づいて並べ替えます。他のマイクロフレームワークでは、経路の順序付けを行うさまざまな戦略があります。

あなたのアプリケーションは、ルートの順序が問題を引き起こさないほど十分に小さいかもしれません。しかし、アプリケーションが十分に大きくなると、アプリケーションが大きくなるにつれて順序を指定したり予測したりすることが難しくなります。ある時点で、特に拡張性を必要とするアプリケーションでは、より明示的に経路順序を制御し始める必要があります。

あなたのマイクロフレームワークが複雑さに基づいてルートマッチングを注文する場合、&quot;複雑さ&quot;が意味するものを理解する必要があります。そして、 &quot;より複雑ではない&quot;ルートを注入して、それが最初に試されることを保証するために &quot;より複雑な&quot;ものを選択します。

あなたのマイクロフレームワークが、関数デコレータ定義の相対的なインポート/実行に基づいてルートマッチングを注文する場合は、これらのステートメントをすべて「右」の順序で実行する必要があります。このインポートを認識する必要がありますアプリケーションを拡張したり、拡張しようとすると、実行順序が変わることがあります。これは、最小のアプリケーション以外のすべてを維持するのは難しい不変量です。

どちらの場合でも、アプリケーションは、構成の飾りを含む ``__main__``以外のモジュールを、何らかの形でそれらの構成が実行されるようにインポートする必要があります。それはあなたを少し不快にさせますか?これは、:ref: `you_dont_own_modulescope`のためです。

Pyramidは、デコレータのインポート時間の順序付けも、経路の順序付けを定義する手段として、ある経路の相対的な複雑さを別の経路に割り当てることもしません。 Pyramidでは、:meth: pyramid.config.Configurator.add_route`メソッドを複数回実行することによって、相対的なルートの順序付けを命令的に維持する必要があります。 ` add_route``を繰り返し呼び出す順序は、ルートマッチングの順番になります。

この必須命令を本当にバグのままにする必要がある場合、ルートマッチングの代わりに:term: `traversal`を使うことができます。これはコードをURLにマップするための完全に宣言的な(完全に予測可能な)メカニズムです。小さな非拡張可能アプリケーションではURLディスパッチが理解しやすくなりますが、トラバーサルは、非常に大きなアプリケーションや任意に拡張可能なアプリケーションに最適です。

&quot;スタックされたオブジェクトのプロキシ&quot;があまりにも賢い/スレッドの地元の人は迷惑です

いくつかのマイクロフレームワークは、 `` import``ステートメントを使って、論理的にグローバルではないオブジェクトへのハンドルを取得します

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from flask import request

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # this is executed if the request method was GET or the
    # credentials were invalid

`Pylons 1.X <https://docs.pylonsproject.org/projects/pylons-webframework/en/latest/> `_ web frameworkも同様の戦略を使用します。これは、これらのものを「スタックオブジェクトプロキシ」と呼びます。この議論の目的のために、私はそうするでしょう。

Pythonのimport文( `` import foo``、 `` from bar import baz``)は、外部Pythonモジュール内でグローバルに定義されたオブジェクトへの参照を取得するために最も頻繁に実行されます。しかし、通常のプログラムでは、関数の本体のスコープで測定された有効期間を持つオブジェクトへの参照を取得することはありません。たとえば、関数の本体で定義されたループカウンタを表す `` i``という名前の変数をインポートしようとするのは不合理です。例えば、以下のコードから `` i``をインポートしようとはしません。

1
2
3
def afunc():
    for i in range(10):
        print(i)

その性質上、WSGIサーバーの長期間Webフレームワークへの呼び出しの結果として生成される* request *オブジェクトは、グローバルにすることはできません。単一の要求の存続期間は、実行中のプロセスの存続期間フレームワーク。 Webフレームワークによって作成されたリクエストオブジェクトは、Python標準ライブラリまたは通常のライブラリコードで定義されている同等のインポート可能なオブジェクトよりも、上記の例の `` i``ループカウンタと実際に類似しています。

しかし、スタックされたオブジェクトプロキシを使用するシステムでは、 ``要求 &#39;&#39;のようなローカルスコープのオブジェクトをモジュールスコープに送り出して、 `` import``を含む素晴らしいスペルをユーザに提供することを目的としています。彼らは私が疑わしい理由を考えると、myframework.threadlocals import get_requestからsanerを使うのではなく、 ``フレームワークインポート要求から ``要求 &#39;&#39;を得る標準的な方法をユーザに提示するだろう。 request = get_request() ``のようになります。

マイクロフレームワークがスレッドローカル変数をまったく使用していない場合は、* most * explicitになります。ピラミッドビュー関数はリクエストオブジェクトに渡されます。 PyramidのAPIの多くは、明示的な要求オブジェクトを渡す必要があります。現在のピラミッド要求をスレッドローカル変数として取り出すことは可能ですが、緊急の場合には &quot;ブレークグラス&quot;タイプのアクティビティです。この設定では、テストセットアップ中に適切な&quot;ダミー&quot;要求(および同様のスコープを持つ)オブジェクトを作成するためにフレームワークに頼る必要がないため、ピラミッドビュー機能をより簡単にユニットテスト可能にしています。また、非同期サーバなどの、モノスケッチをしない任意のシステムで動作する可能性が高くなります。

明示的にWSGI

いくつかのマイクロフレームワークは、簡単な実行のためにデフォルトのサーバ設定を実行するアプリケーションオブジェクトの `` run() ``メソッドを提供します。

Pyramidは現在、ルータが便利な `` run() `` APIの後ろにあるWSGIアプリケーションであるという事実を隠そうとしていません。これは、WSGIサーバーをインポートし、そのWSGIサーバーのドキュメントに従ってPyramidアプリケーションを提供するために、WSGIサーバーをインポートするように指示します。

`` run() の後ろで提供ステップを抽象化することで節約された余分な行は、いくつかのマイクロフレームワークでそのAPIに関連する疑わしい2次的決定を引き起こしたようです。たとえば、Bottleには、 ` app.run() メカニズムを介してサポートされているWSGIサーバのタイプごとに、 `` ServerAdapter``サブクラスが含まれています。これは `` wsgiref、 `` flup``、 `` paste``、 `` cherrypy``、 `` fapws``モジュールに依存する `` bottle.py``にコードが存在することを意味します。 `` google.appengine``、 `` twisted.web``、 `` diesel``、 `` gevent``、 `` gunicorn``、 `` eventlet``、 ``ロケット。 `` run``メソッドに名前を渡すことで、実行したいサーバの種類を選択します。理論的には、これはすばらしいことです:私は `` gunicorn``のボトルを名前を渡すだけで試すことができます!ただし、ボトルを完全にテストするには、これらのサードパーティシステムをすべてインストールして機能させる必要があります。ボトルの開発者は、これらのパッケージのそれぞれに対する変更を監視し、コードが依然としてそれらと適切にインターフェースしていることを確認する必要があります。これにより、テストに必要なパッケージの数が大幅に増えます。これは要件の*ロット*です。要件の競合やビルドの問題により、これらのテストを完全に自動化することは難しいでしょう。

その結果、単一ファイルのアプリケーションの場合、現在 `` run() ``ショートカットを提供することに煩わされることはありません。私たちは、選択したWSGIサーバーをインポートし、手動で実行するように指示します。サーバー抽象化レイヤーが必要な人にとっては、PasteDeployを使用することをお勧めします。 PasteDeployベースのシステムでは、サーバーがWSGIアプリケーションとインターフェイスできることを確認するための責任は、Webフレームワークの開発者ではなく、サーバーの開発者に配置されるため、タイムリーかつ正確になる可能性が高くなります。

ラッピング

ここでは、最も単純なピラミッドアプリケーションのダイアグラムを示します。ここでは、:ref: `microframeworks_smaller_hello_world`セクションで説明したインラインコメントが考慮されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from wsgiref.simple_server import make_server  # explicitly WSGI
from pyramid.config import Configurator  # to configure app registry
from pyramid.response import Response  # explicit response, no threadlocal

def hello_world(request):  # accept a request; no request threadlocal reqd
    # explicit response object means no response threadlocal
    return Response('Hello world!')

if __name__ == '__main__':
    with Configurator() as config:    # no global application object
        config.add_view(hello_world)  # explicit non-decorator registration
        app = config.make_wsgi_app()  # explicitly WSGI
    server = make_server('0.0.0.0', 8080, app)
    server.serve_forever()            # explicitly WSGI

Pyramidはプラグイン可能なアプリケーションを提供していません

複数の外部ソースを:meth: `〜pyramid.config.Configurator.include`を使って同じ設定に組み立てるのは&quot; Pyramidic &quot;です。アプリケーションの作成には、任意の数のインクルードを行うことができます。包含は他の包含の中からでも行うことができます。 1つのディレクティブはインクルード内で使用できます(:meth: `〜pyramid.config.Configurator.add_view`など)。

ピラミッドには競合検出システムがあり、含まれている2つの外部が同じ構成を競合する方法で追加しようとするとエラーが発生します(同じ名前を使用してルートを追加しようとしている外部もあれば、同じ述語セット)。このセットの機能を&quot;プラグイン可能なアプリケーション&quot;からシステムを構成するために使うことができるものと呼ぶのはひどく魅力的です。しかし実際には、これを主張することにはいくつかの問題があります。

  • 用語は緊張している。 Pyramidには複数の &quot;アプリケーション&quot;という概念はありません。単一のWSGIアプリケーションを作成するために複数のソースから構成を作成する方法です。そのWSGIアプリケーションは、構成を含めるか否かによって動作を得ることができますが、一度構成すると、ピラミッドは実際には、アプリケーションの境界を区切るために使用できる機械を提供しません外部からルート、ビューなどを追加する外部)。
  • Pyramidは真に正直な、神からの、無作為な場所からのダウンロード、プラグインの作成を可能にするのに十分な &quot;レール&quot;を提供していません。 -system &quot;pluggable &quot;アプリケーション。 Pyramid自体は(特定の種類のデータベースを要求するものではなく、URLをコードなどにマップするための複数の方法を提供します)、アプリケーションに似たものを作成する人は、 J. Random Pyramid Userであり、パッケージの機能をconfig.includeに依頼するだけで動作します。これは、ブログ、ウィキ、ツイッタークローン、コメントシステムなどの非常に高いレベルのコンポーネントに特に当てはまります。インテグレータ(&quot;プラグ可能なアプリケーション&quot;として宣伝されたパッケージをダウンロードしたPyramid開発者)は、彼がどのようなタイプの永続システムを使用しているかについての選択、および「プラグ可能なアプリケーション」の要件を緩和するためのインテグレータのために、彼は別のデータベースを設定し、プラグイン可能なアプリケーションのシャドウイング(またはその逆)、その他任意の数の変更が含まれます。

このため、Pyramidにはプラグイン可能なアプリケーションではなく、 &quot;拡張可能な&quot;アプリケーションがあると主張しています。すべてのPyramidアプリケーションは、設定文が `` config.include``を介して取り込めるものに構成されていれば、それをフォークせずに拡張することができます。

単一の開発者やチームが、config.includeを使用して有効または無効にできる相互運用コンポーネントのセットを作成することも、まったく合理的です。その開発者またはチームは、プロジェクトを作成するために使用される技術について高いレベルの選択を行うことによって、&quot;rails &quot;を提供することができるので、すべてのコンポーネントを一緒に接続することに問題はありません。 Djangoは&quot;プラグ可能なアプリケーション&quot;と同様の問題を抱えていますが、これは多くの、より多くのレールを提供していますが、任意のサードパーティで動作する必要があることに注意してくださいn &quot;プラグ可能なアプリケーション&quot;の話を実際にローカルで修正することなく動作させるのに十分ではありません。

本当にプラグイン可能なアプリケーションは、Webフレームワークよりはるかに高いレベルで作成する必要があります。実際には、アプリケーションにプラグインする必要があります。これらの制約を提供し、アプリケーションをプラグインする方法を提供するPyramidを使ってアプリケーションを構築することは、貴重な目標です(Joomla、Plone、Drupalが思い浮かびます)。

ピラミッドにはゾープが入っているので、複雑すぎる

場合によっては、誰かが次のようなメーリングリストのメッセージを投稿しなければならないと感じるでしょう:

had a quick look at pyramid ... too complex to me and not really
understand for which benefits.. I feel should consider whether it's time
for me to step back to django .. I always hated zope (useless ?)
complexity and I love simple way of thinking

(実際の電子メールから言い換えると、実際には。)

この批判をポイントごとに見てみましょう。

複雑すぎる

この &quot;hello world&quot;プログラムを理解できれば、Pyramidを使うことができます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
    return Response('Hello world!')

if __name__ == '__main__':
    with Configurator() as config:
        config.add_view(hello_world)
        app = config.make_wsgi_app()
    server = make_server('0.0.0.0', 8080, app)
    server.serve_forever()

ピラミッドには、基本的なものから最も高度なものまで、1200ページ以上のドキュメンテーション(印刷物)があります。 文字通り、文書化されていないものは何もありません。それはまた素晴らしい、非常に有用なコミュニティを持っています。 freenode.netの `#pyramid IRCチャンネルをご覧ください<https://webchat.freenode.net/?channels=pyramid> `_そして参照してください。

憎むゾープ

私はあなたがそのように感じごめんなさい。 Zopeブランドは、長年に渡って確かに塊を占めており、孤独で神秘的であるという評判を持っています。しかし、&quot;ゾープ&quot;という言葉は、文字通り、無意味で無意味です。 Zopeの何があなたのことを憎んでいるのですか? &quot;Zope &quot;は技術ではなくブランドです。

Zope2-the-web-frameworkの場合、Pyramidはそうではありません。ピラミッドの主なデザイナーと開発者は誰でも知っておくべきです。 Zope 2にユーザビリティの問題や制限があることを知っていたため、Pyramidの前身(:mod: repoze.bfg)を書きました。 :mod: repoze.bfg`(そして今は:app: Pyramid`)がこれらの問題に対処するために書かれました。

Zope3-the-web-frameworkの場合、ピラミッドは絶対にそうではありません。多くのZope 3技術を利用することは、既に:term: `Grok`プロジェクトによって賭けられています。両方ともWebフレームワークであるという明白な事実のために保存してください:app: `Pyramid`はGrokと非常に大きく異なっています。 Grokは多くのZopeテクノロジをエンドユーザーに公開しています。一方、Pyramidを使用してZopeのみのコンセプトを理解する必要がある場合は、いくつかの非常に基本的な軸で失敗しました。

Zopeという単語だけの場合、これは関連性によってのみ罪を犯すことができます。ソフトウェアの一部は内部的に `` zope.foo``という名前のパッケージを使用しているので、それを使用するソフトウェアを&quot;Zope &quot;にすることはありません。その名前にZopeという言葉が書かれた*素晴らしいソフトウェアがたくさんあります。 Zopeはモノリシックなものではなく、多くのソフトウェアが外部で使用可能です。そして、それを守ることは実際にこの文書の仕事ではありませんが、Zopeは10年以上にわたって存在し、信じられないほど大きく、活発なコミュニティを持っています。あなたがこれを信じていないなら、http://pypi-ranking.info/authorは目を開く現実のチェックです。

愛シンプリシティ

このパッケージとそのドキュメントは、開発者が使用できるように人間工学的に可能な限りシンプルにするために努力してきました。もちろん、すべてはトレードオフですが、人々は&quot;シンプル&quot;について何か自分の考えを持っています。ピラミッドが複雑だと思えば、スタイルの違いがあるかもしれません。その開発者は明らかに同意しない。

その他の課題

他の挑戦は `Pylons-devel <https://groups.google.com/forum/#!forum/pylons-devel> `_ maillist。私たちはデザインの変更を考慮して、またはここでは少なくとも展覧会を経てそれらに取り組もうとします。