Python实现带参Linux管道

615 阅读3分钟

这是我参与更文挑战的第24天,活动详情查看: 更文挑战

需求描述

假如需要实现一个随机生成三餐的食谱的需求,提供全部随机生成或自定义同时随机生成两种选项,尽量Pythonic。例如,这样调用即可:

breakfast >> lunch >> dinner

需求分析

>>的语法实现需要使用__rshift和__rrshift。 具体使用方式可参考前两期推文。
Python魔法方法之rrshift
Python实现Linux管道

  1. 自定义一个三餐的列表作为随机选取的对象
  2. 如果是全部随机生成,则无需传递参数,进行4和5的步骤
  3. breakfast的结果传递给lunch,在breakfast的结果基础插入lunch
  4. lunch的结果传递给dinner,在lunch的结果基础插入dinner
  5. 如果是自定义同时随机生成,则需要一个函数进记录参数,然后重复45步骤

实现>>管道语法

语法例子建议参考前两期推文
Python魔法方法之rrshift
Python实现Linux管道

# -*- coding=utf-8 -*-
import functools
import random
import pprint

class Pipe:

    def __init__(self, function):
        self.function = function
        functools.update_wrapper(self, function)

    # 当 >> 两边其中一个没有实现__rshift__时调用
    def __rrshift__(self, other):
        return self.function(other)

    # 实现携带自定义参数
    def curry(self, *args, **kwargs):
        return Pipe(lambda x: self.function(x, *args, **kwargs))

菜单候取对象

breakfast_menu = ['bacon', 'egg', 'milk', 'porridge', 'bread', 'corn']
lunch_menu = ['fish', 'beef', 'chicken', 'radish', 'spinach', 'watercress']
dinner_menu = ['lean meat', 'mutton', 'celery', 'tofu', 'cucumber']

菜单随机实现

@Pipe
def breakfast(menu, *args, **kwargs):
    menu['breakfast'] = random.sample(breakfast_menu, 3 if args == ('',) else 3 - len(args))
    if not args == ('',):
        for custom in args:
            menu['breakfast'].append(custom)
    return menu


@Pipe
def lunch(menu, *args, **kwargs):
    menu['lunch'] = random.sample(lunch_menu, 3 if args == ('',) else 3 - len(args))
    if not args == ('',):
        for custom in args:
            menu['lunch'].append(custom)
    return menu


@Pipe
def dinner(menu, *args, **kwargs):
    menu['dinner'] = random.sample(dinner_menu, 3 if args == ('',) else 3 - len(args))
    if not args == ('',):
        for custom in args:
            menu['dinner'].append(custom)
    return menu

整体控制及管道实现

if __name__ == "__main__":
    # menu存放菜单
    menu = dict()

    random_choice = int(input("菜单是否自动生成?是:1 否:0\n"))
    # 自动随机生成
    if random_choice:
        pprint.print(menu >> breakfast >> lunch >> dinner)
    # 自定义菜单,传递参数
    else:
        breakfast_custom_list = input("早餐菜单(最多3样),不够3样,剩下随机生成:").split(' ')
        lunch_custom_list = input("午餐菜单(最多3样),不够3样,剩下随机生成:").split(' ')
        dinner_custom_list = input("晚餐菜单(最多3样),不够3样,剩下随机生成:").split(' ')

        # 携带参数, *的作用是解包,[1,2,3] => 1,2,3
        breakfast = breakfast.curry(*(breakfast_custom_list))
        lunch = lunch.curry(*(lunch_custom_list))
        dinner = dinner.curry(*(dinner_custom_list))

        # 输出的漂亮格式就不搞了,直接打印啦
        pprint.print(menu >> breakfast >> lunch >> dinner)

随机生成效果

菜单是否自动生成?是:1 否:0 
1
{'breakfast': ['bread', 'egg', 'corn'],
 'dinner': ['tofu', 'cucumber', 'lean meat'],
 'lunch': ['spinach', 'chicken', 'fish']}

自定义菜单生成效果

菜单是否自动生成?是:1 否:0
0
早餐菜单(最多3样),不够3样,剩下随机生成:地瓜 玉米 白粥
午餐菜单(最多3样),不够3样,剩下随机生成:
晚餐菜单(最多3样),不够3样,剩下随机生成:丝瓜汤
{'breakfast': ['地瓜', '玉米', '白粥'],
 'dinner': ['tofu', 'cucumber', '丝瓜汤'],
 'lunch': ['beef', 'fish', 'radish']}

携带参数的实现

# 实现携带自定义参数
    def curry(self, *args, **kwargs):
        return Pipe(lambda x: self.function(x, *args, **kwargs))

原理: 匿名函数的*args和**kwargs保存了需要携带的参数。

其他 其他语法,未提到的,欢迎留言沟通