1

我目前正在尝试为 python 中的内置 min-max 函数编写等效代码,并且我的代码返回了一个我完全不理解的非常奇怪的异常:

TypeError: 'generator' object is not subscriptable, min, 7, , 9

当我尝试时:

min(abs(i) for i in range(-10, 10))

这是我的代码:

def min(*args, **kwargs):
key = kwargs.get("key", None)
argv=0
for i in args:
    argv+=1
    if argv == 1 and (type(args) is list or type(args) is tuple or type(args) is str):
        min=args[0][0]
        for i in args[0]:
            if key != None:
                if key(i) < key(min):
                    min = i
            else:
                if i < min:
                    min = i
        return min
    else:
        min=args[0]
        for i in args:
            if key != None:
                if key(i) < key(min):
                    min = i
            else:
                if i < min:
                    min = i
        return min

根据文档,我应该能够迭代生成器......

4

3 回答 3

3

这是我的实现:

def max(*args, **kwargs):
    key = kwargs.get("key", lambda x: x)
    if len(args) == 1:
        args = args[0]
    maxi = None
    for i in args:
        if maxi == None or key(i) > key(maxi):
            maxi = i
    return maxi

def min(*args, **kwargs):
    key = kwargs.get("key", lambda x: x)
    if len(args) == 1:
        args = args[0]
    mini = None
    for i in args:
        if mini == None or key(i) < key(mini):
            mini = i
    return mini

比预览帖子更简洁一点。

于 2016-08-14T23:06:04.313 回答
2

min您遇到的问题是由于具有两个函数签名的事实。从它的文档字符串:

min(...)
    min(iterable[, key=func]) -> value
    min(a, b, c, ...[, key=func]) -> value

因此,它将接受单个位置参数(一个可迭代的,您需要比较的值)或几个位置参数,这些参数本身就是值。我认为您需要在函数开始时测试您所处的模式。只需简单地将一个参数版本转换为多参数版本非常容易args = args[0]

这是我实现该功能的尝试。key是一个仅限关键字的参数,因为它出现在*args.

def min(*args, key=None):    # args is a tuple of the positional arguments initially
    if len(args) == 1:       # if there's just one, assume it's an iterable of values
        args = args[0]       # replace args with the iterable

    it = iter(args)          # get an iterator

    try:
        min_val = next(it)   # take the first value from the iterator
    except StopIteration:
        raise ValueError("min() called with no values")

    if key is None:       # separate loops for key=None and otherwise, for efficiency
        for val in it:    # loop on the iterator, which has already yielded one value
            if val < min_val
                min_val = val
    else:
        min_keyval = key(min_val)    # initialize the minimum keyval
        for val in it:
            keyval = key(val)
            if keyval < min_keyval:  # compare keyvals, rather than regular values
                min_val = val
                min_keyval = keyval

    return min_val

这里有一些测试:

>>> min([4, 5, 3, 2])
2
>>> min([1, 4, 5, 3, 2])
1
>>> min(4, 5, 3, 2)
2
>>> min(4, 5, 3, 2, 1)
1
>>> min(4, 5, 3, 2, key=lambda x: -x)
5
>>> min(4, -5, 3, -2, key=abs)
-2
>>> min(abs(i) for i in range(-10, 10))
0
于 2014-08-11T22:10:21.770 回答
0

所讨论的功能有很多共同点。实际上,唯一的区别是比较(<vs >)。鉴于这一事实,我们可以实现查找和元素的通用函数,它将使用作为参数传递的比较函数。最小值和最大值示例可能如下所示:

def lessThan(val1, val2):
  return val1 < val2

def greaterThan(val1, val2):
  return val1 > val2


def find(cmp, *args, **kwargs):
  if len(args) < 1:
    return None

  key = kwargs.get("key", lambda x: x)
  arguments = list(args[0]) if len(args) == 1 else args
  result = arguments[0]

  for val in arguments:
    if cmp(key(val), key(result)):
      result = val

  return result


min = lambda *args, **kwargs: find(lessThan, *args, **kwargs)
max = lambda *args, **kwargs: find(greaterThan, *args, **kwargs)

一些测试:

>>> min(3, 2)
2
>>> max(3, 2)
3
>>> max([1, 2, 0, 3, 4])
4
>>> min("hello")
'e'
>>> max(2.2, 5.6, 5.9, key=int)
5.6
>>> min([[1, 2], [3, 4], [9, 0]], key=lambda x: x[1])
[9, 0]
>>> min((9,))
9
>>> max(range(6))
5
>>> min(abs(i) for i in range(-10, 10))
0
>>> max([1, 2, 3], [5, 6], [7], [0, 0, 0, 1])
[7]
于 2016-12-13T00:25:50.147 回答