Reputation: 43487
I've got a somewhat complex data-type Mask
that I'd like to be able to use fast identity checking for such as:
seen = set()
m = Mask(...)
if m in seen:
...
This suggests that Mask should be hashable and therefore immutable. However, I'd like to generate variants of m
and Mask
seems like the place to encapsulate the variation logic. Here is a minimalish example that demonstrates what I want to accomplish:
class Mask(object):
def __init__(self, seq):
self.seq = seq
self.hash = reduce(lambda x, y: x ^ y, self.seq)
# __hash__ and __cmp__ satisfy the hashable contract §3.4.1)
def __hash__(self):
return self.hash
def __cmp__(self, other):
return cmp(self.seq, other.seq)
def complement(self):
# cannot modify self without violating immutability requirement
# so return a new instance instead
return Mask([-x for x in self.seq])
This satisfies all of the hashable and immutable properties. The peculiarity is having what is effectively a Factory method complement
; is this a reasonable way to implement the desired function? Note that I am not at all interested in protecting against "malicious" modification as many related questions on SO are looking to achieve.
As this example is intentionally small it could be trivially solved by making a tuple of seq. The type that I am actually working with does not afford such simple casting.
Upvotes: 0
Views: 139
Reputation: 414139
Python doesn't inforce immutability. It is up to you to make sure that objects are not modified while they are in a set
. Otherwise you don't need immutability to use sets, dictionaries in Python.
Upvotes: 1
Reputation: 363517
Yes, this is pretty much how you write an immutable class; methods that would otherwise change an object's state become, in your terms, "factories" that create new instances.
Note that in the specific case of computing a complement, you can name the method __invert__
and use it as
inv_mask = ~mask
Operator syntax is a strong signal to client code that operations return new values of the same type.
Upvotes: 2
Reputation: 20131
When using immutable types, all 'variation' methods must return new objects/instances, and thus be factories in that sense.
Many languages make strings immutable (including Python). So all string operations return new strings; strB = strA.replace(...)
etc.
If you could change the instance at all, it wouldn't be immutable.
Edit:
Rereading, you're asking if this is reasonable, and I say yes. The logic would not be better put somewhere else, and as I pointed out with string immutability it is a common paradigm to get new variations from existing ones.
Upvotes: 1