Python实例装饰器

时间:2016-01-09 15:12:58

标签: python decorator

我想用来自父母"的装饰器来装饰某些实例函数。实例,有没有办法可以使用实例来装饰函数。

以下是我需要做的事情;

class Foo(object):

    def __init__(self):
        pass

    def set_configuration(self, function):
        def config(*args, **kwargs):
            # NOTE: this function needs to use instance variables.
            print 'foo ' + function()
        return config()

class Bar(object):

    def __init__(self, parent):
        self.parent = parent

    @self.parent.set_configuration
    def set_config_2(self)
        return 'bar'

foo = Foo()
foo.bar = Bar(foo)
foo.bar.set_config_2

编辑:

好的伙伴在这里是实际问题,我有一个我需要与之交互的设备。因此,设备可能具有多个级别,即设备a 具有多个接口,并且接口可以附加多个vlan。所以我的想法是,如果我想在接口上更改vlan,而不是构建一个完整的命令,我希望允许父类处理它的命令级别的构建。所以我想打电话给#34;改变vlan"函数,它会将它的一部分命令发送到下一级别进行包装并发送链,直到达到设备级别并将完整命令发送到设备。

class Device(object):

    def __init__(self):
        self.interfaces = list()
        self.ssh = ssh('blah')

    def set_device(self, function):
        self.ssh.command('setup commands')
        self.ssh.command(wrapped command here)
        self.ssh.command('exit commands')


class Interface(object):

    def __init__(self, name, parent):
        self.name
        self.parent
        self.vlan = Vlan('name')

    def set_interface(self):
        return self.name


class Vlan(object):

    def __init__(self, name, parent):
        self.name = name
        self.parent = parent

    def set_vlan(self):
        return self.name 

我希望这更有意义。如果没有,请告诉我。

4 个答案:

答案 0 :(得分:1)

不,你不能在这里使用装饰器,因为在Bar的定义时间,父母不知道。

只需将set_configuration与参数一起使用:

class Foo(object):

    def __init__(self):
        pass

    def set_configuration(self, function):
        def config(*args, **kwargs):
            # NOTE: this function needs to use instance variables.
            print 'foo ' + function()
        return config

class Bar(object):

    def __init__(self, parent):
        self.parent = parent

    def set_config_2(self, args)
        def inner_function():
            return 'bar'
        return self.parent.set_configuration(inner_function)(args)


foo = Foo()
foo.bar = Bar(foo)
foo.bar.set_config_2(123)

答案 1 :(得分:1)

Python是一种动态语言,所以很多事情都是可能的。我没有评论这是否是一件好事 - 我真的无法理解你的逻辑目的。

为了实现这一目标,您需要在set_config_2中动态创建Bar.__init__,因为parent在类定义时未知:

from types import MethodType
class Foo(object):
    def __init__(self):
        pass

    def set_configuration(self, f):
        def config(inst, *args, **kwargs):
            print('foo', f(inst, *args, **kwargs))
        return config

class Bar(object):
    def __init__(self, parent):
        self.parent = parent
        @self.parent.set_configuration
        def set_config_2(inst):
            return 'bar'
        self.set_config_2 = MethodType(set_config_2, self)

foo = Foo()
foo.bar = Bar(foo)
foo.bar.set_config_2()

输出:

foo bar

这非常难看,必须有一种更好的方法来做你正在尝试的事情。也许你可以问一个不同的问题来解释你想要实现的目标。

答案 2 :(得分:0)

你的装饰者不必使用实例方法,因为那是需要它们的包装函数config。因此,装饰器不一定是一种方法。例如:

def set_configuration(func):
    @functools.wraps(func)  # copy function's metadata
    def wrapper(self, *args, **kwargs):
        # do whatever you want to fetch the config data
        return 'foo' + func(self, *args, **kwargs)

    return wrapper

尽管如此,根据您的具体需要,可能会有一种更为直接和明确的方式。

答案 3 :(得分:0)

我非常确定你可以在不将装饰器作为实例的情况下做到这一点。这里有几个想法。

反转层次结构

在我看来,你所拥有的等级是向后。我的理解:

  • Device仅提供ssh实例
  • 您要调用的常用方法是VLAN定义的
  • 设置和退出命令是常量

通过使层次结构走向另一个方向,您可以定义"更改VLAN" 从较低级别访问所需内容的方法。

class Device(object):
    def __init__(self):
        self.ssh = ssh('blah')

class Interface(object):

    def __init__(self, name, device):
        self.name
        self.device = device

class Vlan(object):
    def __init__(self, name, change_command, interface):
        self.name = name
        # How you actually store this command is completely up to you.
        # You might want to shove it in an abstract method
        # and subclass Vlan, but the point is make it part of the
        # Vlan somehow.
        self.change_command = change_command
        self.interface = interface

    def change_vlan(self):
        ssh = self.interface.device.ssh
        ssh.command('setup commands')
        ssh.command(self.change_command)
        ssh.command('exit commands')

device1 = Device()
device2 = Device()

interface1 = Interface('i1', device1)
interface2 = Interface('i2', device1)
interface3 = Interface('i3', device2)

vlans = [
    Vlan('v1', 'change 1', interface1)
    Vlan('v2', 'change 2', interface1)
    Vlan('v3', 'change 3', interface2)
    Vlan('v4', 'change 4', interface3)
]

这可能不会显示完全您想要做什么,但希望它演示了如何使用层次结构以另一种方式设置它。

让装饰者接受Device

或者,如果你仍然认为装饰是一个更好的选择,你可以让装饰接受你需要的实例。

def ssh_command(device, function):
    def execute_ssh_command(*args, **kwargs):
        device.ssh.command('setup commands')
        device.ssh.command(wrapped command here)
        device.ssh.command('exit commands')
    # Note: no parentheses. You're returning the function itself
    return execute_ssh_command

class Interface(object):
    def __init__(self, name, parent):
        self.name
        self.parent
        self.vlan = Vlan('name')

    @ssh_command
    def set_interface(self):
        return self.name

请注意,对于任何使用装饰器的东西,你都需要创建一个单独的子类。

相关问题