Python 如何在文件操作中编写两个decorator

Python 如何在文件操作中编写两个decorator,python,function,file,file-io,decorator,Python,Function,File,File Io,Decorator,我有一个csv文件,内容如下 101,第1项 101,第1项 如果是csv,将执行下面的代码 import csv fName = input() def read_csv(fName): try: with open(fName, 'r') as f: reader = csv.reader(f) for row in reader: print (row) read_csv(fN

我有一个csv文件,内容如下

101,第1项
101,第1项

如果是csv,将执行下面的代码

import csv    
fName = input()
def read_csv(fName):
    try:
        with open(fName, 'r') as f:
            reader = csv.reader(f)
            for row in reader:
                print (row)

read_csv(fName)
下面介绍如何在
decorator
函数中编写异常,并在此基础上调用异常

第一装饰师

如果
fName
未通过
.txt
.csv
结束,则必须生成输出
不接受

第二个装饰师

如果
fName=file.txt
文本文件,则必须注意以下操作

def read_txt(fName):
    f = open(fName, "r")
    print(f.readline())

如果是csv,则执行第一个函数,如果是txt,则执行下一个函数。如何使用decorator实现。我可以设定条件来达到这种情况,但事实并非如此

我的整个代码没有装饰如下

fName = input()
def read_csv(fName):
    if fName.endswith('.csv'):
        #print  ('hi')
        try:
            with open(fName, 'r') as f:
                reader = csv.reader(f)
                for row in reader:
                    print (row)
        except IOError:
            print ("Could not read file:", fName)
    #SECOND DECORATOR
    if fName.endswith('.txt'):
        f = open(fName, "r")
        print(f.readline())
    #FIRST DECORATOR
    if not(fName.endswith('.csv')) and not(fName.endswith('.txt')):
        print ('not accept')
read_csv(fName)

您的问题似乎不属于decorator,而是属于工厂模式,即根据输入文件进行不同的处理

下面的代码是针对您的问题的一个非常简单和基本的工厂模式解决方案,应该根据您的需要进行相应的修改

import os
from abc import ABC, abstractmethod


class FileProcessor(ABC):
    @abstractmethod
    def process():
        pass

class TextFileProcessor(FileProcessor):
    def process(self, file_path):
        print("Text file processing goes here")


class CsvFileProcessor(FileProcessor):
    def process(self, file_path):
        print("CSV file processing goes here")


class DefaultFileProcessor(FileProcessor):
    def process(self, file_path):
        raise ValueError("File %s is not valid" % file_path)


class FileFactory:
    processors = {
        'txt': TextFileProcessor,
        'csv': CsvFileProcessor,
        'default': DefaultFileProcessor
    }

    def __init__(self, file_path):
        if not os.path.exists(file_path):
            raise IOError("File not found")
        self.file_path = file_path

    def process(self):
        dot_splits = self.file_path.split(".")
        ext = dot_splits[-1] if len(dot_splits) > 1 else "default"
        ext = ext if ext in self.processors else "default"
        processor_class = self.processors.get(ext)

        return processor_class().process(self.file_path)


FileFactory(file_path).process()
在以后的阶段中,如果您想添加json处理器,那么也可以通过添加

processors = {
    'txt': TextFileProcessor,
    'csv': CsvFileProcessor,
    'json': JsonFileProcessor,
    'default': DefaultFileProcessor
}
创建新的Json处理器类

class JsonFileProcessor(FileProcessor):
    def process(self, file_path):
        print("JSON file processing goes here")
根据您的代码和,这里有一个可能的解决方案:

def read_file_decorator(fName):
    def read_csv():
        print('read_csv')
        with open(fName, 'r') as f:
            reader = csv.reader(f)
            for row in reader:
                print(row)

    def read_txt():
        print('read_txt')
        f = open(fName, 'r')
        for row in f:
            print(row)

    if fName.endswith('.csv'):
        return read_csv
    elif fName.endswith('.txt'):
        return read_txt
    else:
        return None

reader_function = read_file_decorator(fileName)
if reader_function != None:
    reader_function()
else:
    print('not accept')

我使用一个有状态修饰符,在实际执行reader函数之前记住它内部的文件名(为了不传递它两次);对于无效的文件类型,我使用固定值
None

你可以用装饰师这样做:

import functools


def check_arguments(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        fname = kwargs['fname']
        if not fname.endswith('.csv') and not fname.endswith('.txt'):
            print('not accept')
        return func(*args, **kwargs)
    return wrapper


def set_file_processor(func):
    def read_csv(fname):
        print('read_csv', fname)

    def read_txt(fname):
        print('read_txt', fname)


    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        fname = kwargs['fname']
        if fname.endswith('.csv'):
            read_csv(fname)
        elif fname.endswith('.txt'):
            read_txt(fname)
        return func(*args, **kwargs)
    return wrapper


@check_arguments
@set_file_processor
def process(fname):
    pass


process(fname='input.csv')

根据需求,使用decorator将是对decorator的过度使用。但如果必须使用decorator实现此功能,我们可以这样实现:

  • 我们可以创建一个名为
    read\u file
    的伪函数和一个名为
    reader
  • 用户将始终使用文件名作为参数调用
    read\u file
    ,装饰函数
    reader
    将检查传递的文件扩展名,并调用所需函数-
    read\u csv
    read\u text
输出

In read_csv()
In read_text()
not accepted

具体问题是什么?如果csv是第一个要执行的函数,如果txt是下一个要执行的函数。如何做到用装饰这一点呢?现在还不清楚为什么你需要使用decorator来解决这个问题,因为有更好的替代方案。很好地工作,但我需要实现使用decorator对于上述问题,decorator根本不是一个解决方案,问题是有一个条件函数调用,也就是说,如果是CSV,则调用一个函数,如果不是CSV,则应调用另一个函数。Decorator不应该用于此,因为它是为解决常见的可重复问题(如检查身份验证)/可读性而设计的。但是如果你正在寻找一个装饰链来处理同一个对象的不同事情,请看这个,
In read_csv()
In read_text()
not accepted