How to pass an augment in super() correctly - python

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.

Related

Correct way of returning new class object (which could also be extended)

I am trying to find a good way for returning a (new) class object in class method that can be extended as well.
I have a class (classA) which has among other methods, a method that returns a new classA object after some processing
class classA:
def __init__(): ...
def methodX(self, **kwargs):
process data
return classA(new params)
Now, I am extending this class to another classB. I need methodX to do the same, but return classB this time, instead of classA
class classB(classA):
def __init__(self, params):
super().__init__(params)
self.newParams = XYZ
def methodX(self, **kwargs):
???
This may be something trivial but I simply cannot figure it out. In the end I dont want to rewrite the methodX each time the class gets extended.
Thank you for your time.
Use the __class__ attribute like this:
class A:
def __init__(self, **kwargs):
self.kwargs = kwargs
def methodX(self, **kwargs):
#do stuff with kwargs
return self.__class__(**kwargs)
def __repr__(self):
return f'{self.__class__}({self.kwargs})'
class B(A):
pass
a = A(foo='bar')
ax = a.methodX(gee='whiz')
b = B(yee='haw')
bx = b.methodX(cool='beans')
print(a)
print(ax)
print(b)
print(bx)
class classA:
def __init__(self, x):
self.x = x
def createNew(self, y):
t = type(self)
return t(y)
class classB(classA):
def __init__(self, params):
super().__init__(params)
a = classA(1)
newA = a.createNew(2)
b = classB(1)
newB = b.createNew(2)
print(type(newB))
# <class '__main__.classB'>
I want to propose what I think is the cleanest approach, albeit similar to existing answers. The problem feels like a good fit for a class method:
class A:
#classmethod
def method_x(cls, **kwargs):
return cls(<init params>)
Using the #classmethod decorator ensures that the first input (traditionally named cls) will refer to the Class to which the method belongs, rather than the instance.
(usually we call the first method input self and this refers to the instance to which the method belongs)
Because cls refers to A, rather than an instance of A, we can call cls() as we would call A().
However, in a class that inherits from A, cls will instead refer to the child class, as required:
class A:
def __init__(self, x):
self.x = x
#classmethod
def make_new(cls, **kwargs):
y = kwargs["y"]
return cls(y) # returns A(y) here
class B(A):
def __init__(self, x):
super().__init__(x)
self.z = 3 * x
inst = B(1).make_new(y=7)
print(inst.x, inst.z)
And now you can expect that print statement to produce 7 21.
That inst.z exists should confirm for you that the make_new call (which was only defined on A and inherited unaltered by B) has indeed made an instance of B.
However, there's something I must point out. Inheriting the unaltered make_new method only works because the __init__ method on B has the same call signature as the method on A. If this weren't the case then the call to cls might have had to be altered.
This can be circumvented by allowing **kwargs on the __init__ method and passing generic **kwargs into cls() in the parent class:
class A:
def __init__(self, **kwargs):
self.x = kwargs["x"]
#classmethod
def make_new(cls, **kwargs):
return cls(**kwargs)
class B(A):
def __init__(self, x, w):
super().__init__(x=x)
self.w = w
inst = B(1,2).make_new(x="spam", w="spam")
print(inst.x, inst.w)
Here we were able to give B a different (more restrictive!) signature.
This illustrates a general principle, which is that parent classes will typically be more abstract/less specific than their children.
It follows that, if you want two classes that substantially share behaviour but which do quite specific different things, it will be better to create three classes: one rather abstract one that defines the behaviour-in-common, and two children that give you the specific behaviours you want.

Correct way of passing a self variable as argument to a mixin parent method

