代码之家  ›  专栏  ›  技术社区  ›  Thamme Gowda

“lambda”关键字的较短替代项?

  •  28
  • Thamme Gowda  · 技术社区  · 8 年前

    背景:

    Python是关于简单性和可读性的代码。它已经变得更好的版本,我是一个巨大的球迷!但是,键入 l a m b d 每次我必须定义一个lambda都不有趣(你可能不同意)。 l m b d 把我的陈述写得长一些,尤其是如果我在里面放了几只羔羊 map s和 filter l d 感觉太冗长了。

    # How to rename/alias a keyword to a nicer one? 
    lines = map(lmd x: x.strip(), sys.stdin)
    
    # OR, better yet, how to define my own operator like -> in python?
    lines = map(x -> x.strip(), sys.stdin)
    # Or may be :: operator is pythonic
    lines = map(x :: x.strip(), sys.stdin)
    
    # INSTEAD of this ugly one. Taking out this is my goal!
    lines = map(lambda x: x.strip(), sys.stdin)
    

    我很高兴添加这样的导入:

    from myfuture import lmd_as_lambda
    # OR
    from myfuture import lambda_operator
    
    3 回复  |  直到 5 年前
        1
  •  21
  •   Thamme Gowda    8 年前

    好消息是:你不需要使用 map filter 总之,你可以使用 generator expressions list comprehensions (渴望)相反,因此避免 lambda s完全。

    因此,不是:

    lines = map(lambda x: x.strip(), sys.stdin)
    

    只需使用:

    # You can use either of those in Python 2 and 3, but map has changed between
    # Python 2 and Python 3 so I'll present both equivalents:
    lines = (x.strip() for x in sys.stdin)  # generator expression (Python 3 map equivalent)
    lines = [x.strip() for x in sys.stdin]  # list comprehension   (Python 2 map equivalent)
    

    滤器 -并使用 这里有更多的反模式(和慢)。


    这个问题只包含一个例子 ,但也可以替换 滤器 滤器

    filter(lambda x: x%2==0, whatever)
    

    您可以使用条件理解:

    (x for x in whatever if x%2==0)
    [x for x in whatever if x%2==0]
    

    地图

    (x*2 for x in whatever if x%2==0)
    

    想想看,如果 滤器 :

    map(lambda x: x*2, filter(lambda x: x%2==0, whatever))
    

    注意:这并不意味着 λ 没有用!有很多地方 key argument for sorted (同样适用于 min max )或 functools.reduce for -循环更可读)或 itertools itertools.accumulate itertools.dropwhile itertools.groupby itertools.takewhile . 举几个例子 λ 可能有用,可能还有很多其他地方。

        2
  •  8
  •   Georgy rassa45    6 年前

    我不会说 defining your own syntax in an editor Python: defining my own operators?

    1. 方法 built-in types
      words = ['cat', 'dog', 'shark']
      result_1 = map(lambda x: x.upper(), words)
      result_2 = (x.upper() for x in words)
      result_3 = map(str.upper, words)
      # ['CAT', 'DOG', 'SHARK']
      
      map 具有 str.upper 比两者都短 具有 lambda another answer .
      docs int , float , str , bytes
      numbers = [1.0, 1.5, 2.0, 2.5]
      result_1 = map(lambda x: x.is_integer(), numbers)
      result_2 = (x.is_integer() for x in numbers)
      result_3 = map(float.is_integer, numbers)
      # [True, False, True, False]
      
    2. Class methods :
      以类似的方式,您可以使用 使用类方法:

      class Circle:
          def __init__(self, radius):
              self.radius = radius
          def area(self):
              return 3.14 * self.radius ** 2
      
      circles = [Circle(2), Circle(10)]
      result_1 = map(lambda x: x.area(), circles)
      result_2 = (x.area() for x in circles)
      result_3 = map(Circle.area, circles)
      # [12.56, 314.0]
      
    3. operator

      • itemgetter :
        当您希望通过索引选择元素时,可以使用此选项:

        from operator import itemgetter
        
        numbers = [[0, 1, 2, 3],
                   [4, 5, 6, 7],
                   [8, 9, 0, 1]]
        result_1 = map(lambda x: x[0], numbers)
        result_2 = (x[0] for x in numbers)
        result_3 = map(itemgetter(0), numbers)
        # [0, 4, 8]
        

        虽然它比给定示例中的生成器表达式长,但当您想要同时选择几个元素时,它实际上会更短:

        result_1 = map(lambda x: (x[0], x[2], x[3]), numbers)
        result_2 = ((x[0], x[2], x[3]) for x in numbers)
        result_3 = map(itemgetter(0, 2, 3), numbers)
        # [(0, 2, 3), (4, 6, 7), (8, 0, 1)]
        

        使用字典:

        data = [{'time': 0, 'temperature': 290, 'pressure': 1.01},
                {'time': 10, 'temperature': 295, 'pressure': 1.04},
                {'time': 20, 'temperature': 300, 'pressure': 1.07}]
        
        result_1 = map(lambda x: (x['time'], x['pressure']), data)
        result_2 = ((x['time'], x['pressure']) for x in data)
        result_3 = map(itemgetter('time', 'pressure'), data)
        # [(0, 1.01), (10, 1.04), (20, 1.07)]
        
      • attrgetter
        这个用于获取对象的属性:

        from collections import namedtuple
        from operator import attrgetter
        
        Person = namedtuple('Person', ['name', 'surname', 'age', 'car'])
        people = [Person(name='John', surname='Smith', age=40, car='Tesla'), 
                  Person(name='Mike', surname='Smith', age=50, car=None)]
        result_1 = map(lambda x: (x.name, x.age, x.car), people)
        result_2 = ((x.name, x.age, x.car) for x in people)
        result_3 = map(attrgetter('name', 'age', 'car'), people)
        # [('John', 40, 'Tesla'), ('Mike', 50, None)]
        

        吸引子 get 它会更短,但没有人真正做到这一点。使用 吸引子 λ ):

        get_features = attrgetter('name', 'age', 'car')
        group_1_features = map(get_features, people)
        group_2_features = map(get_features, other_people)
        ...
        

        fget 属性方法:

        result = map(Person.age.fget, people)
        

        不过,我从未见过有人使用它,所以如果你使用它,请准备好向那些会阅读你的代码的人解释。

      • contains
        用于检查元素是否存在于另一个对象/容器中:

        from functools import partial
        from operator import contains
        
        fruits = {'apple', 'peach', 'orange'}
        objects = ['apple', 'table', 'orange']
        result_1 = map(lambda x: x in fruits, objects)
        result_2 = (x in fruits for x in objects)
        is_fruit = partial(contains, fruits)
        result_3 = map(is_fruit, objects)
        # [True, False, True]
        

        然而,这有一个缺点,即创建额外的 partial __contains__

        result = map(fruits.__contains__, objects)
        

        但一些人认为,使用dunder方法是一种不好的做法,因为这些方法仅供私人使用。

      • 数学运算:
        例如,如果要对数对求和,可以使用 operator.add :

        from itertools import starmap
        from operator import add
        
        pairs = [(1, 2), (4, 3), (1, 10), (2, 5)]
        result_1 = map(lambda x: x[0] + x[1], pairs)
        result_2 = (x + y for x, y in pairs)
        result_3 = starmap(add, pairs)
        # [3, 7, 11, 7]
        

        itertools.starmap 这里是因为我们需要在将数字元组提供给 add(a, b) 作用


    我想我涵盖了我经常遇到的大多数情况,这些情况可以不用 λ . 如果你知道更多,请写在评论中,我会把它添加到我的答案中。

        3
  •  7
  •   chepner    8 年前

    要回答您的具体问题,请 operator lambda methodcaller 函数来创建调用对象上给定方法的函数。

    from operator import methodcaller as mc
    
    lines = map(mc('strip'), sys.stdin)
    

    map .

    lines = [x.strip() for x in sys.stdin]