python - 可选关键字参数的命名元组和默认值

标签 python default-value namedtuple optional-arguments

我正在尝试将一个较长的空心“数据”类转换为一个命名元组。我的类(class)目前看起来像这样:

class Node(object):
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

转换成 namedtuple 后的样子:

from collections import namedtuple
Node = namedtuple('Node', 'val left right')

但是这里有一个问题。我原来的类只允许我传入一个值,并通过使用命名/关键字参数的默认值来处理默认值。比如:

class BinaryTree(object):
    def __init__(self, val):
        self.root = Node(val)

但这不适用于我重构的命名元组,因为它希望我传递所有字段。我当然可以将 Node(val) 的出现替换为 Node(val, None, None) 但这不是我喜欢的。

那么是否有一个好技巧可以使我的重写成功而不会增加大量代码复杂性(元编程),还是我应该吞下药丸并继续“搜索和替换”? :)

最佳答案

Python 3.7

使用 defaults 参数。

>>> from collections import namedtuple
>>> fields = ('val', 'left', 'right')
>>> Node = namedtuple('Node', fields, defaults=(None,) * len(fields))
>>> Node()
Node(val=None, left=None, right=None)

或者更好的是,使用新的 dataclasses库,比 namedtuple 好很多。

>>> from dataclasses import dataclass
>>> from typing import Any
>>> @dataclass
... class Node:
...     val: Any = None
...     left: 'Node' = None
...     right: 'Node' = None
>>> Node()
Node(val=None, left=None, right=None)

在 Python 3.7 之前

Node.__new__.__defaults__ 设置为默认值。

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

在 Python 2.6 之前

Node.__new__.func_defaults 设置为默认值。

>>> from collections import namedtuple
>>> Node = namedtuple('Node', 'val left right')
>>> Node.__new__.func_defaults = (None,) * len(Node._fields)
>>> Node()
Node(val=None, left=None, right=None)

订单

在所有版本的 Python 中,如果您设置的默认值少于命名元组中存在的默认值,则默认值将应用于最右边的参数。这允许您保留一些参数作为必需参数。

>>> Node.__new__.__defaults__ = (1,2)
>>> Node()
Traceback (most recent call last):
  ...
TypeError: __new__() missing 1 required positional argument: 'val'
>>> Node(3)
Node(val=3, left=1, right=2)

Python 2.6 到 3.6 的包装器

这里有一个包装器,它甚至可以让您(可选地)将默认值设置为 None 以外的值。这不支持必需的参数。

import collections
def namedtuple_with_defaults(typename, field_names, default_values=()):
    T = collections.namedtuple(typename, field_names)
    T.__new__.__defaults__ = (None,) * len(T._fields)
    if isinstance(default_values, collections.Mapping):
        prototype = T(**default_values)
    else:
        prototype = T(*default_values)
    T.__new__.__defaults__ = tuple(prototype)
    return T

例子:

>>> Node = namedtuple_with_defaults('Node', 'val left right')
>>> Node()
Node(val=None, left=None, right=None)
>>> Node = namedtuple_with_defaults('Node', 'val left right', [1, 2, 3])
>>> Node()
Node(val=1, left=2, right=3)
>>> Node = namedtuple_with_defaults('Node', 'val left right', {'right':7})
>>> Node()
Node(val=None, left=None, right=7)
>>> Node(4)
Node(val=4, left=None, right=7)

关于python - 可选关键字参数的命名元组和默认值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11351032/

相关文章:

python - 无效参数异常 : Message: invalid argument: 'using' must be a string

c++ - 初始化类成员 - 默认值还是成员初始化列表?

Python3 — 替换动态选择的命名元组字段

python - 枚举和命名元组有什么区别?

html - 更改输入类型 ="file"中的默认文本?

python - 如何将字段添加到 namedtuple?

python - 糊糊的 : Getting the name of the biggest PyObjects in a Python program sorted by size

python - 有没有办法删除 python 中的命令提示符 shell?

python - 在这种情况下,itertools 可以用于未指定的维数吗?

python - 具有不同数量的参数 (*args) 和具有默认值的参数的函数?