これは現実のシナリオです:私はアプリケーションを作成していますが、特定の種類のファイルを表すクラスがあります(私の場合は写真ですが、その詳細は問題とは関係ありません)。 Photographクラスの各インスタンスは、写真のファイル名に対して一意である必要があります。Pythonでクラスのインスタンス化をどのようにメモすることができますか?
問題は、ユーザーがファイルを読み込むようにアプリケーションに指示したときに、ファイルが既にロードされていることを識別し、同じファイル名に重複するインスタンスを作成するのではなく、 。
これは私にとってはメモを使う良い状況のようですが、そこには多くの例がありますが、この場合私は普通の関数をメモしているだけではなく、__init__()
をメモする必要があります。これは問題があります。__init__()
が呼び出されるまでにはすでに新しいインスタンスが作成されているので、すでに遅すぎます。
私の研究では、Pythonの__new__()
メソッドが見つかりましたが、実際には簡単な例を書くことができましたが、実際のオブジェクトに使用しようとすると分解してしまいました。私が考えることができるのは、私の実際の世界のオブジェクトは、私が本当に制御できない他のオブジェクトのサブクラスなので、このアプローチにはいくつかの非互換性がありました)。これは私が持っていたものです:
making a new one!
139958663753808
139958663753808
making a new one!
139958663753872
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb090>
True False
killing <__main__.Flub object at 0x7f4aaa6fb050>
killing <__main__.Flub object at 0x7f4aaa6fb090>
それは完璧です:これは出力
class Flub(object):
instances = {}
def __new__(cls, flubid):
try:
self = Flub.instances[flubid]
except KeyError:
self = Flub.instances[flubid] = super(Flub, cls).__new__(cls)
print 'making a new one!'
self.flubid = flubid
print id(self)
return self
@staticmethod
def destroy_all():
for flub in Flub.instances.values():
print 'killing', flub
a = Flub('foo')
b = Flub('foo')
c = Flub('bar')
print a
print b
print c
print a is b, b is c
Flub.destroy_all()
!一意の2つのidに対して2つのインスタンスのみが作成され、Flub.instancesには2つのリストが明示されています。
しかし、私が使用していたオブジェクトでこのアプローチを取ろうとしたとき、__init__()
は2つではなく0つの引数しか取らなかったという無意味なエラーが発生しました。私は__init__()
に議論が必要でした。完全に奇妙な。
はそれと戦うしばらくして、私は基本的にはちょうどあきらめ、get
呼ばstaticmethodにすべての__new__()
黒魔術を移動し、私はPhotograph.get(filename)
を呼び出すことができますし、ファイル名がPhotograph.instances
にはすでになかった場合にのみPhotograph(filename)
を呼ぶだろうな。
ここで私がどこに間違っていたのか誰か知っていますか?これを行うにはよりよい方法がありますか?
もう一つの考え方は、シングルトンに似ていることですが、グローバルシングルトンではなく、ファイルごとにシングルトンだけである点が異なります。
Here's my real-world code using the staticmethod getすべて一緒に表示する場合は、 __new__
へ
あなたが言ったことを削除する質問を編集しました。 – robru