在一个玩具示例中实现python装饰器

2024-10-04 11:34:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在努力寻找一个学习装饰师的用例,我想我已经找到了一个与我相关的用例

我正在使用以下代码

在文件class1.py中,我有:

import pandas as pd, os

class myClass():
    def __init__(self):
        fnDone = f'C:\user1\Desktop\loc1\fn.csv'
        if os.path.exists(fnDone): return
        self.Fn1()
        pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

    def Fn1(self):
        print('something')

if __name__ == '__main__':
    myClass()

在文件class2.py中,我有:

class myClassInAnotherFile():
    def __init__(self):
        fnDone = f'C:\user1\Desktop\loc2\fn.csv'
        if os.path.exists(fnDone): return
        self.Fn1()
        self.Fn2()
        pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

    def Fn1(self):
        print('something')

    def Fn2(self):
        print('something else')

if __name__ == '__main__':
    myClassInAnotherFile('DoneFile12)

是否有一种方法可以在另一个名为utilities.py的文件中定义通用装饰器代码,以便我可以执行以下操作:

在文件class1.py中需要的,我有:

import pandas as pd, os

class myClass():
    def __init__(self):
        fnDone = f'C:\user1\Desktop\loc1\fn.csv'
        self.Fn1()
        pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

    def Fn1(self):
        print('something')

if __name__ == '__main__':
    @myDecorator
    myClass()

在文件class2.py中,我有:

class myClassInAnotherFile():
    def __init__(self):
        fnDone = f'C:\user1\Desktop\loc2\fn.csv'
        self.Fn1()
        self.Fn2()
        pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

    def Fn1(self):
        print('something')

    def Fn2(self):
        print('something else')

if __name__ == '__main__':
    @myDecorator
    myClassInAnotherFile()

本质上是使用装饰器模仿原始行为

编辑1: 我希望扩展我的类定义的功能。在这两个原始类定义中,我重复了检查fnDone文件的代码,如果该文件存在,则退出该类目标是有一个decorator来检查fnDone文件,如果该文件存在,则退出该类。

编辑2: 我也可以将其作为一个函数来实现,但我正在尝试学习如何使用装饰器扩展类或方法的功能

编辑3: 如果在class1.py中使用以下内容,是否会更容易:

def myClass():
    fnDone = f'C:\user1\Desktop\loc1\fn.csv'
    if os.path.exists(fnDone): return
    self.Fn1()
    pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

def Fn1(self):
    print('something')

if __name__ == '__main__':
    myClass()

和{}如下:

def myClassInAnotherFile():
    fnDone = f'C:\user1\Desktop\loc2\fn.csv'
    if os.path.exists(fnDone): return
    self.Fn1()
    self.Fn2()
    pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

def Fn1(self):
    print('something')

def Fn2(self):
    print('something else')

if __name__ == '__main__':
    myClassInAnotherFile('DoneFile12)

Tags: 文件csvpyselfifosdefmyclass
3条回答

我对@鸽子手给出的答案投了更高的票,因为您主要对使用类感兴趣。但这就是我如何使用常规函数实现您的目标,我认为这更有意义。出于@鸽子手提供的相同原因,将CSV文件名作为myclass函数的参数作为参数名fnDone是有意义的:

import os.path
from functools import wraps

import pandas as pd

def myDecorator(func):
    @wraps(func)
    def wrapper(fnDone):
        if os.path.exists(fnDone):
            return
        func(fnDone)
    return wrapper

@myDecorator
def myClass(fnDone):
    Fn1()
    pd.DataFrame({'Done': 1}, index=[0]).to_csv(fnDone)

def Fn1():
    print('something')

if __name__ == '__main__':
    myClass('test1.csv')

下面是一个在运行代码之前检查文件是否存在的装饰程序:

文件:my_decorator.py

import os
import pandas as pd


def checkDoneDecorator(doneFilename):
    def _decorator(decorated):
        def _wrapper_function(*args, **kwargs):
            if os.path.exists(doneFilename):
                return

            try:
                result = decorated(*args, **kwargs)
            finally:
                pd.DataFrame({'Done': 1}, index=[0]).to_csv(doneFilename)
        return _wrapper_function
    return _decorator

文件:class1.py

from my_decorator import checkDoneDecorator


@checkDoneDecorator(doneFilename='C:\user1\Desktop\loc1\fn.csv')
def myClass():
    Fn1()


def Fn1():
    print('something')


if __name__ == '__main__':
    myClass()

文件:class2.py

from my_decorator import checkDoneDecorator


@checkDoneDecorator(doneFilename='C:\user1\Desktop\loc2\fn.csv')
def myClassInAnotherFile():
    Fn1()
    Fn2()


def Fn1():
    print('something')


def Fn2():
    print('something else')


if __name__ == '__main__':
    myClassInAnotherFile()

一些注意事项:

  • 我使用了一个带参数doneFilename的装饰器,它比简单的装饰器多添加了一层嵌套函数。您可以看到一个详细的示例here
  • 我还将doneFilename写入装饰器中,因为文件检查和文件写入是相关的。但这不是强制性的
  • 我从您的示例中删除了self参数,因为在这个示例中并不真正需要类。如果你真的需要一个类,请不要把装饰器放在__init__上,这样做:
class myClass:

    @checkDoneDecorator(doneFilename='C:\user1\Desktop\loc1\fn.csv')
    def start(self):
        self.Fn1()

    def Fn1(self):
        print('something')

if __name__ == '__main__':
    myClass().start()

因为fnDone是一个局部变量而不是一个参数,所以使用decorator有点尴尬。如果您稍微修改代码,将fnDone作为参数传入,则使用装饰器更为可行

例如,您可以制作一个包装对象构造函数的装饰器,并检查传入的文件是否存在:

import os.path
from functools import wraps

import pandas as pd

def check_file_exists(f):
    @wraps(f)
    def _inner(self, fn_done):
        if os.path.exists(fn_done):
            return
        f(self, fn_done)
    return _inner

class MyClass:
    @check_file_exists
    def __init__(self, fn_done) -> None:
        pd.DataFrame({'Done': 1}, index=[0]).to_csv(fn_done)

if __name__ == "__main__":
    MyClass("fn.csv")

相关问题 更多 >