无法复制作为 float 子类的对象

问题描述 投票:0回答:3

具体问题:我在Python中创建了一个类,它是float的子类,这里作为示例只是添加了一个“name”字段。该课程似乎如我所愿地工作,但我注意到我无法对这些对象执行 copy.copy() 或 copy.deepcopy() 。类和复制命令是:

import copy


class NamedFloat(float):

    def __new__(cls, val: float, name: str):
        if val is None:
            return None
        else:
            return super().__new__(cls, val)

    def __init__(self, val: float, name: str):
        self.name = name


x = NamedFloat(4.23, 'ClientA')
x2 = copy.copy(x)

报错信息是:

Traceback (most recent call last):
  File "C:\Users\Noughbee\Python\nf\named_float.py", line 18, in <module>
    x2 = copy.copy(x)
         ^^^^^^^^^^^^
  File "C:\Users\Noughbee\AppData\Local\Programs\Python\Python311\Lib\copy.py", line 102, in copy
    return _reconstruct(x, None, *rv)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Noughbee\AppData\Local\Programs\Python\Python311\Lib\copy.py", line 265, in _reconstruct
    y = func(*args)
        ^^^^^^^^^^^
  File "C:\Users\Noughbee\AppData\Local\Programs\Python\Python311\Lib\copyreg.py", line 105, in __newobj__
    return cls.__new__(cls, *args)
           ^^^^^^^^^^^^^^^^^^^^^^^
TypeError: NamedFloat.__new__() missing 1 required positional argument: 'name'

是否有缺失的 dunder 方法或其他方法可以帮助这门课很好地处理复制?

元问题:我真的很喜欢将浮点数或 NumPy ndarrays 子类化的类的想法,因为主要数据是一个单一的东西——一个浮点数或一个 NDArray——恰好有与之相关的元数据……和使用这些子类,当我想访问主要内容时我可以写“value”,而在访问元数据时我可以写“value.name”或其他任何内容。这很有趣,而且对我来说,当您可以使用数量编写熟悉的数学表达式并“忘记”它携带的元数据时,可以生成更清晰的代码。但是这个问题和我最近发布的一个有点相关的问题(How to avoid an object that subclasses NumPy's ndarray being "demoted" to a regular ndarray when placed in a containing ndarray?) may be telling me that this "trick" is'没有那么强大,我应该克服被它迷住的感觉。你怎么说?

python floating-point copy subclass
3个回答
0
投票

为了避免这个错误,你应该为参数定义一个默认值

name

import copy


class NamedFloat(float):
    def __new__(cls, val: float, name: str = None):
        if val is None:
            return None
        else:
            return super().__new__(cls, val)

    def __init__(self, val: float, name: str):
        self.name = name


x = NamedFloat(4.23, "ClientA")
x2 = copy.copy(x)

0
投票

copy.copy
函数不知道类的构造函数的签名,这就是它引发该错误的原因,但它允许您通过
__copy__
方法提供自己的浅拷贝实现:

    def __copy__(self) -> 'NamedFloat':
        return NamedFloat(self, self.name)

0
投票

尝试定义

__getnewargs__()
来告诉
__copy__()
的默认实现如何重建
NamedFloat
的实例:

In [25]: import copy
    ...: 
    ...: 
    ...: class NamedFloat(float):
    ...:     __slots__ = ('name',)
    ...: 
    ...:     def __new__(cls, value, name):
    ...:         self = super().__new__(cls, value)
    ...:         self.name = name
    ...:         return self
    ...: 
    ...:     def __getnewargs__(self):
    ...:         return float(self), self.name
    ...: 
    ...: 
    ...: 
    ...: x = NamedFloat(4.23, 'ClientA')
    ...: y = NamedFloat(4.23, 'ClientB')
    ...: x2 = copy.copy(x)
    ...: y2 = copy.copy(y)
    ...: print('x', id(x), x, repr(x), type(x), x.name)
    ...: print('x2', id(x2), x2, repr(x2), type(x2), x2.name)
    ...: print('y', id(y), y, repr(y), type(y), y.name)
    ...: print('y2', id(y2), y2, repr(y2), type(y2), y2.name)
x 4371847520 4.23 4.23 <class '__main__.NamedFloat'> ClientA
x2 4371844592 4.23 4.23 <class '__main__.NamedFloat'> ClientA
y 4371844208 4.23 4.23 <class '__main__.NamedFloat'> ClientB
y2 4371854624 4.23 4.23 <class '__main__.NamedFloat'> ClientB
© www.soinside.com 2019 - 2024. All rights reserved.