Python 命名元组的语法

Python syntax for namedtuple

我看到命名元组的 Python 语法是:

Point = namedtuple('Point', ['x', 'y'])

为什么不这么简单:

Point = namedtuple(['x','y'])

它不那么冗长,

class 应该是有名有姓的。而且它看不到你分配给它的变量,所以它不能使用那个。另外你可以叫它别的东西,甚至什么都不叫:

c = namedtuple('Point', ['x', 'y'])
do_something_with_this(namedtuple('Point', ['x', 'y']))

说到更简单的语法,你也可以这样写:

namedtuple('Point', 'x y')

namedtuple 是一个工厂,返回一个 class。只考虑表达式:

namedtuple(['x','y'])

此表达式返回的 class 的名称是什么?

因为namedtuple是returns一个class的函数。为此,实际上是 rendering a string template 并调用 eval。要构建字符串,它需要事先提供所有参数。

您需要将相关上下文作为参数包含在 namedtuple 中才能实现。如果您不提供 class 名称参数,则需要猜测。编程语言不喜欢猜测。

根据 Python 语言的规则,此表达式中的 namedtuple 函数..

>>> Point = namedtuple(['x','y'])

..无权访问表达式执行后存储结果的变量名称 (Point)。它只能访问作为其参数提供的列表的元素(以及之前定义的变量)。

一般来说,对象并不知道它们被赋值给了哪些变量:

# Create three variables referring to an OrderedPair class

tmp = namedtuple('OrderedPair', ['x','y'])  # create a new class with metadata
Point = tmp                                 # assign the class to a variable
Coordinate = tmp                            # assign the class to another var

这是命名元组的问题。我们必须将 class 名称传递给 namedtuple() 工厂函数,以便为 class 提供有用的名称、文档字符串和 __repr__ 所有这些里面都有 class 名字。

您觉得奇怪的原因是普通函数和 class 定义的处理方式不同。 Python 对 defclass 有特殊语法,它不仅创建函数和 classes,而且分配它们的元数据(名称和文档字符串)并将结果分配给变量.

考虑一下 def 的作用:

def square(x):
    'Return a value times itself'
    return x * x

关键字 def 为您处理几件事(注意 "square" 一词将被使用两次):

tmp = lambda x: x*x                         # create a function object
tmp.__name__ = 'square'                     # assign its metadata
tmp.__doc__ = 'Return a value times itself'
square = tmp                                # assign the function to a variable

classes也是如此。 class 关键字负责多个操作,否则这些操作会重复 class 名称:

class Dog(object):
    def bark(self):
        return 'Woof!'

基础步骤重复class名称(注意"Dog"这个词用了两次):

Dog = type('Dog', (object,), {'bark': lambda self: 'Woof'})

命名元组没有像 defclass 这样的特殊关键字的优势,因此它必须自己完成第一步。分配给变量的最后一步属于您。如果您考虑一下,命名元组方式是 Python 中的规范,而 defclass 是例外:

 survey_results = open('survey_results')      # is this really a duplication?
 company_db = sqlite3.connect('company.db')   # is this really a duplication?
 www_python_org = urllib.urlopen('http://www.python.org')
 radius = property(radius)

您不是第一个注意到这一点的人。 PEP 359 建议我们添加一个新关键字 make,它可以允许任何可调用对象获得 defclassimport 的自动分配功能。

make <callable> <name> <tuple>:
    <block>

将被翻译成作业:

<name> = <callable>("<name>", <tuple>, <namespace>)

最后,Guido 不喜欢 "make" 提议,因为它造成的问题比解决的问题多(毕竟,它只是让你免于进行单个变量赋值)。

希望能帮助您了解为什么 class 名称被写了两次。这不是真正的重复。 class 名称的字符串形式用于在创建对象时分配元数据,而单独的变量分配只是为您提供了一种引用该对象的方法。虽然它们通常是同名的,但它们不一定是 :-)