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

Is it possible to make wrapper object for numbers, e.g. float, to make it mutable?

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

是否可以为数字创建包装器对象,例如float,这样它的行为就和普通数字完全一样,除了它必须是可变的?

我想知道是否可以使用内置 type 函数创建从 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() 添加一些字段或添加额外的基础 class 以强制执行可变性?

值是不可变的。它们是柏拉图式的。像 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
# <
# 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)

        for attr_name in dir(self._type):
            if attr_name not in dir(Mutable):
                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 [=21] 实例的属性 _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 等低级语言中使用指针来实现这种行为。