我想用来自父母"的装饰器来装饰某些实例函数。实例,有没有办法可以使用实例来装饰函数。
以下是我需要做的事情;
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
我希望这更有意义。如果没有,请告诉我。
答案 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" 从较低级别访问所需内容的方法。
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
请注意,对于任何使用装饰器的东西,你都需要创建一个单独的子类。