Pythonic方式实现三个相似的整数范围运算符?

Nic*_*zet 2 python operators

我正在研究一个循环问题.在这个问题中,我们将对象放在一个大小的环上MAX,并从(0到MAX-1)分配ID.

我有三个简单的函数来测试范围包含.inRange(i,j,k)测试i是否在循环区间[j,k [(Mnemonic is i inRange(j,k))中.并且我对范围有相同的] j,k [和] j,k].

这三种方法中的代码看起来从一种方法复制到另一种方法:

def inRange(i,j,k):
    """
    Returns True if i in [j, k[
    * 0 <= i, j, k < MAX
    * no order is assumed between j and k: we can have k < j
    """
    if j <= k:
        return j <= i < k
    # j > k :
    return j <= i or i < k

def inStrictRange(i,j,k):
    """
    Returns True if i in ]j, k[
    * 0 <= i, j, k < MAX
    * no order is assumed between j and k: we can have k < j
    """
    if j <= k:
        return j < i < k
    # j > k :
    return j < i or i < k

def inRange2(i,j,k):
    """
    Returns True if i in ]j, k]
    * 0 <= i, j, k < MAX
    * no order is assumed between j and k: we can have k < j
    """
    if j <= k:
        return j < i <= k
    # j > k :
    return j < i or i <= k
Run Code Online (Sandbox Code Playgroud)

你知道任何更简洁的方法来实现这三种方法吗?毕竟,只有经营者正在改变?!

在考虑了更好的解决方案之后,我提出了:

from operator import lt, le
def _compare(i,j,k, op1, op2):
    if j <= k:
        return op1(j,i) and op2(i,k)
    return op1(j,i) or op2(i,k)

def inRange(i,j,k):
    return _compare(i,j,k, le, lt)
def inStrictRange(i,j,k):
    return _compare(i,j,k, lt, lt)
def inRange2(i,j,k):
    return _compare(i,j,k, lt, le)
Run Code Online (Sandbox Code Playgroud)

有没有更好的?你能想出更直观的东西吗?简而言之,编写这三个运算符的Pythonic方法是什么?

另外,我讨厌inRange,inStrictRange,inRange2的名字,但我想不出清晰的名字.有任何想法吗?

谢谢.

Wes*_*ley 7

两个禅宗的Python原则跳跃于脑海:

  • 简单比复杂更好.
  • 应该有一种 - 最好只有一种 - 显而易见的方法.

range

Python的内置函数range(start, end)从生成列表startend.1该列表的第一个元素是start,最后一个元素是end - 1.

没有range_strict功能或inclusive_range功能.当我开始使用Python时,这对我来说非常尴尬.("我只是想从一个列表a,以b包容的!有多难的是,圭多?")然而,在调用中使用的常规range功能,简单易记,而且缺乏的多种功能,可以轻松准确地记得如何每次都生成一个范围.

建议

你可能已经猜到了,我的建议是只创建一个函数来测试i是否在[ j,k ] 范围内.事实上,我的建议是只保留现有的inRange功能.

(由于您的问题特别提到了Pythonicity,我建议您将该函数命名为in_range更适合Python样式指南.)

理由

为什么这是个好主意?

  • 单一功能很容易理解.学习如何使用它非常容易.

    当然,对于你的三个起始功能中的每一个都可以这样说.到现在为止还挺好.

  • 只有一个功能需要学习.没有三个函数具有必然相似的名称.

    鉴于您的三个函数的名称和行为相似,有时您可能会使用错误的函数.事实上,除了边缘情况之外,函数返回相同的值,这可能导致难以找到的逐个错误.只使一个功能可用,你知道你不会犯这样的错误.

  • 该功能易于编辑.

    您不太可能需要调试或编辑这么简单的代码.但是,如果您需要这样做,则只需编辑此功能.使用原来的三个功能,您必须在三个位置进行相同的编辑.通过自行回答中修改后的代码,操作员混淆后代码变得不那么直观.

  • 范围的"大小"是显而易见的.

    对于您将使用的给定环inRange(i, j, k),很明显有多少元素将被范围[ j,k)覆盖.这是代码.

    if j <= k:
        size = k - j
    if j > k:
        size = k - j + MAX
    
    Run Code Online (Sandbox Code Playgroud)

    所以

    size = (k - j) % MAX
    
    Run Code Online (Sandbox Code Playgroud)

注意事项

我从一个完全通用的角度来看待这个问题,例如为一个公开发布的库编写函数的人.由于我不知道您的问题域,我不能说这是否是一个实用的解决方案.

使用此解决方案可能意味着对调用这些函数的代码进行相当多的重构.查看此代码,看看编辑是否过于困难或乏味.


1:实际上,它是range([start], end, [step]).我相信你明白我的意思.


e-s*_*tis 5

Pythonic的方法是选择可读性,因此保留3种方法,就像它们在开始时一样.

它不像是巨大的方法,或者有数千种方法,或者你必须动态生成它们.