I would like to decorate certain instance functions with a decorator from a "parent" instance, is there a way that I can use the instance to decorate the functions.
Here is the thought on what I need to do;
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
EDIT:
Ok guys here is the actual issue, I have a device that i need to interact with. So a device may have several levels to it ie a device a
has multiple interfaces and an interface may have multiple vlans attached. So the idea is that if I want to change a vlan on an interface, instead of building a full command I would like to allow the parent class to handle the building of it's level of the command. So I would like to just call the "change vlan" function and it will send it's part of the command to the next level to be wrapped and sent up the chain till it hits the device level and the full command is sent to the device.
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
I hope this makes more sense. if not please let me know.
No, you cannot use decorators here, because at definition time of Bar, parent is not known.
Simply use set_configuration with a argument:
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)
Python is a dynamic language so many things are possible. I'm making no comment about whether this is a good thing to do or not - and I really can't understand the purpose of your logic.
To make this possible you will need dynamically create the set_config_2 in Bar.__init__ as parent is unknown at the class definition time:
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()
Output:
foo bar
This is desperately ugly and there must be a better way of doing what you are attempting. Perhaps you can ask a different question explaining what you are trying to achieve.
Your decorator does not have to use instance methods, since that's the wrapping function config who needs them. Therefore, the decorator does not have to be a method. For example:
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
That said, there likely is a more straightforward and explicit way, depending on what exactly you want.
I'm pretty sure you can do this without making the decorator an instance. Here are a couple ideas.
Invert the hierarchy
It seems to me like the hierarchy you have is backwards. My understanding:
Device is only providing the ssh instance
The common method you want to call is something the VLAN defines
The setup and exit commands are constants
By making the hierarchy go the other way, you can define the "change VLAN" method to access stuff from the lower levels that it needs.
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)
]
This might not show exactly what you want to do, but hopefully it demonstrates how you can set this up with the hierarchy going the other way.
Make The decorator accept a Device
Alternatively, if you still think decorating is a better option, you can make the decorate accept the instances you need.
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
Note you'll need to make a separate subclass per whatever thing uses the decorator.
Related
I have two classes as follows:
class Buttons():
def __init__(self, dDict):
self.TCT = Tool()
self.dDict = dDict
def btnName(self):
# I will use both self.TCT and self.dDict here
a = self.dDict['setup']
class Switch(Buttons):
def __init__(self):
self.TCT =Tool()
I need to instantiate Switch class, but I need to provide dDict so that Buttons class will have the data it is looking for. What is the right way to instantiate the class Switch?
You can inherit the __init__ from your parent class as follows:
class Switch(Buttons):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Followed by init code that is used by Switch
This also means that you don't need to repeat the self.TCT =Tool() in your new __init__.
You can then safely call
switch = Switch(mydict)
I have two classes:
class Egg:
def __init__(self):
self._color = 'White'
class Larvae(Egg):
def __init__(self):
super().__init__()
self._color = 'Transparente'
To illustrate ...
So, in my code I have an Egg instance. When it's time I would like transform them into Larvae instances. I can create a Larvae instance and hand copy informations about a "previous" Egg instance. What does Python offer for something like that? For "mute" an instance in instance of subclass of its class?
Edit: As commented below, OOP in this question is not good way to do the wanted behavior. So, keep this in mind when reading answer
How about using a state-based approach?
class Ant:
def __init__(self, state='egg'):
self.state = state
#property
def color(self):
return {
'egg': 'Transparent',
'larvae': 'White,'
}[self.state]
def hatch(self):
if self.state == 'egg':
self.state = 'larvae'
else:
raise Exception('Cannot hatch if not an egg!')
This is possible, but not a great idea.
It is possible to change the type of an object after constructing it, but, well, it's just not robust. When you change the type of an object, its __init__() does not run. Any attributes left over from the old type are still there, and if they clash with attributes belonging to the new type, you probably have a nasty mess to deal with. If you're really sure this is the right approach, you can do it by assigning to the __class__ attribute (e.g. spam.__class__ = SomeClass). I strongly advise against this, however.
Instead, I would recommend factoring out the data you want to preserve into a "state" attribute, which you then transfer from one type to another. For example:
class Egg(object):
def __init__(self, state):
# Other egg-related stuff here...
self.state = state
def grow_up(self):
return Larva(self.state)
class Larva(object):
def __init__(self, state):
# Other larva-related stuff here...
self.state = state
def grow_up(self):
return Pupa(self.state)
class Pupa(object):
# and so on...
spam = Egg([1, 2, 3])
spam = spam.grow_up()
print(spam.state) # [1, 2, 3]
This answer has little to do with your request, but I find that it's worth to show that your OOP is a little bit counterintuitive. The whole point of OOP is that you create an intuitive inheritance hierarchy. There is little point in OO if your low level classes are supposed to be aware of higher level ones. In your use-case the Egg must be aware of the Larvae in order to transform, but that makes little sense. A parent class should not reference its child-classes.
class BaseInsect(object):
"""
Some stuff that all insects share at any stage
"""
def __init__(self, colour, *args, **kwargs):
self.colour = colour
...
class ImmatureAnt(BaseInsect):
...
class Egg(ImmatureAnt):
"""
Some egg-specific stuff
"""
def __init__(self, *args, **kwargs):
super(Egg, self).__init__("white")
...
class Larvae(ImmatureAnt):
def __init__(self, *args, **kwargs):
super(Larvae, self).__init__("transparent")
...
#staticmethod
def from_egg(egg, *args, **kwargs):
# make a larvae out of an egg
...
class BaseAdultAnt(BaseInsect):
"""
Some stuff all adult ants have
"""
...
class WorkerAnt(BaseAdultAnt):
...
class BaseReproducingAnt(BaseAdultAnt):
...
class Male(BaseReproducingAnt):
...
class Queen(BaseReproducingAnt):
...
Back to your question.
You've already been told that you can pass an Egg instance to the Larvae constructor. That will be a beautiful way. To make this answer a little bit less off-topic I'm giving an alternative solution. You might want to use several functions.
def egg_to_larvae(egg, *args, **kwargs):
"""
:param egg: an Egg instance
:type egg: Egg
"""
# do some stuff to get all the info needed to create a larvae...
return larvae
def larvae_to_pupae(larvae, *args, **kwargs):
...
return pupae
You get the idea
Just use a common base class instead of trying to inherit Larvae from an Egg:
class AntBase:
def __init__(self, color):
self._color = color
class Egg(AntBase):
def __init__(self, color='White'):
super().__init__(color)
class Larvae(AntBase):
def __init__(self, color='Transparente'):
super().__init__(color)
While Egg and Larvae are similar (both related to ants), Larvae is not an Egg, nor is an Egg a Larvae.
They are both "ant-things" though, thus we create a common AntBase class for all your ant things.
To convert an Egg into a Larvae, you can have a converter classmethod:
class AntBase:
def __init__(self, color):
self._color = color
#classmethod
def transform_from(cls, instance):
return cls(instance._color)
And now you can do:
egg0 = Egg()
larvae0 = Larvae.transform_from(egg0)
You can even have custom behaviour for each class:
class Larvae(AntBase):
#classmethod
def transform_from(cls, instance):
if isinstance(instance, AntMale):
raise ValueError("You can't have Larvae from AntMale")
return super().transform_from(instance)
My class takes an augment called resource:
> AClass(resource="123")
Class:
class AClass(Base):
def __init__(self, resource):
super(AClass, self).__init__(self)
Which will be set in the Base class it extends from.
class BaseHTTP(object):
def __init__(self, resource, data=None):
self.resource = resource
In Python 2.7 what should I be doing to make sure the base class gets these arguments, is this OK...
super(Get, self).__init__(self, resource)
You should not pass self to super(...).__init__, as super(...).__init__ returns the bound method:
class AClass(Base):
def __init__(self, resource):
super(AClass, self).__init__(resource)
Also, I'm not sure what Get is. Usually super's first argument should be the class from which it is called -- in this case, AClass.
Bonus trivia: super(...).__new__, in contrast, returns the staticmethod, since __new__ is a staticmethod. So for __new__, self must still be passed:
super(...).__new__(self, ...)
In addition to #unutbu's excellent answer, let me point out the canonical use of this idiom.
class Parent(object):
def __init__(self, name, species, gender):
self.name = name
self.color = color
self.species = species
self.gender = gender
self.children = []
def make_kid(self, partner, child_name):
if self.gender == "F":
return Child(mom=self, dad=partner, name=child_name,
species=self.species, gender=random.choice(["M", "F"]))
else:
return Child(mom=partner, dad=self, name=child_name,
species=self.species, gender=random.choice(["M", "F"]))
class Child(Parent):
def __init__(self, mom=None, dad=None, *args, **kwargs):
# a list of arguments we care about as a Child, followed by
# *args, **kwargs that other classes further up the MRO may need
self.mom = mom
self.dad = dad
# strip out the arguments we deal with here as a Child
super(Child, self).__init__(*args, **kwargs)
# then send the rest of them to the parent object
man = Parent("Adam","Human","M")
woman = Parent("Eve","Human","F")
child = man.make_kid(woman, "Junior")
I usually use:
class AClass(Base):
def __init__(self, resource):
Base.__init__(self, resource)
But #unutbu solution is better, I think.
Hope this helps.
There is an existing module I use containing a class that has methods with string arguments that take the form:
existing_object.existing_method("arg1")
or
existing_object.existing_method("arg1:arg2")
The arguments are in a hierarchical structure.
I would like to create a module that objectifies the arguments and makes them methods of the class of the imported module such that use would look like this:
my_object.arg1.my_method()
or
my_object.arg1.arg2.my_method()
my_method() would call existing_method() while passing it the "arg1:arg2" as an argument.
If someone could point me in the right direction to get started I'd appreciate it.
You can do this with a custom __getattr__ that returns special method caller instances:
class MethodCaller(object):
def __init__(self, args, parent):
self.args = args
self.parent = parent
def __getattr__(self, name):
return MethodCaller(self.args + (name,), self.parent)
def my_method(self):
return self.parent.existing_method(':'.join(self.args))
class MyClass(object):
def __getattr__(self, name):
return MethodCaller((name,), self)
def existing_method(self, arg):
print arg
Example:
>>> MyClass().arg1.my_method()
arg1
>>> MyClass().arg1.arg2.my_method()
arg1:arg2
>>> MyClass().foo.bar.my_method()
foo:bar
Thinking about this more clearly I realized that what I really wanted was to be able to use the IPython introspection of modules to navigate the hierarchy. This meant that I simply needed to create objects like this:
class Foo():
def __init__(self, arg):
self.arg = arg
def my_method(self.arg)
arg1 = Foo("arg1")
arg1.arg2 = Foo("arg1:arg2")
My apologies if this question has already been answered somewhere, but if it has I have not been able to locate the answer.
I would like to create a sub-class of a parent class in such a way that there will be a delay (e.g. time.sleep()) before each call to the corresponding parent class method. I would like to do this in such a way that I do not need to replicate each parent class method in the child class. In fact, I would like to have a generic method that would work with virtually any parent class -- so that I do not even need to know all the parent class methods.
The delay would be specified when instantiating the sub-class.
For example:
class Parent():
....
def method1(self):
....
def method2(self):
....
class Child(Parent):
def __init__(self, delay)
self.delay = delay
....
child = Child(1)
A call to child.method1() would result in a 1 second delay before Parent.method1() is called.
I think the previously given answers have not really addressed your specific need to delay ALL methods from the parent class, and not necessarily have to go and decorate them. You said you do NOT want to have to replicate the parent class method in the child class just so that you can delay them. This answer uses the same delay wrapper from S.Lott, but also uses a metaclass (http://www.voidspace.org.uk/python/articles/metaclasses.shtml)
#!/usr/bin/env python
from types import FunctionType
import time
def MetaClassFactory(function):
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if type(attribute) == FunctionType:
attribute = function(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
return MetaClass
def delayed(func):
def wrapped(*args, **kwargs):
time.sleep(2)
func(*args, **kwargs)
return wrapped
Delayed = MetaClassFactory(delayed)
class MyClass(object):
__metaclass__ = Delayed
def a(self):
print 'foo'
def b(self):
print 'bar'
The MetaClassFactory wraps every function in the delayed decorator. If you wanted to make sure certain built-ins like the init function were not delayed, you could just check for that name in the MetaClassFactory and ignore it.
Really, what you have here is a design that involves a Strategy object.
Your best approach is to fix the parent class to include a call to a "delay object". A default delay object does nothing.
This violates the "so that I do not even need to know all the parent class methods" hoped-for feature set.
Method lookup doesn't have a handy __getmethod__ that corresponds to __getattribute__; this gap makes it difficult to tap into Python's internals for method invocation.
class Parent( object ):
delay= ZeroDelay()
def method1(self):
self.delay()
....
def method2(self):
self.delay()
...
class ZeroDelay( object ):
def __call__( self ):
pass
class ShortDelay( ZeroDelay ):
def __init__( self, duration=1.0 )
self.duration= duration
def __call__( self ):
time.sleep( self.duration )
class Child( Parent ):
delay= ShortDelay( 1 )
EDIT: Of course, you can decorate each method, also.
def delayed( delayer ):
def wrap( a_method ):
def do_delay( *args, **kw ):
delayer()
return a_method( *args, **kw )
return do_delay
return wrap
class Parent( object ):
delay= ZeroDelay()
#delayed( self.delay )
def method1(self):
self.delay()
....
#delayed( self.delay )
def method2(self):
self.delay()
...
S.Lott solution is a good one. If you need more granularity (i.e. to delay only certain methods, not all of them), you could go with a decorator:
from time import sleep
def delayed(func):
'''This is the decorator'''
def wrapped(*args, **kwargs):
sleep(2)
func(*args, **kwargs)
return wrapped
class Example(object):
#delayed
def method(self, str):
print str
e = Example()
print "Brace! I'm delaying!"
e.method("I'm done!")
The idea is that you add #delayed in before the definition of those methods you want to delete.
EDIT: Even more granularity: setting an arbitrary delay:
from time import sleep
def set_delay(seconds):
def delayed(func):
'''This is the decorator'''
def wrapped(*args, **kwargs):
sleep(seconds)
func(*args, **kwargs)
return wrapped
return delayed
class Example(object):
#set_delay(1)
def method(self, str):
print str
#set_delay(2)
def method_2(self, str):
print str
e = Example()
print "Brace! I'm delaying!"
e.method("I'm done!")
e.method_2("I'm also done!")
You can achieve what you want by using the method __getattribute__
class Child(Parent):
def __init__(self, delay):
self.delay = delay
def __getattribute__(self, name):
attr = object.__getattribute__(self, name)
if hasattr(attr, '__call__'):
def proxFct(*args, **kwargs):
time.sleep(object.__getattribute__(self, "delay"))
return attr(*args, **kwargs)
return proxFct
else:
return attr
Update: Updated according delnan's comment
Update 2: Updated according delnan's second comment