是用户定义的类的可变(are user defined classes mutable)

2019-06-27 06:45发布

说我要创建一类cartractorboat 。 所有这些类有一个实例engine ,我想跟踪所有引擎的一个列表。 如果我理解正确,如果电机的对象是可变的,我可以将其存储为属性car在列表中,也是同样的情况。

我不能追查任何固体信息用户定义的类是否是可变的,如果有一个选择,当你确定他们选择,有谁能够提供一些线索?

Answer 1:

用户类被认为是可变的。 Python没有(绝对)私有属性,让您可以随时通过进入的内部变化的类。

对于使用类如在一个关键的dict或将它们存储在一set ,你可以定义一个.__hash__()方法和.__eq__()方法 ,使得一个承诺,你的类是不可变的。 通常你设计你的类API在这种情况下,创建后发生变异的内部状态。

例如,如果你的引擎由其唯一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

现在你可以使用在集合类引擎的实例:

>>> 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


Answer 2:

所有对象(少数的标准库以外,一些实现使用像描述符和装饰,或者一些用C语言实现特殊的访问机制)是可变的。 这包括定义类用户定义的类的实例,类本身,甚至类型对象。 你甚至可以发生变异在运行时的类对象,必须在修改前创建类的实例清单的修改。 总的来说,如果你挖得足够深的东西是不变的只是由Python中约定。



Answer 3:

我想你混淆的可变性与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对象,而不是实际存储的对象真正的引用。 在这种情况下,你会检查,以确保基准仍然活着(尚未收集垃圾)返回一个新的参照对象之前。



Answer 4:

编辑:这是错误的概念, 在Python的不可变对象可以提供一些线索,为什么。

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

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

打印True



文章来源: are user defined classes mutable