【问题标题】:Is it OK to re-use the names of Python's built-in functions?是否可以重用 Python 内置函数的名称?
【发布时间】:2015-06-25 05:58:02
【问题描述】:

正如目前在this question 中讨论的那样,我正在编写内置rangexrange 函数的包容性版本。如果将它们放在名为 inclusive 的模块中,我会看到两种可能的方法来命名函数本身:

  1. 将函数命名为inclusive_rangeinclusive_xrange,以便客户端代码可以按如下方式使用它们:

    from inclusive import *
    ...
    inclusive_range(...)
    
  2. 将函数命名为 rangexrange

    import inclusive
    ...
    inclusive.range(...)
    

对我来说,客户端代码的第二个示例看起来更好,但我应该避免以这种方式重复使用内置名称吗?

【问题讨论】:

  • 好问题。第一个例子不好。如果我要避免使用相同的名称,我会称它们为inclusive.irange()inclusive.ixrange()。但也许使用range()xrange() 是可以的。

标签: python naming-conventions


【解决方案1】:

这变成了一个不同选项的列表,而不是一个直接的答案。然而,有两个概念是最重要的:

  • 用户应该能够替换rangexrange 如果他们明确选择;但是
  • 用户不应隐式/意外替换rangexrange

读者应该始终清楚他们的代码在哪里使用内置函数以及在哪里使用替换。

因此,我在下面概述的所有选项防止通配符导入 (from inclusive import *) 遮蔽内置插件。哪个是您的最佳选择取决于您是否将替换内置插件视为模块的主要用途或次要用途。用户通常会想要替换内置插件,还是将它们一起使用?


在你的位置上,我想我会做以下事情:

inclusive.py:

"""Inclusive versions of range and xrange."""

__all__ = []  # block 'from inclusive import *'

old_range, old_xrange = range, xrange  # alias for access

def range(...):  # shadow the built-in
    ...

def xrange(...):  # ditto
    ...

这允许用户:

  1. import inclusive 和访问 inclusive.rangeinclusive.xrange;
  2. from inclusive import range, xrange,明显替换了内置,没有任何不愉快的副作用;或
  3. from inclusive import range as irange, xrange as ixrange 一起使用内置版本和替换版本。

__all__ 定义为一个空列表意味着from inclusive import * 不会悄悄地隐藏内置函数。


如果你真的想要,你可以添加:

irange, ixrange = range, xrange

inclusive.py 的末尾并将__all__ 定义修改为:

__all__ = ['irange', 'ixrange']

现在用户有两个额外的选择:

  • from inclusive import irange, ixrange(比上面选项 3 中的手动别名功能稍微简单一些);和
  • from inclusive import *(与上面的结果相同,仍然没有隐式隐藏内置函数)。

当然,您可以完全采用其他方式 - 将您自己的版本命名为 irangeixrange,然后如果用户真的想要替换内置插件,他们将不得不:

from inclusive import irange as range, ixrange as xrange

这不需要您定义 __all__ 以避免通配符导入遮蔽内置函数。

【讨论】:

  • 可能还值得指出的是,您始终可以使用 __builtins__.range__builtins__.xrange__builtins__ 恢复原始的 rangexrange 函数。
  • 感谢您的详细回答,特别是顶部提到的两个概念 - 它们当然是合适的。我也很欣赏实现这些概念的可能方法列表,尽管我还没有确切决定使用哪个选项。
  • 关于“用户一般会想要替换内置插件,还是一起使用它们?”。我希望替换内置函数很容易引起混淆,所以不要指望这是一个常见的用例。
【解决方案2】:

您应该避免以这种方式重用内置函数名称,因为这可能会破坏您所依赖的任何库,并且会让其他人(或将来的您)阅读和维护非常混乱。但是,如果您必须这样做,您可以选择这样做。

【讨论】:

  • "这可能会破坏您所依赖的任何库" - Python 小心让这种情况发生,替换内置的ins 将inclusive 的范围内,除非用户另有决定。
  • 是的,但如果你这样做from inclusive import *,那么这肯定会发生。
  • 仅在进行该导入的模块中,这就是不鼓励通配符导入的原因 - 请参阅我的答案以了解避免这种情况发生的选项(同时仍为用户提供明确 替换 rangexrange)。
  • 是的,你的回答比我的要全面得多。
【解决方案3】:

这里的问题是在你的模块中你不能调用内置的range()xrange()。您描述inclusive.range() 的方式看起来不错,但任何其他用户可能不会以相同的方式导入,他们也会遇到冲突。

inclusive.irange()inclusive.ixrange() 呢?

编辑:确实,如果您注意导入和重命名它们,您可以在自己的模块中使用range(),但这可能是另一个迹象,表明这是一种潜在的棘手方法。

【讨论】:

  • 仍然可以使用它们,但你必须在函数定义之前给它们起别名(例如old_range = range; def range(...):)。
【解决方案4】:

你可以,但这可能不是一个好主意。

问题是如果其他人使用该库,他们可能会引入副作用

 from your_lib import inclusive range

 ..... lots of code .....

 range()    # ambiguous 

【讨论】:

  • 一点也不含糊——range 仍然是内置的,包含版本是inclusive.range。只有当用户使用from your_lib.inclusive import *from your_lib.inclusive import range, xrange 时才会出现问题(在这种情况下,他们可能想要替换内置插件)。
  • 对不起,您的权利-我更改了答案以显示导入,如果导入位于顶部并且在代码中使用范围很深,这可能是一个问题。不是一个大问题,但当它真的不需要时仍然是一个潜在的陷阱
猜你喜欢
  • 2016-06-22
  • 2014-06-12
  • 2014-01-25
  • 2017-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
相关资源
最近更新 更多