python的NamedTuple返回结构是应该使用可变默认值的少数地方之一吗?

2024-10-01 17:41:21 发布

您现在位置:Python中文网/ 问答频道 /正文

从python函数返回结构的方法已经在不同的文章中详细讨论过。两个好的herehere

但是,除非我没有注意到,否则建议的解决方案中没有一个将结构定义在其成员设置的同一位置,而是重复分配的成员列表(不干燥)或依赖于位置(容易出错)

我正在寻找一种干净利落的方法来做到这一点,既可以提高写作速度,又可以避免重复时经常出现的参数不对齐错误

下面的代码片段显示了执行此操作的三次尝试。为简洁起见,示例的结构仅包含一个元素,但其目的显然是这些结构包含多个元素

这三种方法都是干式的,在初始化返回的实例时嵌入结构定义

方法1强调了对更好方法的需要,但说明了干法语法,其中结构和填充方式(在运行时决定)位于同一位置,即dict()调用

方法2使用typing.NamedTuple并且似乎有效。但是,它使用可变的默认值来执行此操作

方法3遵循方法2的方法,使用dataclasses.dataclass而不是typing.NamedTuple。它失败了,因为前者明确禁止可变默认值,导致ValueError: mutable default is not allowed

from collections import namedtuple
from dataclasses import dataclass
from typing import NamedTuple, List, Tuple

# Method 1
def ret_dict(foo_: float, bar_: float) -> Tuple:
    return_ = dict(foo_bar=[foo_, bar_])
    _ = namedtuple('_', return_.keys())
    return _(*return_.values())


# Method 2
def ret_nt(foo_: float, bar_: float) -> 'ReturnType':
    class ReturnType(NamedTuple):
        foo_bar: List[float] = [foo_, bar_]     # Mutable default value allowed
    return ReturnType()


# Method 3
def ret_dc(foo_: float, bar_: float) -> 'ReturnType':
    @dataclass
    class ReturnType:
        foo_bar: List[float] = [foo_, bar_]   # raises ValueError: mutable default is not allowed
    return ReturnType()


def main():
    rt1 = ret_dict(1, 0)
    rt1.foo_bar.append(3)
    rt2 = ret_dict(2, 0)
    print(rt1)
    print(rt2)

    rt1 = ret_nt(1, 0)
    rt1.foo_bar.append(3)   # amending the mutable default does not affect subsequent calls
    rt2 = ret_nt(2, 0)
    print(rt1)
    print(rt2)

    rt1 = ret_dc(1, 0)
    rt1.foo_bar.append(3)  # amending the default does not affect subsequent calls
    rt2 = ret_dc(2, 0)
    print(rt1)
    print(rt2)


if __name__ == "__main__":
    main()

出现以下问题:

方法2是一种合理的Python方法吗?

一个问题是可变默认值在某种程度上是一个禁忌,当然对于函数参数来说。但是,我想知道它们在这里的使用是否合适,因为所附的代码表明这些NamedTuple默认值(可能还有整个ReturnType定义)在每次函数调用时都会被计算,这与函数参数默认值相反,在我看来,函数参数默认值只计算一次,并且永远存在(因此问题)

另一个问题是,dataclasses模块似乎已经特意明确禁止这种使用。在这种情况下,这个决定是否过于教条?或者,是否有理由防范方法2

这样效率低吗?

如果方法2的语法意味着:

1-仅在第一次通过时定义一次ReturnType

2-在每次传递时使用给定的(动态设置的)初始化调用__init__()

然而,我恐怕这可能意味着:

1-在每次传递时定义ReturnType及其默认值

2-在每次传递时使用给定的(动态设置的)初始化调用__init__()

当调用处于“紧密”循环时,是否应该担心在每次传递时重新定义chunkyReturnType的效率低下?每当在函数中定义类时,这种低效不是就存在吗?类应该在函数中定义吗

使用新的dataclasses模块(Python3.7)是否有一种(希望是好的)实现干式定义实例化的方法

最后,是否有更好的干式定义实例化语法?


Tags: 方法defaultreturn定义foobarfloatnamedtuple
1条回答
网友
1楼 · 发布于 2024-10-01 17:41:21

However, I am afraid that it may instead mean the following:

1 - Define ReturnType and its defaults on every pass

2 - call __init__() with the given (dynamically set) initialization on every pass

这就是它的意思,它需要花费大量的时间和空间。此外,它使注释无效-> 'ReturnType'需要模块级的ReturnType定义。它也会破坏酸洗

坚持使用模块级ReturnType,不要使用可变默认值。或者,如果您只想通过点表示法访问成员,而并不真正关心创建有意义的类型,那么只需使用^{}

return types.SimpleNamespace(thing=whatever, other_thing=stuff)

相关问题 更多 >

    热门问题