2

私はPythonにかなり慣れていないので、この質問がばかげていると思われる場合はお詫び申し上げます。これは単なる好奇心ではなく、そのようなクラスを持つコードで作業する必要があります。

次のPythonコードスニペットについて考えてみます。

class _Base(object):
  constant1 = 1
  constant2 = 2
  constant3 = 3


def main():
  a = _Base    # Referencing a class
  b = _Base()  # Instantiating


if __name__ == '__main__':
  main()

この特定の例では、_Baseクラスにメソッドがない場合、?と比較してアプローチを__init__()使用することで、パフォーマンス面またはその他の面で欠点がありますか?ba

4

4 に答える 4

4

通常は、クラスではなくモジュール内に定数を配置します。それらをサブクラスに使用する必要がある場合は、Baseから継承して使用します。それ以外の場合はclass、一種の「名前空間」として使用しているだけなので、インスタンス化しないでください。

それよりも良い名前を付け、代わりに_Base(たとえば:)として変数にアクセスしますMyConstants.constant1...

于 2013-02-21T01:02:39.323 に答える
3

Jon Clementsは、これをどのように行うべきかについての答えを示しています。

しかし、あなたの実際の質問に答えるために:

aと比較してbアプローチを使用することには、パフォーマンス面またはその他の面でマイナス面がありますか?

パフォーマンスよりも重要なのは読みやすさです。オブジェクトをインスタンス化すると、読者は何らかの理由でインスタンス化したと思い、オブジェクトモデルでb何が使用されているのか、インスタンスが何を表しているのかなどを把握しようとします。_Base役に立たないことを理解するのにそれほど時間はかかりませんが、「理解するのに時間がかかりすぎない」よりも「明白」の方が常に優れています。

ただし、パフォーマンスの欠点もあります。これまでに作成したプログラムでは、測定可能な方法で問題になることはほとんどありませんが、問題はありません。

1bつ目は、新しく割り当てられたオブジェクトで、数バイト(おそらく数十バイト)かかりますが、aは既存のオブジェクト(クラス自体)の新しい名前です。だから、それはメモリを浪費します。

第二に、構築bには少し時間がかかります。__new__そのメモリを割り当てることに加えて、のと__init__スロットを呼び出す必要もありますobject

でパフォーマンスの違いを自分でテストできますがtimeit、気にしません。bほとんどの場合、それは20倍遅いか、そのようなものであることがわかりますaが、1回の実行で1マイクロ秒未満かかる20:1の改善は、それでも意味がありません。

于 2013-02-21T01:17:30.293 に答える
0

@Jon Clementsの答えはかなり良いですが、必要に応じて、クラスにとどまることができますが、すべての定数を静的メソッドに変換します。

class MyConstants(object):

    @staticmethod
    def constant1():
        return 1

次に、それを呼び出すことができます:

some_variable = MyConstants.constant1()

このような処理は保守性の点で優れていると思います---定数を返す以外のことをしたい場合、Jonのソリューションは機能せず、コードをリファクタリングする必要があります。たとえば、constant1ある時点での定義を変更したい場合があります。

def constant1():
    import time
    import math

    current_time = time.time()        
    return math.ceil(current_time)

現在の時刻を最も近い秒に戻します。

とにかく、エッセイでごめんなさい:)


したがって、ここでのコメントを考えると、(ファクトリを使用して)自分のやり方で物事を行う場合、静的定数を宣言する場合、クラスでプロパティを使用する場合の実際のオーバーヘッドがわかると思いました。

time_test.py

import time

CONSTANT_1 = 1000
CONSTANT_2 = 54
CONSTANT_3 = 42
CONSTANT_4 = 3.14

class Constants(object):
    constant_1 = 1000
    constant_2 = 54
    constant_3 = 42
    constant_4 = 3.14

class Factory(object):

    @staticmethod
    def constant_1():
        return 1000

    @staticmethod
    def constant_2():
        return 54

    @staticmethod
    def constant_3():
        return 42

    @staticmethod
    def constant_4():
        return 3.14

if __name__ == '__main__':

    loops = 10000000

    # static const                                                                                                                                                                                                                                                              
    start = time.time()
    for i in range(loops):
        sum = CONSTANT_1
        sum += CONSTANT_2
        sum += CONSTANT_3
        sum += CONSTANT_4

    static_const_time = time.time() - start

    # as attributes                                                                                                                                                                                                                                                             
    start = time.time()
    for i in range(loops):
        sum = Constants.constant_1
        sum += Constants.constant_2
        sum += Constants.constant_3
        sum += Constants.constant_4

    attributes_time = time.time() - start

    # Factory                                                                                                                                                                                                                                                                   
    start = time.time()
    for i in range(loops):
        sum = Factory.constant_1()
        sum += Factory.constant_2()
        sum += Factory.constant_3()
        sum += Factory.constant_4()

    factory_time = time.time() - start

    print static_const_time / loops
    print attributes_time / loops
    print factory_time / loops

    import pdb
    pdb.set_trace()

結果:

Bens-MacBook-Pro:~ ben$ python time_test.py
4.64897489548e-07
7.57454514503e-07
1.09821901321e-06
--Return--
> /Users/ben/time_test.py(71)<module>()->None
-> pdb.set_trace()
(Pdb) 

これで、効率がわずかに向上しました(1000万ループあたり数秒)。これは、コード内の他の場所にあるものに圧倒される可能性があります。したがって、このようなマイクロ最適化を気にしない限り、3つのソリューションすべてが同様のパフォーマンスを発揮することを確立しました。(その場合は、おそらくCで作業する方がよいでしょう。)3つのソリューションはすべて、読み取り可能で保守可能であり、Pythonを使用するソフトウェア会社のバージョン管理に含まれている可能性があります。したがって、違いは美学にあります。

とにかく、書誌が正しくフォーマットされていなかったので、高校の研究論文で15%のポイントを失ったことがあります。内容は完璧でした、それは私の先生にとってちょうど十分ではありませんでした。ルールを学んだり、問題を解決したりするのに時間を費やすことができることがわかりました。私は問題を解決することを好みます。

于 2013-02-21T01:09:43.677 に答える
0

@property将来のメンテナンスに注意し、すべてのメソッドが通常の定数と区別できないため、クラスにすべてのメソッドを設定し、すべてがのインスタンスに_Baseなり、便利なpropertyデコレータにラップされるため、コードを拡張できるようにします。

class Base(object):
    """for now, just holds constants"""
    def __init__(self):
        pass

    @property
    def constant1(self):
        return 1

    @property
    def constant2(self):
        return 2

    @property
    def constant3(self):
        return 3

もちろん、私の次の質問は...なぜそれを行うためにクラスをインスタンス化する必要があるのですか?メソッドで定数を定義しないのはなぜですか?

#! /usr/bin/env python
"""this module does stuff"""

CONSTANT_1 = 1
CONSTANT_2 = 2
CONSTANT_3 = 3

それらを引数として提供せずに、メソッドおよびクラスでそれらを参照できます。それらは、定数がそうであるように、データの広範なソースとして機能します。これは通常、マジックナンバーを回避する方法です。

于 2013-02-21T01:26:43.930 に答える