为同一对象的另一个实例更改“self”?
Changing `self` for another instance of same object?
我想创建一个 class,并且所有对象都需要有一个唯一标识符 key
,并且如果我尝试使用以前存在的键创建对象的新实例,则实例应该与已经存在的实例相同。
类似于单例class,但在这种情况下而不是一个class,有很多但不同。
我的第一个方法是这样
class Master:
existent = {}
def __init__(self, key, value=None):
try:
self = Master.existent[key]
return
except KeyError:
Master.existent[key] = self
# Rest of the __init__ method
但是当我比较两个对象时,比如 A = Master('A', 0)
和 B = Master('B', 0)
,B
没有共享它应该有的任何属性,如果主 class有任何_method
(单下划线),也没有出现
知道我该怎么做吗?
我认为这类似于工厂方法模式,但我仍然无法找到相似之处,或者如何以优雅的形式实现。
编辑:
class 基本上有两个属性,仅此而已,但很多东西会继承 and/or 包含此类型的实例,easy 方式我我以为我能做到,是从现有实例中提取对应于所述 key
的属性,将它们分配给新实例并滥用它们将具有相同的 hash
输出和 equal
运算符将根据哈希值运行,因此我可以毫无问题地使用 ==
和 is
运算符。
这个想法解决了我的问题,但总的来说,我认为这可能是一个常见或有趣的场景,需要解决。
我认为您不能使用 __init__()
方法来做到这一点,因为在调用该方法时已经创建了 class 的新实例。您可能需要创建一个类似于以下内容的工厂类型方法:
class Master:
existent = {}
init_OK = False
def __init__(self, key, value=None):
if not Master.init_OK:
raise Exception('Direct call to Master() is not allowed')
Master.init_OK = False
self.key = key
self.value = value
Master.existent[key] = self
@staticmethod
def make(key, value=None):
try:
inst = Master.existent[key]
except:
Master.init_OK = True
inst = Master(key, value=value)
return inst
可以使用__new__
方法来处理。你不想调用 __init__
除非你想用一个新的键创建一个新对象,并且 __new__
可以用来在调用 __init__
之前先检查键是否唯一。
class Master(object):
instances = {}
def __new__(cls, key, value=None):
if key in Master.instances:
return Master.instances[key]
else:
instance = super(Master, cls).__new__(cls)
Master.instances[key] = instance
return instance
def __init__(self, key, value=None):
self.value = value
然后你可以用
创建对象
>>> A = Master('A',0)
>>> B = Master('B',0)
>>> C = Master('A',1)
由于 A
和 C
具有相同的键,它们将指向相同的对象并且实际上是相同的实例。由于 C
与 A
具有相同的键,因此它更新了它的值。
>>> print(A.value)
1
对 A
的任何新更改都将在 C
中显示,反之亦然。
>>> A.value = 5
>>> print(C.value)
5
但 A
和 C
的更改不会影响 B
,B
的更改不会影响 A
或 C
.
编辑:
如果你想复制值而不是实例,你可以只将值存储在 Master.instances
字典中并检查是否已经有键的值。
class Master(object):
instances = {}
def __init__(self, key, value=None):
if key in Master.instances:
self.value = Master.instances[key]
else:
self.value = value
Master.instances[key] = value
>>> A = Master('A',0)
>>> C = Master('A',1)
>>> print(C.value)
0
受 A Kruger
回答的启发,我有另一种解决方案,该解决方案是根据建议使用 __new__
方法构建的。这个答案的主要区别在于不需要创建内部 __Master
class。 __new__
方法在 Master()
被调用时自动调用,并且预期 return Master
class 的一个实例。在我的回答中,如果需要,__new__
方法 return 是一个新实例,但如果可能,return 是 existent
字典中的一个实例。请注意,用户像往常一样访问 Master
class,即他们只是调用 Master('A', 0)
。这可以通过使 Master
class 扩展 object
.
来实现
代码如下:
class Master(object):
existent = {}
def __init__(self, key, value=None):
self.key = key
self.value = value
if not key in Master.existent:
Master.existent[key] = self
def __new__(cls, *args, **kwargs):
key = args[0]
if key in Master.existent:
return Master.existent[key]
else:
return super(Master, cls).__new__(cls)
def __str__(self):
return('id: ' + str(id(self)) + ', key=' + str(self.key) + ', value=' + str(self.value))
A = Master('A', 0)
print('A = ' + str(A))
B = Master('A', 1)
print('\nAfter B created:')
print('B = ' + str(B))
print('A = ' + str(A))
B.value = 99
print('\nAfter B modified:')
print('B = ' + str(B))
print('A = ' + str(A))
C = Master('C', 3)
print('\nC = ' + str(C))
这是输出:
A = id: 140023450750200, key=A, value=0
After B created:
B = id: 140023450750200, key=A, value=1
A = id: 140023450750200, key=A, value=1
After B modified:
B = id: 140023450750200, key=A, value=99
A = id: 140023450750200, key=A, value=99
C = id: 140023450750256, key=C, value=3
注意A
和B
有相同的id
(它们是同一个对象)。另请注意,对 A
或 B
的更改会相互影响,因为它们是同一对象。
我想创建一个 class,并且所有对象都需要有一个唯一标识符 key
,并且如果我尝试使用以前存在的键创建对象的新实例,则实例应该与已经存在的实例相同。
类似于单例class,但在这种情况下而不是一个class,有很多但不同。
我的第一个方法是这样
class Master:
existent = {}
def __init__(self, key, value=None):
try:
self = Master.existent[key]
return
except KeyError:
Master.existent[key] = self
# Rest of the __init__ method
但是当我比较两个对象时,比如 A = Master('A', 0)
和 B = Master('B', 0)
,B
没有共享它应该有的任何属性,如果主 class有任何_method
(单下划线),也没有出现
知道我该怎么做吗?
我认为这类似于工厂方法模式,但我仍然无法找到相似之处,或者如何以优雅的形式实现。
编辑:
class 基本上有两个属性,仅此而已,但很多东西会继承 and/or 包含此类型的实例,easy 方式我我以为我能做到,是从现有实例中提取对应于所述 key
的属性,将它们分配给新实例并滥用它们将具有相同的 hash
输出和 equal
运算符将根据哈希值运行,因此我可以毫无问题地使用 ==
和 is
运算符。
这个想法解决了我的问题,但总的来说,我认为这可能是一个常见或有趣的场景,需要解决。
我认为您不能使用 __init__()
方法来做到这一点,因为在调用该方法时已经创建了 class 的新实例。您可能需要创建一个类似于以下内容的工厂类型方法:
class Master:
existent = {}
init_OK = False
def __init__(self, key, value=None):
if not Master.init_OK:
raise Exception('Direct call to Master() is not allowed')
Master.init_OK = False
self.key = key
self.value = value
Master.existent[key] = self
@staticmethod
def make(key, value=None):
try:
inst = Master.existent[key]
except:
Master.init_OK = True
inst = Master(key, value=value)
return inst
可以使用__new__
方法来处理。你不想调用 __init__
除非你想用一个新的键创建一个新对象,并且 __new__
可以用来在调用 __init__
之前先检查键是否唯一。
class Master(object):
instances = {}
def __new__(cls, key, value=None):
if key in Master.instances:
return Master.instances[key]
else:
instance = super(Master, cls).__new__(cls)
Master.instances[key] = instance
return instance
def __init__(self, key, value=None):
self.value = value
然后你可以用
创建对象>>> A = Master('A',0)
>>> B = Master('B',0)
>>> C = Master('A',1)
由于 A
和 C
具有相同的键,它们将指向相同的对象并且实际上是相同的实例。由于 C
与 A
具有相同的键,因此它更新了它的值。
>>> print(A.value)
1
对 A
的任何新更改都将在 C
中显示,反之亦然。
>>> A.value = 5
>>> print(C.value)
5
但 A
和 C
的更改不会影响 B
,B
的更改不会影响 A
或 C
.
编辑:
如果你想复制值而不是实例,你可以只将值存储在 Master.instances
字典中并检查是否已经有键的值。
class Master(object):
instances = {}
def __init__(self, key, value=None):
if key in Master.instances:
self.value = Master.instances[key]
else:
self.value = value
Master.instances[key] = value
>>> A = Master('A',0)
>>> C = Master('A',1)
>>> print(C.value)
0
受 A Kruger
回答的启发,我有另一种解决方案,该解决方案是根据建议使用 __new__
方法构建的。这个答案的主要区别在于不需要创建内部 __Master
class。 __new__
方法在 Master()
被调用时自动调用,并且预期 return Master
class 的一个实例。在我的回答中,如果需要,__new__
方法 return 是一个新实例,但如果可能,return 是 existent
字典中的一个实例。请注意,用户像往常一样访问 Master
class,即他们只是调用 Master('A', 0)
。这可以通过使 Master
class 扩展 object
.
代码如下:
class Master(object):
existent = {}
def __init__(self, key, value=None):
self.key = key
self.value = value
if not key in Master.existent:
Master.existent[key] = self
def __new__(cls, *args, **kwargs):
key = args[0]
if key in Master.existent:
return Master.existent[key]
else:
return super(Master, cls).__new__(cls)
def __str__(self):
return('id: ' + str(id(self)) + ', key=' + str(self.key) + ', value=' + str(self.value))
A = Master('A', 0)
print('A = ' + str(A))
B = Master('A', 1)
print('\nAfter B created:')
print('B = ' + str(B))
print('A = ' + str(A))
B.value = 99
print('\nAfter B modified:')
print('B = ' + str(B))
print('A = ' + str(A))
C = Master('C', 3)
print('\nC = ' + str(C))
这是输出:
A = id: 140023450750200, key=A, value=0
After B created:
B = id: 140023450750200, key=A, value=1
A = id: 140023450750200, key=A, value=1
After B modified:
B = id: 140023450750200, key=A, value=99
A = id: 140023450750200, key=A, value=99
C = id: 140023450750256, key=C, value=3
注意A
和B
有相同的id
(它们是同一个对象)。另请注意,对 A
或 B
的更改会相互影响,因为它们是同一对象。