说我要创建一类car
, tractor
和boat
。 所有这些类有一个实例engine
,我想跟踪所有引擎的一个列表。 如果我理解正确,如果电机的对象是可变的,我可以将其存储为属性car
在列表中,也是同样的情况。
我不能追查任何固体信息用户定义的类是否是可变的,如果有一个选择,当你确定他们选择,有谁能够提供一些线索?
说我要创建一类car
, tractor
和boat
。 所有这些类有一个实例engine
,我想跟踪所有引擎的一个列表。 如果我理解正确,如果电机的对象是可变的,我可以将其存储为属性car
在列表中,也是同样的情况。
我不能追查任何固体信息用户定义的类是否是可变的,如果有一个选择,当你确定他们选择,有谁能够提供一些线索?
用户类被认为是可变的。 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
所有对象(少数的标准库以外,一些实现使用像描述符和装饰,或者一些用C语言实现特殊的访问机制)是可变的。 这包括定义类用户定义的类的实例,类本身,甚至类型对象。 你甚至可以发生变异在运行时的类对象,必须在修改前创建类的实例清单的修改。 总的来说,如果你挖得足够深的东西是不变的只是由Python中约定。
我想你混淆的可变性与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
对象,而不是实际存储的对象真正的引用。 在这种情况下,你会检查,以确保基准仍然活着(尚未收集垃圾)返回一个新的参照对象之前。
编辑:这是错误的概念, 在Python的不可变对象可以提供一些线索,为什么。
class Engine():
def __init__(self, sn):
self.sn = sn
a = Engine(42)
b = a
print (a is b)
打印True
。