Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
除python外,是否尝试使用常规装饰器包装?_Python_Try Catch_Wrapper_Decorator - Fatal编程技术网

除python外,是否尝试使用常规装饰器包装?

除python外,是否尝试使用常规装饰器包装?,python,try-catch,wrapper,decorator,Python,Try Catch,Wrapper,Decorator,我曾经与很多我没有编写的嵌套很深的json进行过交互,我想让我的python脚本对无效输入更加“宽容”。我发现自己在编写try-except-blocks时遇到了麻烦,我宁愿把这个可疑的函数包装起来 我理解接受异常是一种糟糕的策略,但我更希望它们在以后打印和分析,而不是实际停止执行。在我的用例中,在循环中继续执行比获取所有键更有价值 以下是我现在正在做的: try: item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST() ex

我曾经与很多我没有编写的嵌套很深的json进行过交互,我想让我的python脚本对无效输入更加“宽容”。我发现自己在编写try-except-blocks时遇到了麻烦,我宁愿把这个可疑的函数包装起来

我理解接受异常是一种糟糕的策略,但我更希望它们在以后打印和分析,而不是实际停止执行。在我的用例中,在循环中继续执行比获取所有键更有价值

以下是我现在正在做的:

try:
    item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST()
except:
    item['a'] = ''
try:
    item['b'] = OBJECT_THAT_DOESNT_EXIST.get('key2')
except:
    item['b'] = ''
try:
    item['c'] = func1(ARGUMENT_THAT_DOESNT_EXIST)
except:
    item['c'] = ''
...
try:
    item['z'] = FUNCTION_THAT_DOESNT_EXIST(myobject.method())
except:
    item['z'] = ''
以下是我想要的(1):

或(二):

…在这里,我可以将单个数据项(1)或主函数(2)包装到某个函数中,该函数将停止执行的异常转换为空字段,并打印到标准输出。前者是一种逐项跳转——在该键不可用的情况下,它记录为空白并继续移动——后者是一种行跳转,如果任何字段不起作用,则跳过整个记录

我的理解是某种包装应该能够解决这个问题。下面是我用包装纸试过的:

def f(func):
   def silenceit():
      try:
         func(*args,**kwargs)
      except:
         print('Error')
      return(silenceit)
这就是它不起作用的原因。调用不存在的函数,它不会尝试将其捕获:

>>> f(meow())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'meow' is not defined
>>f(喵喵())
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
名称错误:未定义名称“喵喵”
在我添加一个空白返回值之前,我想让它正确地尝试捕获。如果这个函数起作用,它会打印“错误”,对吗

包装器函数是正确的方法吗

更新

