Python 里面的装饰器 class

Python Decorator inside class

我有一个 class 基本上连接到 SFTP 服务器,与问题不太相关。 我正在尝试创建一个包装器 function/decorator 来帮助我消除大量重复代码。 这是一段代码的工作版本:

def upload_file(self, local_file, destionation_path: str):
    with pysftp.Connection(
            host=self.host,
            username=self.username,
            password=self.password,
            cnopts=self.cnopts
    ) as sftp:
        local_file_path = local_file
        print(f'Uploading output file: {local_file_path} to remote location: {destionation_path}')
        sftp.put(
            localpath=local_file_path,
            remotepath=destionation_path,
            confirm=False
        )

我宁愿不必在每个函数的开头都写上 `with pysftp.... as sftp' 部分。 我试着这样解决问题:

def connection(self, function):
    def wrapper(*args, **kwargs):
        connection = pysftp.Connection(
            host=self.host,
            username=self.username,
            password=self.password,
            cnopts=self.cnopts
        )
        return_val = function(connection, *args, **kwargs)
        return return_val
    return wrapper

@connection
def upload_file(self, connection, local_file, destionation_path: str):
        print(f'Uploading output file: {local_file} to remote location: {destionation_path}')
        connection.put(
            localpath=local_file,
            remotepath=destionation_path,
            confirm=False
        )

但是话又说回来,如果它是这样声明的,则不能将 self 参数传递给包装器,我如何从其他地方调用 upload_file?由于连接参数是由装饰器实例化的。 如果这应该以任何其他方式完成,我将非常感谢一些指南,因为我什至不确定我在寻找什么。

self 应该作为 wrapper 函数中的参数:

def connection(function):
    def wrapper(self, *args, **kwargs):
        with pysftp.Connection(
            host=self.host,
            username=self.username,
            password=self.password,
            cnopts=self.cnopts
        ) as connection:
            return_val = function(connection, *args, **kwargs)
            return return_val
    return wrapper

无论如何,您可以像@pqans 所说的那样将连接传递给构造函数。这是最简单的解决方案,也是我会做的。我觉得你有点复杂。

使用上下文管理器在运行时注入依赖:

with pysftp.Connection(
            host=self.host,
            username=self.username,
            password=self.password,
            cnopts=self.cnopts
        ) as connection:

    sftp = MyClass(connection)
    sftp.upload_file(local_file, destionation_path)

另一种方法是为您的 class 创建上下文管理器并使用依赖注入模式:

class ContextWrapperClass(object):
    def __init__(self, my_ftp_class_instance, *args, **kwargs):
        # ... Some code here

        self.ftp_operations = my_ftp_class_instance # This could be an instance 

    def __enter__(self):
        self.connection = pysftp.Connection(
            host=self.host,
            username=self.username,
            password=self.password,
            cnopts=self.cnopts
        )
        self.ftp_operations.connection = self.connection
        return self.ftp_operations

    def __exit__(self, type, value, traceback):
        print("Exception has been handled")
        self.connection.close()
        return True

那么您可以将其用作:

with ContextWrapperClass(MyClass()) as sftp:
    # connection is inserted as dependency injection on constructor
    sftp.upload_file(local_file, destionation_path)