I have to model a warrior and the different kinds of attacks he can perform. The idea is to use mixins to contain the attack logic. I have my classes defined in the following way:
class Warrior:
def __init__(self, energy):
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self):
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self):
super().__init__()
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
But the problem comes when I try to test this setup. When I do
class TestTemplarKnight(unittest.TestCase):
def setUp(self):
self.templar = TemplarKnight(energy=100)
def test_templar_knight_can_sword_spin(self):
self.templar.sword_spin(self.warrior)
self.assertEquals(self.templar.energy, 90)
I get
def sword_spin(self, attacker):
return self.attack(
> attacker, self.attacks_cost['sword_spin'])
E AttributeError: 'TemplarKnight' object has no attribute 'attacks_cost'
It seems that Python thinks that the parameter self.attacks_cost (when calling self.attack() inside the sword_spin() method of the HandToHandCombatMixin class) belongs to the TemplarKnight class instead of the HandToHandCombatMixin.
How should I have written this code to make Python look for self.attacks_cost inside HandToHandCombatMixin?
To use super correctly, all the classes involved need to use it. Right now, Warrior.__init__ is called first, but it doesn't use super, so HandToHandCombatMixin.__init__ is never called.
Make the following additions:
class Warrior:
def __init__(self, energy, **kwargs):
super().__init__(**kwargs)
self.energy = energy
class TemplarKnight(Warrior, HandToHandCombatMixin):
pass
class CombatMixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.attacks_cost = {}
def attack(self, attacker, attack_cost):
if attacker.energy < attack_cost:
print('Not enough energy to attack')
else:
attacker.energy -= attack_cost
print('Attack!')
class HandToHandCombatMixin(CombatMixin):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.attacks_cost['sword_spin'] = 10
def sword_spin(self, attacker):
return self.attack(attacker, self.attacks_cost['sword_spin'])
Now when you instantiate TemplarKnight, you'll guarantee that all the __init__ methods are called, and in the correct order. Eventually, once of the calls to super() will cause object.__init__ to be called, at which point the chain finally ends. If you are correctly handling the keyword arguments, **kwargs will be empty by the time that happens.

Diamond inheritance in Python with different signatures

Here's the setup:
class Player(object):
def __init__(self, heigth):
self.heigth = heigth
print('do not forget that this should happen once!')
class Attacker(Player):
def __init__(self, heigth, goal_probability):
super().__init__(heigth)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, heigth, save_probability=0.1):
super().__init__(heigth)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(heigth=1.96, goal_probability=0.6)
It all works as expected: the MRO chooses Attacker first, then Goalie. I call UniversalPlayer's constructor with Attacker's __init__ signature, Goalie's constructor is called with Player's signature, it goes ok because save_probability has a default value but the problem is that I have no way of choosing save_probability, apart from setting up.save_probability after instantiating up, which I find very inelegant.
Furthermore, had Goalie not had a default value for save_probability, this code would raise an exception.
Is there a way to write UniversalPlayer so that I can choose save_probability too, or is there some fundamental problem here that cannot be worked around?
Each additional parameter to __init__ needs to have a class responsible for removing it from calls to super, so that when object.__init__ is finally called, you don't accidentally pass any arguments to it. Additionally, each method has to accept arbitrary arguments and pass them on for the next method to possibly handle.
# Player will be responsible for height
class Player(object):
def __init__(self, height, **kwargs):
super().__init__(**kwargs) # Player needs to use super too!
self.height = height
print('do not forget that this should happen once!')
# Attacker will be responsible for goal_probability
class Attacker(Player):
def __init__(self, height, goal_probability, **kwargs):
super().__init__(height, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# Goalie will be responsible for save_probability
class Goalie(Player):
def __init__(self, height, save_probability=0.1, **kwargs):
super().__init__(height, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
# Pass all arguments
# Life is easier if you stick to keyword arguments when using super().__init__
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)
Now, Attacker.__init__ is the first to be called. It uses goal_probability, then does not pass it on to other calls. It accepts save_probability via **kwargs and passes it on for Goalie.__init__ to eventually receive. Note that neither Attacker.__init__ nor Goalie.__init__ would have to explicitly include height in their argument lists; it could also be accepted via **kwargs to be eventually received by Player.__init__.
Besides the fact I'm not sure if separate classes is the best way to handle these, the issue is that your constructors can't handle unknown arguments. To allow them to use the *args, **kwargs notation.
Effectively all arguments will be passed to each __init__ and the unused ones ignored.
class Player(object):
def __init__(self, *args, **kwargs):
self.height = kwargs['height']
class Attacker(Player):
def __init__(self, goal_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.goal_prob = goal_probability
def hit(self):
pass
# implementation
class Goalie(Player):
def __init__(self, save_probability, *args, **kwargs):
super().__init__(*args, **kwargs)
self.save_prob = save_probability
def catch(self):
pass
# implementation
class UniversalPlayer(Attacker, Goalie):
pass
up = UniversalPlayer(height=1.96, goal_probability=0.6, save_probability=0.2)

Python instance Decorator

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.

Python: Instance class mutation

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)

Categories

Resources