Python namedtuple的可变默认参数

but5z9lq  于 2023-04-04  发布在  Python
关注(0)|答案(4)|浏览(160)

我偶然发现了一种让namedtuples使用here的默认参数的简洁方法。

from collections import namedtuple
Node = namedtuple('Node', 'val left right')
Node.__new__.__defaults__ = (None, None, None)
Node()

节点(瓦尔=None,left=None,right=None)
如果你想让'right'的默认值是一个空的list,你会怎么做?你可能知道,使用一个可变的默认参数,比如一个list,是不可以的。
有没有一个简单的方法来实现这一点?

p8h8hvxi

p8h8hvxi1#

你不能这样做,因为__defaults__中的值是实际的默认值。也就是说,如果你写了一个有someargument=None的函数,然后用someargument = [] if someargument is None else someargument或类似的东西检查函数体,对应的__defaults__条目仍然是None。换句话说,你可以用一个函数来做这件事,因为在一个函数中,你可以编写代码来做任何你想做的事情,但是你不能在一个namedtuple中编写自定义代码。
但如果你想要默认值,只需创建一个具有该逻辑的函数,然后创建正确的namedtuple:

def makeNode(val=None, left=None, right=None):
    if right is None:
        val = []
    return Node(val, left, right)
ha5z0ras

ha5z0ras2#

the accepted answer中给出的方法工作得很好。我看到的唯一缺点是,一个人必须同时 * 知道 *(在其他用户的情况下)和 * 记住 * 使用工厂函数而不是命名元组类-无论是在创建对象时,还是在做这样的事情时:

isinstance(node, Node) #  success
isinstance(node, makeNode) #  misery

解决这个问题的一个方法可能是做一些如下所示的事情。

NodeBase = nt('NodeBase', 'val left right')
NodeBase.__new__.__defaults__ = (None, None, None)

class Node(NodeBase):
    '''A namedtuple defined as:

    Node(val, left, right)

    with default values of (None, None, [])'''
    __slots__ = ()
    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls, *args, **kwargs)
            if obj.right is None:
                obj = obj._replace(right = [])
            return obj
chy5wohz

chy5wohz3#

自从这个问题被提出以来,dataclasses模块已经被提出并被Python接受。这个模块与namedtuples有很多重叠的用例,但具有更多的灵活性和功能。特别是,当你想要为可变字段指定默认值时,你可以指定一个工厂函数。

from typing import List
from dataclasses import dataclass, field

@dataclass
class Node:
    val: str
    left: List["Node"] = field(default_factory=list)
    right: List["Node"] = field(default_factory=list)

在一个数据类中,你指定了不同字段的类型,所以在这个例子中,我必须填写几个空格,并假设val是一个字符串,leftright都是其他Node对象的列表。
由于rightleft是类定义中赋值的左手,因此当我们初始化Node对象时,它们是可选参数。此外,我们可以提供默认值,但我们提供了一个默认工厂,这是一个函数,每当我们初始化Node对象而不指定这些字段时,它都会被调用0个参数。
例如:

node_1 = Node('foo')
# Node(val='foo', left=[], right=[])

node_2 = Node('bar', left=[node_1])
# Node(val='bar', left=[Node(val='foo', left=[], right=[])], right=[])

node_3 = Node('baz')
# Node(val='baz', left=[], right=[])

node_4 = Node('quux', left=[node_2], right=[node_3])
# Node(val='quux', left=[Node(val='bar', left=[Node(val='foo', left=[], right=[])], right=[])], right=[Node(val='baz', left=[], right=[])])

就我个人而言,我发现自己在任何应用程序中使用dataclasses而不是namedtuples,我需要的不仅仅是最薄的数据容器。

flvlnr44

flvlnr444#

Rick Teachey在实现上做了一点小改动,默认值可以在类外设置:

NodeBase = namedtuple('NodeBase', 'val left right')

class Node(NodeBase):
    __slots__ = ()
    def __new__(cls, *, right=[], **kwargs):
        obj = super().__new__(cls, right=right, **kwargs)
        return obj

#IMPLEMENTATION
kw = {'val': 1, 'left':12}

m  = Node(**kw) 
# outputs Node(val=1, left=12, right=[])

相关问题