我想要为car
,tractor
和boat
创建一个课程。所有这些类都有engine
的实例,我想跟踪单个列表中的所有引擎。如果我正确理解电机对象是否可变,我可以将其存储为car
的属性,也可以将其存储在列表中。
我无法追踪关于用户定义的类是否可变的任何可靠信息,以及在定义它们时是否可以选择,是否有人可以解释一下?
答案 0 :(得分:31)
用户类被认为是可变的。 Python没有(绝对)私有属性,所以你总是可以通过进入内部来改变一个类。
要将您的课程用作dict
中的关键字或将其存储在set
中,您可以定义.__hash__()
method和.__eq__()
method,并承诺class是不可变的。您通常将类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
现在您可以在集合中使用类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
答案 1 :(得分:1)
所有对象(标准库中的少数对象,一些使用描述符和装饰器等实现特殊访问机制的对象,或者在C中实现的一些对象)都是可变的。这包括用户定义的类,类本身的实例,甚至是定义类的类型对象。您甚至可以在运行时改变类对象,并在修改之前创建的类的实例中显示修改。总的来说,如果你深入挖掘,事物只能通过Python中的常规变化。
答案 2 :(得分: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
dict存储weakref.ref
对象而不是实际存储对象的实际引用,可以稍微改进上面的示例。在这种情况下,在返回对象的新引用之前,请检查以确保引用仍处于活动状态(尚未进行垃圾回收)。
答案 3 :(得分:-2)
编辑:这在概念上是错误的,The immutable object in python可以解释为什么。
class Engine():
def __init__(self, sn):
self.sn = sn
a = Engine(42)
b = a
print (a is b)
打印True
。