【问题标题】:using decorator arguments for switching使用装饰器参数进行切换
【发布时间】:2019-04-25 23:18:05
【问题描述】:

在 flaks 库中,我们可以使用类似 switch case 的装饰器。 (我明白了吗?)

app.route('')

所以...我想用装饰器和参数做一些 switch 语句,

喜欢:

@color('pink')
def _pink_power(self):
    print("wow")

@color('blue')
@color('red')
def _powerpower(self):
    print("god!!!!")

def input(color):
    I don't know what to do in here..
    if color is pink, print wow!

我很长一段时间都在努力解决这个问题,但我无法做到。你觉得不可能吗?

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    这里有一个相对简单的方法(虽然我建议你在末尾更改input函数的名称,因为它与同名的内置函数冲突):

    class color:
        _func_map = {}
    
        def __init__(self, case):
            self.case = case
    
        def __call__(self, f):
            self._func_map[self.case] = f
            return f
    
        @classmethod
        def switch(cls, case):
            cls._func_map[case]()
    
    
    @color('pink')
    def _pink_power():
        print("wow")
    
    @color('blue')
    @color('red')
    def _powerpower():
        print("god!!!!")
    
    
    def input(colorname):
        color.switch(colorname)
    
    input('pink') # -> wow
    input('blue') # -> god!!!!
    input('red')  # -> god!!!!
    

    增强

    您可以支持在没有匹配的colorname 时使用默认情况,例如 C/C++ 的 switch 语句支持:

    class color:
        DEFAULT = '_DEFAULT'
        _func_map = {}
    
        def __init__(self, case):
            self.case = case
    
        def __call__(self, f):
            self._func_map[self.case] = f
            return f
    
        @classmethod
        def _default(cls):
            raise ValueError('Unknown color!')
    
        @classmethod
        def switch(cls, case):
            cls._func_map.get(case, cls._default)()
    

    添加到类中的_default() 方法在调用时会引发异常:

    input('lavender')  # -> ValueError: Unknown color!
    

    但是您可以通过定义自己的错误处理函数来覆盖它:

    @color(color.DEFAULT)  # Override default function.
    def my_default():
        print("loser!")
    
    input('lavender')  # -> loser!
    

    【讨论】:

      【解决方案2】:

      你...可以这样做,但我不确定这样做是不是个好主意。

      import contextlib
      
      class Colors(object):
          def __init__(self):
              self.__colors = dict()
      
          def register(self, colorname):
              def wrapper(f):
                  @contextlib.wraps(f)
                  def wrapper(*args, **kwargs):
                      return f(*args, **kwargs)
                  self.__colors[colorname] = wrapper
                  return wrapper
      
          def __getitem__(self, item):
              return self.__colors[item]
      
      colors = Colors()
      
      @colors.register("pink")
      def _pink_power():
          print("wow")
      
      @colors.register("blue")
      @colors.register("red")
      def _powerpurple():
          print("god!!!!!")
      
      def input(colorname):
          colors[colorname]()
      

      【讨论】:

      • 非常感谢你,但你为什么认为这不是一个好主意?
      • 我认为你获得的功能不值得你编写奇怪的代码结构。一年后你不会记得为什么要这样做,也绝对不会记得它是如何工作的。
      【解决方案3】:

      这是另一种方法,我认为它比我原来的答案有所改进,因为它在某种意义上更通用,不需要为每个 switch 上下文定义一个新类,这使得它更可重用。

      装饰器被实现为一个名为小写switch 的类,当一个值与定义的任何相关“case”函数的值不匹配时,它所应用的函数将成为调用的默认函数。

      class switch:
          """ Value dispatch function decorator.
      
          Transforms a function into a value dispatch function, which can have
          different behaviors based on the value of its first argument.
          """
          def __init__(self, func):
              self.func = func
              self.registry = {}
      
          def case(self, value, func=None):
              if func is None:
                  return lambda f: self.case(value, f)
              self.registry[value] = func
              return func
      
          def __call__(self, *args, **kwargs):
              return self.registry.get(args[0], self.func)(*args, **kwargs)
      

      示例用法:

      @switch
      def color(name):  # Default when no match.
          print('loser!')
      
      @color.case('pink')
      def _pink_power(name):
          print("wow")
      
      @color.case('blue')
      @color.case('red')
      def _powerpower(name):
          print("god!!!!")
      
      def input(name):
          color(name)
      
      input('pink')       # -> wow
      input('blue')       # -> god!!!!
      input('red')        # -> god!!!!
      input('lavender')   # -> loser!
      

      【讨论】:

        猜你喜欢
        • 2013-01-16
        • 2021-10-01
        • 2017-06-19
        • 1970-01-01
        • 2017-07-21
        • 2022-08-15
        • 2023-04-03
        • 2022-11-12
        • 2012-02-02
        相关资源
        最近更新 更多