【问题标题】:Create a decorator that saves methods input - returns 'NoneType' object is not callable创建一个保存方法输入的装饰器 - 返回“NoneType”对象不可调用
【发布时间】:2019-07-22 06:55:52
【问题描述】:

我目前正在使用无服务器解决方案(ML 引擎),并且我需要不时将流程的数据帧保存在云存储中。为此,我创建了名为 save_current_data_frame_to_track 的方法,我想将其转换为装饰器,如下所示:

import numpy as np
import pandas as pd

def save_current_data_frame_to_track(current_data_frame, filename):
    current_data_frame.to_csv(filename + '.csv')
    pass

def save_input_to_track(func):
    def func_wrapper(*args, func):
        for arg in args:
            for key, value in locals():
                if type(value) == 'pandas.core.frame.DataFrame':
                    save_current_data_frame_to_track( value, key)
            return (func)
        return func_wrapper

rp = pd.DataFrame(data={'time_delta_from': [60, 90, 170],
                                'time_delta_to': [30, 60, 120]},
                        index=[1, 2, 3], dtype=np.int32)

@save_input_to_track
def add_1(data):
    data['time_delta_from'] = 1
    return data

add_1(rp)

这给了我以下错误:

 add_1(rp)
TypeError: 'NoneType' object is not callable

为什么会出现这个错误?

【问题讨论】:

  • 您遇到的错误是什么?此外,如果您的装饰器函数名称为 save_input_to_track,则应将其作为 @save_input_to_track 放在其他函数之上。
  • @Mudits 刚刚更新了我的问题
  • return func_wrapper的缩进,你的save_input_to_track()函数没有返回任何东西..

标签: python decorator python-decorators


【解决方案1】:

我建议你使用wraps,详细了解如何获取包装函数here 的参数。看起来你的代码应该是:

import numpy as np
import pandas as pd
from functools import wraps

def save_current_data_frame_to_track(current_data_frame, filename):
    current_data_frame.to_csv(filename + '.csv')

def save_input_to_track(func):
    @wraps(func)
    def func_wrapper(*args, **kwargs):
        for arg in args:
            if isinstance(arg, pd.core.frame.DataFrame):
                save_current_data_frame_to_track(arg, 'somefile')
        return func(*args)
    return func_wrapper

rp = pd.DataFrame(data={'time_delta_from': [60, 90, 170],
                        'time_delta_to': [30, 60, 120]},
                  index=[1, 2, 3], dtype=np.int32)

@save_input_to_track
def add_1(data):
    data['time_delta_from'] = 1
    return data

add_1(rp)

对于作为文件名的键名,我认为简单的解决方案是使用 kwarg,这里是示例:

import numpy as np
import pandas as pd
from functools import wraps

def save_current_data_frame_to_track(current_data_frame, filename):
    current_data_frame.to_csv(filename + '.csv')

def save_input_to_track(func):
    @wraps(func)
    def func_wrapper(*args, **kwargs):
        for key, kwarg in kwargs.items():
            if isinstance(kwarg, pd.core.frame.DataFrame):
                save_current_data_frame_to_track(kwarg, key)
        return func(*args, **kwargs)
    return func_wrapper

rp = pd.DataFrame(data={'time_delta_from': [60, 90, 170],
                        'time_delta_to': [30, 60, 120]},
                  index=[1, 2, 3], dtype=np.int32)

@save_input_to_track
def add_1(data1, data2):
    data1['time_delta_from'] = 1
    data2['time_delta_from'] = 2
    return data1, data2

add_1(data1=rp, data2=rp)

【讨论】:

  • 谢谢!!!看起来令人印象深刻,虽然我需要它来处理任何给定的数据框输入(例如 2 个数据框作为输入)及其名称,请参阅我的编辑(将其更改为来自“某个文件”的键)
  • 添加了第二个例子
  • 几乎 :) 我需要它来存储“data1”“data2”的原始名称,我有很多方法可以跟踪数据帧,我想在我的项目中的很多地方使用这个装饰器
  • 通过使用locals,您仍将拥有名称args,因此我更新了答案,只需要使用命名参数更改函数的调用。
  • 很高兴为您提供帮助!
【解决方案2】:

您的代码存在缩进问题。您返回 func 的方式也是错误的。以下代码应该适合您:

import numpy as np
import pandas as pd

def save_current_data_frame_to_track(current_data_frame, filename):
    current_data_frame.to_csv(filename + '.csv')
    pass

def save_input_to_track(func):
    def func_wrapper(*args):
        for arg in args:
           if type(value) == 'pandas.core.frame.DataFrame':
               save_current_data_frame_to_track( value, 'some_file')
        return func(*args)
    return func_wrapper

rp = pd.DataFrame(data={'time_delta_from': [60, 90, 170],
                                'time_delta_to': [30, 60, 120]},
                        index=[1, 2, 3], dtype=np.int32)

@save_input_to_track
def add_1(data):
    data['time_delta_from'] = 1
    return data

add_1(rp)

【讨论】:

  • @Yehosaphat Schellekens:它在for key, value in locals(): 失败了我无法修复它,因为我不明白你在那里试图做什么。
  • 谢谢!我想检测输入对象是否为 DF 类型并保存
  • 我现在收到以下错误:for key, value in locals(): ValueError: too many values to unpack (expected 2)
  • 在这种情况下,您不需要遍历本地。 args 有数据框。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2020-08-19
  • 2013-01-10
  • 2021-11-22
  • 2019-03-17
  • 2020-09-22
  • 1970-01-01
相关资源
最近更新 更多