3

フォルダーにスクリーンショットを作成する機能を使用する自動化テストがあります。この関数は、複数のスクリーンショットインスタンスによって呼び出されます。テストを実行するたびに新しいフォルダーが作成されるので、カウンターのリセットは気にしません。これらのスクリーンショットが撮られる順序を反映するために、私は順序でソートできる名前を考え出さなければなりませんでした。これが私の解決策です:

def make_screenshot_file(file_name):
    order = Counter().count
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order))


class Counter():
    __counter_instance = None

    def __init__(self):
        if Counter.__counter_instance is None:
            self.count = 1
            Counter.__counter_instance = self
        else: 
            Counter.__counter_instance.count += 1
            self.count =  Counter.__counter_instance.count

それは私にとってはうまくいきます。しかし、私はこの問題を解決するためのより簡単な方法があるべきだと考え続けています。ある?そして、シングルトンが唯一の方法である場合、私のコードは何らかの方法で最適化できますか?

4

4 に答える 4

4

ここで実行しようとしているのは、グローバル変数をシミュレートすることです。

それをする正当な理由はありません。本当にグローバル変数が必要な場合は、明示的にグローバル変数にします。

アクセスするたびに1ずつ増加する単純なCounterクラスを作成してから、そのグローバルインスタンスを作成できます。しかし、 DSMがコメントで説明してcountいるように、標準ライブラリはすでにそのようなものを無料で提供しています。itertools.count

それで:

import itertools

_counter = itertools.count()
def make_screenshot_file(file_name):
    order = next(_counter)
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order))

なぜこれがどれだけのストレージや時間を費やすのか心配しているのかわかりません。なぜなら、単一のオブジェクトに8バイトを使用しているか800バイトを使用しているかが問題になる可能性のあるプログラムは考えられないからです。複数あるか、またはアクセスするのに3nsまたは3usかかったかどうかは、ほんの数回しかアクセスできません。

しかし、ソースからわかるように、Cで実装されているのではないかと心配している場合、かなりメモリ効率が高く、何もしなければ、基本的に1つで各数値を生成します。数行のコードを解釈するよりもはるかに少ないです。countPyNumber_Add


あなたが尋ねたので、_countクラス属性の代わりにクラス属性を使用することによって、既存のコードを根本的に単純化する方法は次の__counter_instanceとおりです。

class Counter():
    _count = 0
    def count(self):
        Counter._count += 1
        return Counter.count

もちろん、今Counter().count()はただではなく、そうしなければなりません—しかし、それが重要な場合は、それCounter().countを簡単に修正できます@property

It's worth pointing out that it's a really bad idea to use a classic class instead of a new-style class (by passing nothing inside the parens), and if you do want a classic class you should leave the parens off, and most Python programmers will associate the name Counter with the class collections.Counter, and there's no reason count couldn't be a @classmethod or @staticmethod… at which point this is exactly Andrew T.'s answer. Which, as he points out, is much simpler than what you're doing, and no more or less Pythonic.

But really, all of this is no better than just making _count a module-level global and adding a module-level count() function that increments and returns it.

于 2013-03-15T22:44:34.037 に答える
2

どうして

order = time.time()

または次のようなことをします

import glob #glob is used for unix like path expansion
order = len(glob.glob(os.path.join(test_suites_path,"screenshot","%s*"%filename))
于 2013-03-15T18:23:51.620 に答える
1

静的メソッドと変数の使用。あまりPythonicではありませんが、より単純です。

def make_screenshot_file(file_name):
    order = Counter.count() #Note the move of the parens
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order))

class Counter():
  count_n = 0

  @staticmethod
  def count():
    Counter.count_n += 1
    return Counter.count_n


print Counter.count()
print Counter.count()
print Counter.count()
print Counter.count()
print Counter.count()


atarzwell@freeman:~/src$ python so.py
1
2
3
4
5
于 2013-03-15T18:35:40.610 に答える
0

さて、あなたはこの解決策を使うことができます、ただあなたが注文kwargを決して初期化しないことを確認してください!

関数の可変Kwargsは、クラスのグローバル変数のように機能します。そして、あなたが最初に考えるかもしれないように、値は呼び出しの間にデフォルトにリセットされません!

def make_screenshot_file(file_name , order=[0]):
    order[0] = order[0] + 1
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order[0]))
于 2013-03-15T21:56:46.103 に答える