我目前正在尝试为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
根据文档,我应该可以迭代生成器...
答案 0 :(得分:1)
您遇到的问题是由于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
答案 1 :(得分:1)
这是我的实施:
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
比预览帖更简洁。
答案 2 :(得分:0)
有问题的功能有很多共同之处。事实上,唯一的区别是比较(<
vs >
)。鉴于这一事实,我们可以为查找和元素实现泛型函数,它将使用作为参数传递的比较函数。 min和max示例可能如下所示:
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]