In Python 3 everything is supposed to be an object, even numbers, but they're immutable.
Is it possible to create wrapper object for numbers, e.g. float, such that it would behave exactly as ordinary numbers except it must be mutable?
I've wondered whether it would be feasible using built-in type function by creating anonymous wrapper object deriving from float, but changing it behaviour to be mutable.
>>> f = lambda x : type('', (float,), dict())(x)
>>> a = f(9)
>>> a
9.0
What parameters must I change f to make number a be mutable?
How I verify if a number is mutable:
I must be able to create such function f that would create from integer value a float value and after shallow copy it would behave in the following manner:
>>> list_1 = [f(i) for i in [1, 2, 3, 4]]
>>> list_1
[1.0, 2.0, 3.0, 4.0]
>>> list_2 = copy.copy(list_1)
>>> list_1[0] *= 100
>>> list_1
[100.0, 2.0, 3.0, 4.0]
>>> list_2
[100.0, 2.0, 3.0, 4.0]
Modification of the first list, have changed both of them.
Maybe I must add some fields to dict() or add additional base class that would enforce mutability?
Values are immutable. They're platonic forms. An expression like 5 := 3
is nonsensical. What are mutable are locations
, usually referred to as addresses or pointers. Python doesn't have those, but we can fake it by using a container type like a list
, which is really a location that references other locations.
Here's a partial implementation of a mutable numerical type by using a list
to store a location where we will keep the value of the number and change the value in that location when it should change, and because all copies of a mutable number will share that location, all copies will see the change
import copy
# Convenience to work with both normal and mutable numbers
def _get_value(obj):
try:
return obj.value[0]
except:
return obj
class mutable_number(object):
def __init__(self, value):
# Mutable storage because `list` defines a location
self.value = [value]
# Define the comparison interface
def __eq__(self, other):
return _get_value(self) == _get_value(other)
def __ne__(self, other):
return _get_value(self) != _get_value(other)
# Define the numerical operator interface, returning new instances
# of mutable_number
def __add__(self, other):
return mutable_number(self.value[0] + _get_value(other))
def __mul__(self, other):
return mutable_number(self.value[0] * _get_value(other))
# In-place operations alter the shared location
def __iadd__(self, other):
self.value[0] += _get_value(other)
return self
def __imul__(self, other):
self.value[0] *= _get_value(other)
return self
# Define the copy interface
def __copy__(self):
new = mutable_number(0)
new.value = self.value
return new
def __repr__(self):
return repr(self.value[0])
x = mutable_number(1)
y = copy.copy(x)
y *= 5
print x
list_1 = [mutable_number(i) for i in [1, 2, 3, 4]]
list_2 = copy.copy(list_1)
list_1[0] *= 100
print list_1
print list_2
Please let me know if anything is unclear, and I can add more documentation