29

cartractorおよびのクラスを作成したいとしますboat。これらすべてのクラスには のインスタンスがengineあり、すべてのエンジンを 1 つのリストで追跡したいと考えています。carモーター オブジェクトが変更可能かどうかを正しく理解していれば、それを属性として、また同じインスタンスとしてリストに格納できます。

ユーザー定義のクラスが変更可能かどうかについての確実な情報を追跡することはできません。また、それらを定義するときに選択する選択肢がある場合、誰かが光を当てることができますか?

4

4 に答える 4

37

ユーザー クラスは変更可能と見なされます。Python には (絶対に) プライベート属性がないため、内部に到達することでいつでもクラスを変更できます。

クラスを のキーとして使用し dictたり、 に格納したりするために、 methodmethodsetを定義して、クラスが不変であることを約束できます。通常、このような場合、作成後に内部状態を変更しないようにクラス API を設計します。.__hash__().__eq__()

たとえば、エンジンが ID によって一意に定義されている場合、それをハッシュの基礎として使用できます。

class Engine(object):
    def __init__(self, id):
        self.id = id

    def __hash__(self):
        return hash(self.id)

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.id == other.id
        return NotImplemented

クラス Engine のインスタンスをセットで使用できるようになりました。

>>> eng1 = Engine(1)
>>> eng2 = Engine(2)
>>> eng1 == eng2
False
>>> eng1 == eng1
True
>>> eng1 == Engine(1)
True
>>> engines = set([eng1, eng2])
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])
>>> engines.add(Engine(1))
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])

上記のサンプルでは、​​別のEngine(1)インスタンスをセットに追加しましたが、既に存在していると認識され、セットは変更されませんでした。

リストに関する限り、.__eq__()実装が重要であることに注意してください。リストは、オブジェクトが変更可能かどうかは気にしませんが、.__eq__()メソッドを配置すると、特定のエンジンが既にリストに含まれているかどうかをテストできます。

>>> Engine(1) in [eng1, eng2]
True
于 2012-08-22T15:29:52.897 に答える
1

すべてのオブジェクト (標準ライブラリの一部、記述子やデコレータなどを使用して特別なアクセス メカニズムを実装するもの、または C で実装されるものを除く) は変更可能です。これには、ユーザー定義クラスのインスタンス、クラス自体、さらにはクラスを定義する型オブジェクトが含まれます。実行時にクラス オブジェクトを変更し、変更前に作成されたクラスのインスタンスに変更を反映させることもできます。概して、十分に深く掘り下げた場合にのみ、Python の慣例によって物事は不変になります。

于 2012-08-22T15:31:14.020 に答える
0

Pythonが参照を保持する方法と可変性を混同していると思います-考慮してください:

class Foo(object):
    pass

t = (1,2,Foo())  # t is a tuple, :. t is immutable
b = a[2]  # b is an instance of Foo
b.foo = "Hello"  # b is mutable.  (I just changed it)
print (hash(b))  # b is hashable -- although the default hash isn't very useful
d = {b : 3}      # since b is hashable, it can be used as a key in a dictionary (or set).
c = t            # even though t is immutable, we can create multiple references to it.
a = [t]          # here we add another reference to t in a list.

エンジンのリストをグローバルに取得/保存することについての質問です。これを行うにはいくつかの方法があります。

class Engine(object):
     def __init__(self, make, model):
        self.make = make
        self.model = model

class EngineFactory(object):
    def __init__(self,**kwargs):
        self._engines = kwargs

    def all_engines(self):
        return self._engines.values()

    def __call__(self,make, model):
    """ Return the same object every for each make,model combination requested """
       if (make,model) in _engines:
           return self._engines[(make,model)]
       else:
           a = self._engines[(make,model)] = Engine(make,model)
           return a   

 engine_factory = EngineFactory()

 engine1 = engine_factory('cool_engine',1.0)           
 engine2 = engine_factory('cool_engine',1.0)
 engine1 is engine2 #True !!!  They're the same engine.  Changing engine1 changes engine2

EngineFactory._engines上記の例は、オブジェクトへの実際の参照を実際に格納する代わりに、辞書weakref.refにオブジェクトを格納させることで少し改善できます。その場合、オブジェクトへの新しい参照を返す前に、参照がまだ生きている (ガベージ コレクションされていない) ことを確認します。

于 2012-08-22T16:04:36.680 に答える
-3

編集:これは概念的に間違っています。Pythonの不変オブジェクトは、その理由を明らかにすることができます。

class Engine():
    def __init__(self, sn):
        self.sn = sn

a = Engine(42)
b = a
print (a is b)

印刷しTrueます。

于 2012-08-22T15:32:42.333 に答える