是否可以为数字制作包装器对象,例如浮点数,使其可变?



在Python 3中,一切都应该是一个对象,偶数,但它们是不可变的

是否可以为数字创建包装器对象,例如浮点数,使其行为与普通数字完全相同,只是它必须是可变的?

我想知道通过创建从 float 派生的匿名包装器对象来使用内置类型函数是否可行,但将其行为更改为可变。

>>> f = lambda x : type('', (float,), dict())(x)
>>> a = f(9)
>>> a
9.0

我必须更改哪些参数f才能使数字a可变?

如何验证数字是否可变:

我必须能够创建这样的函数f,它将从整数值创建一个浮点值,并且在浅拷贝后它将以以下方式运行:

>>> 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]

修改第一个列表,已经改变了它们。

也许我必须在dict()中添加一些字段或添加额外的基类来强制执行可变性?

值是不可变的。它们是柏拉图式的形式。像5 := 3这样的表达是无意义的。可变的locations,通常称为地址或指针。Python 没有这些,但我们可以通过使用容器类型来伪造它,例如list,这实际上是一个引用其他位置的位置。

下面是可变数值类型的部分实现,它使用list来存储一个位置,我们将保留数字的值,并在该位置的值应该更改时更改该位置的值,并且由于可变数字的所有副本都将共享该位置,因此所有副本都将看到更改

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

如果有任何不清楚的地方,请告诉我,我可以添加更多文档

也许您需要像下面这样的包装器。

# To solve scope issues. See
# <https://stackoverflow.com/questions/3431676/creating-functions-in-a-loop>
# for details.
def make_new_method(self, method_name):
def new_method(self, *a, **aa):
method = getattr(self._type, method_name)
return method(self._heart, *a, **aa)
return new_method

class Mutable():
def __init__(self, obj):
self._heart = obj
self._type = type(obj)
# Remap each of the heart object's attributes to be used on the
# wrapper object.
for attr_name in dir(self._type):
# Do not overwrite existing Mutable methods, only set new ones
# from its heart.
if attr_name not in dir(Mutable):
# Methods need to be treated differently.
if callable(getattr(self._type, attr_name)):
new_attr = make_new_method(self, attr_name)
setattr(Mutable, attr_name, new_attr)
else:
attr_value = getattr(self._heart, attr_name)
setattr(self, attr_name, attr_value)
def set(self, new_value):
if self._type is type(new_value):
self._heart = new_value
else:
self.__init__(new_value)
def __repr__(self):
return f'Mutable({repr(self._heart)})'

当你编写mutable3 = Mutable(3)时,它将您希望可变的值(在本例中为 3)存储在Mutable类实例的 atribute_heart中,并重新映射其方法以直接与实例本身一起使用。例如,它允许做

In [1]: a = list(map(Mutable, range(3)))
In [2]: a
Out[2]: [Mutable(0), Mutable(1), Mutable(2)]
In [3]: b = a[1]
In [4]: b.set('hello')
In [5]: a
Out[5]: [Mutable(0), Mutable('hello'), Mutable(2)]

在我看来,这听起来像是在变量之间创建"符号链接",这是我们使用较低级别语言(如 C)中的指针来实现的行为。

相关内容

最新更新