“id”在Python中是一个糟糕的变量名。

204

为什么在Python中将变量命名为id是不好的?


38
大多数人在与内置关键字发生冲突的标识符后面添加下划线:例如id_,map_,list_,filter_等。 - cdleary
7
一个更加隐秘的解决方案是使用一个变量 ID - Simon Kuang
108
更好的问题应该是...到底哪位天才认为使用如此普通、通用的名称作为内置函数是个好主意? - Basic
1
@Basic 这是一个标准的事情,人们期望函数的名称与其功能相对应。更长的“identity”可能会产生歧义(因为它也可以表示接受一个参数并返回相同值的函数)。 - Karl Knechtel
9个回答

188

id() 是一个基本内部函数:

在模块 __builtin__ 中,内置函数 id 的帮助信息如下:

id(...)

    id(object) -> integer

    Return the identity of an object.  This is guaranteed to be unique among
    simultaneously existing objects.  (Hint: it's the object's memory
    address.)
通常,使用任何语言中关键字或内置函数名称相同的变量名都不是一个好主意,即使允许这样做。

3
好的,对于"id"你是正确的,但是“in general..." 的评论仍然适用,你不这么认为吗? - Kevin Little
8
对于模块全局变量,我肯定会避免使用它。对于被限制在本地作用域的变量,如果您可以确定同一函数不会需要使用内置函数,那么这并不是我担心的事情。 - bobince
51
@EliCourtwright 我希望他们把它移除掉。这是一个名字不当的方法!一个普通、常见的名称,在成千上万个地方都被使用(在上下文中给出意义)。所以有人决定在没有上下文的情况下将其用作全局名称? - Basic
3
令人惊讶的是,Google的Python正则表达式教程(https://developers.google.com/edu/python/regular-expressions)使用了`str ='an example word:cat!!'`。在任何PEP中有没有规定不要这样做的内容? - wordsforthewise
1
@MattS 作为参数名称是可以的,因为阴影在函数范围内,所以你不需要担心它。我能想到的唯一混淆的可能性是如果你在调用之外使用参数名称,比如 object = []; np.array(object) - wjandrea
显示剩余4条评论

113
在Python代码的PEP 8 - 风格指南中,描述:命名风格部分给出了以下指导:
  • single_trailing_underscore_ :按照惯例用于避免与Python关键字冲突,例如:
  • Tkinter.Toplevel(master, class_='ClassName')

因此,回答这个问题,一个应用了这个指南的示例是:
id_ = 42
包括在变量名中添加尾随下划线可以使意图清晰(对于熟悉PEP 8指南的人来说)。

3
这并没有回答实际问题,但是因为遵循了PEP-8的命名规范,给你点赞(+1)。 - ege
7
建议不错,但 id 是内置函数而非关键字,并且这并没有解释为什么掩盖内置函数是不好的。 - wjandrea
@wjandrea,将内置函数名作为变量名是不好的编程习惯,因为这会使代码难以阅读和维护。你可以自由地赋值print = 123,但是在代码后面,你或者你的同事会惊讶于为什么print('Hello World')会引发TypeError异常。PEP8提供了命名此类变量的推荐方式。 - Jeyekomon
@Jeyekomon 这在PEP8中的哪里? - wjandrea
2
@wjandrea PEP8并没有明确说明在与内置变量冲突的情况下如何命名您的变量。这取决于您找到适合自己的解决方案。您可以使用三个尾随下划线来命名变量。但是,由于没有根据您所遮蔽的内容改变命名约定的好理由,因此每个明智的人都会使用与关键字冲突时相同的命名约定。我想知道这其中有什么难以理解的。 - Jeyekomon

61

id 是一个内置函数,它提供了对象的标识符(在 CPython 中也是其内存地址)。如果你给自己的函数命名为 id,那么你将不得不使用 builtins.id 来获取原始函数(或者在 CPython 中使用 __builtins__.id)。在除了小型脚本之外的任何情况下,全局重命名 id 都会令人困惑。

然而,只要使用是局部的,重用内置名称作为变量并不是那么糟糕。Python 有很多内置函数,这些函数 (1) 具有常见的名称,(2) 你也不会经常使用。将它们用作局部变量或对象成员是可以的,因为从上下文中很明显你正在做什么:

例如:

def numbered(filename):
    with open(filename) as file:
        for i, input in enumerate(file):
            print("%s:\t%s" % (i, input), end='')

一些具有诱人名称的内置函数:


9
PEP 8是Python编码规范的一部分,最新更新于2013年8月1日。根据该规范,为了避免潜在的混淆,建议在变量名后面简单地添加下划线“_”。请参考我的答案 - DavidRR
2
值得注意的是,返回对象内存地址的id函数是CPython实现的细节。同样值得注意的是,该函数仅需要为任何两个存在的对象返回不同的数字。如果一个对象被垃圾回收,它的id可能会被回收利用。 - Zac Crites
@Zac 谢谢!我编辑了答案,加入了有关内存地址的说明和一个链接,以便人们可以阅读更多信息。 - wjandrea
1
仅供参考:在Python 3中,file不再是内置的(虽然大多数语法高亮器仍将其视为内置)。 - CrazyChucky

60

我可能会说些不太受欢迎的话: id() 是一个相当专业的内置函数,在业务逻辑中很少使用。因此,如果在紧凑且精心编写的函数中使用它作为变量名,并且清楚地表明 id 不表示内置函数,那么我认为这并没有问题。


1
回应:id是一个相当专业的内置函数,很少在业务逻辑中使用。因此,在紧密而精心编写的函数中使用它作为变量名并不成问题,其中清楚地表明id并不意味着内置函数。虽然这是正确的,但最好对这个变量名更具体化,而不仅仅是“id”。许多东西都有ID(特别是如果您正在使用RDBMS),正如Tim Peters的《Python之禅》的第二行告诉我们的那样:“显式优于隐式”。通过运行“import this”查看其余部分。 - Ross
11
如果有可能的话,我仍然会尽量避免这种情况。即使没有其他原因,也是为了不听同事们的抱怨。 :-) - Jason Baker
4
完全同意:在一个小的函数中(因此作用域很小),将变量命名为“id”是无害的。很少有人使用id内置方法。尽管如此,当我的一个同事用本地变量覆盖了list内置方法时,我还是花了一些时间才明白。因此,其他人提到的一般规则仍然有意义。 - silviot
1
在我看来,几乎可以在任何地方不使用 id(除了滥用情况之外,我唯一能想象到的使用它的时候是间接使用 x is y 身份运算符,其中 Python 基本上为您执行 id(x) == id(y)(即您不需要调用它...)。我会将 id 归类为内置函数,并且当您在模块中确实需要它时,请使其超级明确并 import builtins 并将其称为 builtins.id - Nick T

7
其他人提到这很令人困惑,但我想进一步解释为什么。这里有一个例子,基于一个真实故事。基本上,我写了一个类,接受一个id参数,但后来尝试使用内置的id
class Employee:
    def __init__(self, name, id):
        """Create employee, with their name and badge id."""
        self.name = name
        self.id = id
        # ... lots more code, making you forget about the parameter names
        print('Created', type(self).__name__, repr(name), 'at', hex(id(self)))

tay = Employee('Taylor Swift', 1985)

预期输出:

Created Employee 'Taylor Swift' at 0x7efde30ae910

实际输出:
Traceback (most recent call last):
  File "company.py", line 9, in <module>
    tay = Employee('Taylor Swift', 1985)
  File "company.py", line 7, in __init__
    print('Created', type(self).__name__, repr(name), 'at', hex(id(self)))
TypeError: 'int' object is not callable

哎呀?我在哪里试图调用一个整数?这些都是内置函数...
如果我把它命名为“badge_id”或“id_”,我就不会遇到这个问题。
更新:幸运的是,在Python 3.11+中,这个错误的部分更清晰了。
    print('Created', type(self).__name__, repr(name), 'at', hex(id(self)))
                                                                ^^^^^^^^

5

命名任何变量为内置函数都是不好的。其中一个原因是因为对于不知道名称被覆盖的读者来说,这可能会造成困惑。


2

id是Python中的内置函数。给id赋值会覆盖该函数。最好要么添加前缀,例如some_id,要么使用不同的大小写,例如ID

这个内置函数接受一个参数并返回你传入对象的内存地址整数(在CPython中)。

>>> id(1)
9787760
>>> x = 1
>>> id(x)
9787760

2
请注意,您可以将类属性或方法命名为“id”,这不会影响内置函数。 - Toni Ruža

-2
因为它是一个内置函数的名称。

-6

由于Python是一种动态语言,通常不建议给变量和函数取相同的名称。在Python中,id()是一个函数,因此不建议使用名为id的变量。请记住,这适用于您可能使用的所有函数...变量不应该与函数同名。


4
由于Python是一种动态语言,通常不建议给变量和函数取相同的名字。这与它是动态语言无关。如果您指的是在同一作用域内将属性命名为其他对象相同的名称,我也不赞成。例如,您可能有一个名为“Key”的类,该类的实例称为“key”,另一个对象的属性也称为“key”,例如,“door.key”。 - Purrell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接