python

时间:2017-03-01 22:30:58

标签: python arrays callback

我希望能够定义一个python函数,它执行某种数据结构遍历并在每一步执行一些操作(在回调中定义)。这是一个简单的例子来说明。

def min_value(list):
   m = 0
   for i in range(0, len(list)):
     if list[i] < m: m = list[i]
   return m

这个例子很简单,但如果我遍历一个n维数组,一个numpy数组,或者我想定义一个更复杂的步进数据结构的方法,那就变得更复杂了。

我正在寻找一个&#34; pythonic&#34;类似于以下JavaScript做同样的事情。

traverse = function(list, callback) {
   for(i = 0; i < list.length; i++) {
      callback(list[i])
   }
}

min_value = function(list) {
   m = 0
   traverse(list, function(element) {
      if(element < m) m = element
   });
}

如果我想要一个函数max_value(list),只需将一行调整为if(element > m) m = element即可,而无需复制/粘贴遍历函数。在python中执行此操作的最佳方法是什么?

编辑(答案):在这里,我使用下面接受的答案来说明我的原始JS示例如何用python 3编写。有明显更好的方法来查找列表的最小值标量,但这是我正在寻找的模式。

def traverse(list, callback):
   for i in range(0, len(list)):
      callback(list[i])

def min_value(list):
   m = 0

   def update_min(val):
      nonlocal m
      if(val < m): m = val

   traverse(list, update_min)
   return m

编辑(复杂示例):这是我的用例的更复杂和直接的示例。我有一个图像,我想在焦点区域进行一些处理&#34;图像。让我们说,例如,我想找到图像中最暗的10x10,20x20,30x30等像素区域。我的图像是一个numpy数组。我会使用&#34; bastard&#34;多行lambda来说明我喜欢做什么,尽管据我所知,lambdas不能以这种方式使用。

在python中:

# find the coordinates and of darkest region
def darkest_region(image, fsize):
   darkest_coords = [0, 0]
   darkest_avg = 256

   # illegal lambda
   g = lambda x, y, r:
      # r is an fsize x fsize region
      avg_darkness = # blah blah, traverse and average pixels
      if(avg_darkness < darkest_avg): darkest_coords = [x, y]

   focus_scan(image, fsize, g)
   return darkest_coords

# scan all regions of fsize x fsize
def focus_scan(image, fsize, callback):
   height, width = image.shape[:2]
   for y in range(0, height - fsize):
     for x in range(0, width - fsize):
        focus = image[y:y+fsize, x:x+fsize]
        callback(x, y, focus)

鉴于我不能有这样的多行lambda,我认为我需要做的是对focus_scan的参数和返回值有点看中,以适应各种各样的可能的输入/输出。在这个例子中,我可以传递焦点扫描darkest_avg并让它返回我正在寻找的坐标,但是我可能想要传递除标量之外的其他东西,或者让它返回更复杂的数据结构。我想我必须做类似的事情:

def focus_scan(image, fsize, callback, args):
   ... # loopy loops
      some_result = callback([x, y, focus], args)

   return some_result

我喜欢我可以在其他编程语言中使用的内联函数方法,但它看起来并不像python中常见的模式。

3 个答案:

答案 0 :(得分:3)

您可以完全将函数传递给函数,就像在JS中一样。

def myFancyTraversal(data, callback):
  result = 0
  for element in data:  # or anything more fancy
    result = callback(element, result)
  return result

但在重新发明轮子之前,请确保您能够熟练使用list comprehensionsmapreducelambda

答案 1 :(得分:3)

只使用普通函数而不是多行lambda。要访问darkest_coords变量,您可以在Python 3中使用nonlocal关键字。在Python 2中,您必须改变列表,因为nonlocal关键字不可用。

def darkest_region(image, fsize):
    """Find the coordinates of darkest region."""
    darkest_coords = [0, 0]
    darkest_avg = 256

    def g(x, y, r):
        nonlocal darkest_coords
        # r is an fsize x fsize region
        avg_darkness = # blah blah, traverse and average pixels
        if avg_darkness < darkest_avg:
            darkest_coords = [x, y]

    focus_scan(image, fsize, g)
    return darkest_coords


def focus_scan(image, fsize, callback):
    """Scan all regions of fsize x fsize."""
    height, width = image.shape[:2]
    for y in range(0, height - fsize):
        for x in range(0, width - fsize):
            focus = image[y:y+fsize, x:x+fsize]
            callback(x, y, focus)

答案 2 :(得分:2)

对于您的情况,我只使用内置min函数:

>>> min([1, 2, 3, 4, 5])
1

但是如果你想要一个内联函数,你可以使用lambdamapmap函数本质上是traverse函数的内置版本。

def findMin(arr):
    m = 100 #Must be a value larger than can be in your list
    min_func = lambda el: el if el < m else m #Use an inline lambda to declare a function.
    for val in map(min_func, arr): #Returns the function called on 
                                   #every item in the array
        m = val #Set m to the new lowest value
    return m

min_func lambda相当于:

def min_func(el):
    if el < m:
        return el
    return m