下面我得到了很多非常有用、有用的答案,谢谢你们——但我编辑了上面使用的示例,以说明我正在尝试捕获的不仅仅是嵌套的键错误,我正在寻找一个函数,它包装了一个try-catch for

  • 当方法不存在时
  • 当一个对象不存在,并且正在获取对其调用的方法时
  • 将不存在的对象作为函数的参数调用时
  • 这些东西的任意组合
  • 奖励,当函数不存在时

  • 这取决于您预期的例外情况

    如果您唯一的用例是
    get()
    ,您可以这样做

    item['b'] = myobject.get('key2', '')
    
    对于其他情况,您的decorator方法可能很有用,但不是以您这样做的方式

    我将尝试向您展示:

    def f(func):
       def silenceit(*args, **kwargs): # takes all kinds of arguments
          try:
             return func(*args, **kwargs) # returns func's result
          except Exeption, e:
             print('Error:', e)
             return e # not the best way, maybe we'd better return None
                      # or a wrapper object containing e.
      return silenceit # on the correct level
    
    然而,
    f(一些未定义的函数())
    将无法工作,因为

    a)
    f()
    在执行时间和

    b) 它用错了。正确的方法是包装函数,然后调用它:
    f(function-to-wrap)(

    “lambda层”有助于:

    wrapped_f = f(lambda: my_function())
    
    包装一个lambda函数,该函数反过来调用一个不存在的函数。调用
    wrapped\u f()
    会导致调用lambda的包装器,lambda试图调用
    my\u函数()
    。如果不存在,lambda将引发一个异常,该异常被包装器捕获

    这是因为名称
    my_函数
    不是在定义lambda时执行的,而是在执行lambda时执行的。然后,该执行由函数
    f()
    保护和包装。因此,异常发生在lambda内部,并传播到decorator提供的包装函数中,该函数将优雅地处理异常

    如果您试图用类似于的包装器替换lambda函数,那么这种向lambda函数内部移动的做法是行不通的

    g = lambda function: lambda *a, **k: function(*a, **k)
    
    接着是

    f(g(my_function))(arguments)
    
    因为这里的名称解析是“返回到表面”:
    my_函数
    无法解析,这发生在调用
    g()
    甚至
    f()
    之前。所以它不起作用

    如果你想做类似的事情

    g(print)(x.get('fail'))
    
    如果没有
    x
    ,它就不能正常工作,因为
    g()
    保护
    打印,而不是
    x

    如果您想在此处保护
    x
    ,您必须这样做

    value = f(lambda: x.get('fail'))
    

    因为
    f()
    提供的包装器调用lambda函数,该函数会引发一个异常,该异常随后被静默。

    在您的例子中,您首先计算meow调用的值(该值不存在),然后将其包装到装饰器中。这样不行

    首先,在包装异常之前引发异常,然后包装错误缩进(
    sileneit
    不应返回自身)。您可能希望执行以下操作:

    def hardfail():
      return meow() # meow doesn't exist
    
    def f(func):
      def wrapper():
        try:
          func()
        except:
          print 'error'
      return wrapper
    
    softfail =f(hardfail)
    
    def get_from_object(obj, *keys):
      try:
        value = obj
        for k in keys:
            value = value.get(k)
        return value
      except AttributeError:
        return ''
    
    def return_on_failure(value):
      def decorate(f):
        def applicator(*args, **kwargs):
          try:
             f(*args,**kwargs)
          except:
             print('Error')
    
        return applicator
    
      return decorate
    
    输出:

    >>> softfail()
    error
    
    >>> hardfail()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in hardfail
    NameError: global name 'meow' is not defined
    
    在守则中:

     item['a'] = get_subkey(myobject, 'key', 'subkey')
    
    编辑:

    以防你想要在任何深度都能工作的东西。您可以执行以下操作:

    def hardfail():
      return meow() # meow doesn't exist
    
    def f(func):
      def wrapper():
        try:
          func()
        except:
          print 'error'
      return wrapper
    
    softfail =f(hardfail)
    
    def get_from_object(obj, *keys):
      try:
        value = obj
        for k in keys:
            value = value.get(k)
        return value
      except AttributeError:
        return ''
    
    def return_on_failure(value):
      def decorate(f):
        def applicator(*args, **kwargs):
          try:
             f(*args,**kwargs)
          except:
             print('Error')
    
        return applicator
    
      return decorate
    
    你会称之为:

    >>> d = {1:{2:{3:{4:5}}}}
    >>> get_from_object(d, 1, 2, 3, 4)
    5
    >>> get_from_object(d, 1, 2, 7)
    ''
    >>> get_from_object(d, 1, 2, 3, 4, 5, 6, 7)
    ''
    >>> get_from_object(d, 1, 2, 3)
    {4: 5}
    
    使用你的代码

    item['a'] = get_from_object(obj, 2, 3) 
    
    顺便说一下,从个人角度来看,我也喜欢使用contextmanager的@cravoori解决方案。但这意味着每次有三行代码:

    item['a'] = ''
    with ignored(AttributeError):
      item['a'] = obj.get(2).get(3) 
    

    为什么不直接使用循环呢

    for dst_key, src_key in (('a', 'key'), ('b', 'key2')):
        try:
            item[dst_key] = myobject.get(src_key).get('subkey')
        except Exception:  # or KeyError?
            item[dst_key] = ''
    
    或者,如果你想写一个小助手:

    def get_value(obj, key):
        try:
            return obj.get(key).get('subkey')
        except Exception:
            return ''
    
    另外,如果您有几个地方需要获取值,那么您可以将这两种解决方案结合起来,并且帮助函数将更合理


    不确定您是否真的需要一个装饰程序来解决您的问题。

    您可以使用defaultdict和


    使用可配置的装饰器很容易实现

    def get_decorator(errors=(Exception, ), default_value=''):
    
        def decorator(func):
    
            def new_func(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except errors, e:
                    print "Got error! ", repr(e)
                    return default_value
    
            return new_func
    
        return decorator
    
    f = get_decorator((KeyError, NameError), default_value='default')
    a = {}
    
    @f
    def example1(a):
        return a['b']
    
    @f
    def example2(a):
        return doesnt_exist()
    
    print example1(a)
    print example2(a)
    
    只需传递以获取包含错误类型的_decorator元组,您希望该错误类型为静默,并返回默认值。 输出将是

    Got error!  KeyError('b',)
    default
    Got error!  NameError("global name 'doesnt_exist' is not defined",)
    default
    

    编辑:多亏了martineau,我将错误的默认值更改为元组,并添加了基本异常以防止错误。

    由于您要处理大量损坏的代码,在这种情况下使用
    eval
    可能是情有可原的

    def my_eval(code):
      try:
        return eval(code)
      except:  # Can catch more specific exceptions here.
        return ''
    
    然后将所有可能被破坏的语句包装起来:

    item['a'] = my_eval("""myobject.get('key').get('subkey')""")
    item['b'] = my_eval("""myobject.get('key2')""")
    item['c'] = my_eval("""func1(myobject)""")
    

    这里有很多很好的答案,但是我没有看到任何关于你是否可以通过装饰来完成这一点的答案

    简短的回答是“不”,至少在没有对代码进行结构性修改的情况下是这样。修饰符在函数级别操作,而不是在单个语句上。因此,为了使用decoro
    @return_on_failure('')
    def computeA():
        item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST()
    
    item["a"] = computeA()
    
    def return_on_failure(value):
      def decorate(f):
        def applicator(*args, **kwargs):
          try:
             f(*args,**kwargs)
          except:
             print('Error')
    
        return applicator
    
      return decorate
    
    from contextlib import suppress
    
    with suppress(FileNotFoundError):
        os.remove('somefile.tmp')
    
    with suppress(FileNotFoundError):
        os.remove('someotherfile.tmp')