1

質問

python内部 (および外部) APIで文字列リテラルを再利用する "pythonic" (つまり、正規、公式、PEP8 承認など) の方法はありますか?


バックグラウンド

たとえば、私はいくつかの (一貫性のない) JSON 処理コード (数千行) を扱っており、さまざまな JSON " structs" がアセンブル、解析などされています。コード レビュー中に発生する繰り返しの問題の 1 つは、異なる JSON です。struct同じ内部パラメータ名を使用しているため、混乱が生じ、最終的にはバグが発生します。例:

pathPacket['src'] = "/tmp"
pathPacket['dst'] = "/home/user/out"
urlPacket['src'] = "localhost"
urlPacket['dst'] = "contoso"

これらの 2 つの (例) パケットには、同じ名前のフィールドが多数ありますが、それらは非常に異なるタイプのデータを表しています。この実装には、コードの再利用を正当化する理由はありませんでした。人々は通常、コード補完エンジンを使用して JSON のメンバーを取得しますstruct。これは、タイプミスされた文字列リテラルが機能上の問題を引き起こし、早期にエラーをトリガーしないため、最終的にデバッグが困難な問題につながります。これらの API を変更する必要がある場合、文字列リテラルを調べて、どの JSONstructがどのフィールドを使用しているかを調べるのに多くの時間がかかります。


質問 - Redux

pythonコミュニティのメンバーの間で一般的な、これに対するより良いアプローチはありますか? でこれを行っていた場合C++、前の例は次のようになります。

const char *JSON_PATH_SRC = "src";
const char *JSON_PATH_DST = "dst";
const char *JSON_URL_SRC = "src";
const char *JSON_URL_DST = "dst";
// Define/allocate JSON structs
pathPacket[JSON_PATH_SRC] = "/tmp";
pathPacket[JSON_PATH_DST] = "/home/user/out";
urlPacket[JSON_URL_SRC] = "localhost";
urlPacket[JSON_URL_SRC] = "contoso";

私の最初のアプローチは次のとおりです。

  • object として初期化できないabc抽象基本クラスを作成し、読み取り専用の定数を設定するために使用します。
  • そのクラスをプロジェクト全体の共通モジュールとして使用します。
  • これらの定数を使用することで、スペルが間違っているとシンボルが存在しないため、モンキー パッチ エラーの可能性を減らすことができますが、文字列リテラルのタイプミスはコード レビューをすり抜けてしまう可能性があります。

私の提案する解決策 (アドバイス/批判を受け入れる)

from abc import ABCMeta

class Custom_Structure:
    __metaclass__ = ABCMeta

    @property
    def JSON_PATH_SRC():
        return self._JSON_PATH_SRC

    @property
    def JSON_PATH_DST():
        return self._JSON_PATH_DST

    @property
    def JSON_URL_SRC():
        return self._JSON_URL_SRC

    @property
    def JSON_URL_DST():
        return self._JSON_URL_DST
4

3 に答える 3

4

これが通常行われる方法は次のとおりです。

JSON_PATH_SRC = "src"
JSON_PATH_DST = "dst"
JSON_URL_SRC = "src"
JSON_URL_DST = "dst"


pathPacket[JSON_PATH_SRC] = "/tmp"
pathPacket[JSON_PATH_DST] = "/home/user/out"
urlPacket[JSON_URL_SRC] = "localhost"
urlPacket[JSON_URL_SRC] = "contoso"

「定数」を示す大文字はその通りです。これは標準ライブラリにあり、 PEP8でも推奨されています。

通常、定数はモジュール レベルで定義され、すべて大文字で書かれ、アンダースコアで単語が区切られます。例には、 および が含ま MAX_OVERFLOWTOTALます。

Python には真の定数がなく、それがなくても生き残ったようです。プロパティを使用するクラスでこれをラップする方が快適な場合はABCmeta、先に進んでください。確かに、オブジェクトの初期化を妨げないabc.ABCmetaことは確かです。実際、もしそうなら、あなたの使用はうまくいきません! オブジェクトは class に属しますが、インスタンスからアクセスすることを意図しています。私には、それはほんの少しの利益のために多くのリガマロールのように見えます.propertyproperty

于 2017-12-21T19:18:26.100 に答える
3

私の意見では、定数を作成する最も簡単な方法は、それらをモジュール内の変数として設定することです (変更しないでください)。

JSON_PATH_SRC = "src"
JSON_PATH_DST = "dst"
JSON_URL_SRC = "src"
JSON_URL_DST = "dst"

次に、別のモジュールからそれらを参照する必要がある場合は、既に名前空間が割り当てられています。

>>> that_module.JSON_PATH_SRC
'src'
>>> that_module.JSON_PATH_DST
'dst'
>>> that_module.JSON_URL_SRC
'src'
>>> that_module.JSON_URL_DST
'dst'
于 2017-12-21T19:19:44.140 に答える