I have some code like this:
class Person(object):
def drive(self, f, t):
raise NotImplementedError
class John(Person):
def drive(self, f, t):
print "John drove from %s to %s" % (f,t)
class Kyle(Person):
def drive(self, f, t):
print "Kyle drove from %s to %s" % (f,t)
class RandomPerson(Person):
# instansiate either John or Kyle, and inherit it.
pass
class Vehicle(object):
pass
class Driver(Person, Vehicle):
def __init__(self):
# instantiate and inherit a RandomPerson somehow
pass
d1 = Driver()
d1.drive('New York', 'Boston')
>>> "John drove from New York to Boston"
d2 = Driver()
d2.drive('New Jersey', 'Boston')
>>> "Kyle drove from New Jersey to Boston"
How could i implement RandomPerson, with the following requirements:
calling person = RandomPerson() must return a RandomPerson object.
RandomPerson should subclass either John or Kyle randomly.
In my original answer (which I deleted because it was just plain wrong) I said I would consider doing it like this:
class RandomPerson(Person):
def __init__(self):
rand_person = random.choice((John, Kyle))()
self.__dict__ = rand_person.__dict__
This way is an adaptation of the Python Borg idiom; the idea was that everything that matters about an object is contained in its __dict__.
However, this only works when overwriting objects of the same class (which is what you are doing in the Borg idiom); the object __dict__ only contains state information pertaining to object instance, not the object class.
It is possible to switch out the class of an object like so:
class RandomPerson(Person):
def __init__(self):
rand_person = random.choice((John, Kyle))
self.__class__ = rand_person
However, doing it this way would mean that the call to RandomPerson would then not return an instance of RandomPerson per your requirement, but of Kyle or of John. So this is a no go.
Here is a way to get a RandomPerson object that acts like Kyle or John, but isn't:
class RandomPerson(Person):
def __new__(cls):
new = super().__new__(cls)
new.__dict__.update(random.choice((Kyle,John)).__dict__)
return new
This one - very similar to the Borg idiom, except doing it with classes instead of instance objects and we're only copying the current version of the chosen class dict - is really pretty evil: we have lobotomized the RandomPerson class and (randomly) stuck the brains of a Kyle or John class in place. And there is no indication, unfortunately, that this happened:
>>> rperson = RandomPerson()
>>> assert isinstance(rperson,Kyle) or isinstance(rperson,John)
AssertionError
So we still haven't really subclassed Kyle or John. Also, this is really really evil. So please don't do it unless you have a really good reason.
Now, assuming you do in fact have a good reason, the above solution should be good enough if all you are after is making sure you can use any class state information (methods and class attributes) from Kyle or John with RandomPerson. However, as illustrated prior, RandomPerson still isn't a true subclass of either.
Near as I can tell there is no way to actually randomly subclass an object's class at instance creation AND to have the class maintain state across multiple instance creations. You're going to have to fake it.
One way to fake it is to allow RandomPerson to be considered a subclass of John and Kyle using the abstract baseclass module and __subclasshook__, and adding that to your Person class. This looks like it will be a good solution since the Person class is an interface and isn't going to be directly used, anyway.
Here's a way to do that:
class Person(object):
__metaclass__ = abc.ABCMeta
def drive(self, f, t):
raise NotImplementedError
#classmethod
def __subclasshook__(cls, C):
if C.identity is cls:
return True
return NotImplemented
class John(Person):
def drive(self, f, t):
print "John drove from %s to %s" % (f,t)
class Kyle(Person):
def drive(self, f, t):
print "Kyle drove from %s to %s" % (f,t)
class RandomPerson(Person):
identity = None
def __new__(cls):
cls.identity = random.choice((John,Kyle))
new = super().__new__(cls)
new.__dict__.update(cls.identity.__dict__)
return new
>>> type(RandomPerson())
class RandomPerson
>>> rperson = RandomPerson()
>>> isinstance(rperson,John) or isinstance(rperson,Kyle)
True
Now RandomPerson - though it technically is not a subclass - is considered to be a subclass of Kyle or John, and it also shares the state of Kyle or John. In fact, it will switch back and forth between the two, randomly, every time a new instance is created (or when RandomPerson.identity is changed). Another effect of doing things this way: if you have multiple RandomPerson instances, they all share the state of whatever RandomPerson happens to be in that moment -- i.e., rperson1 might start out being Kyle, and then when rperson2 is instantiated, both rperson2 AND rperson1 could be John (or they could both be Kyle and then switch to John when rperson3 is created).
Needless to say, this is pretty weird behavior. In fact it is so weird, my suspicion is that your design needs a complete overhaul. I really don't think there is a very good reason to EVER do this (other than maybe playing a bad joke on someone).
If you don't want to mix this behavior into your Person class, you could also do it separately:
class Person(object):
def drive(self, f, t):
raise NotImplementedError
class RandomPersonABC():
__metaclass__ = abc.ABCMeta
#classmethod
def __subclasshook__(cls, C):
if C.identity is cls:
return True
return NotImplemented
class John(Person, RandomPersonABC):
def drive(self, f, t):
print "John drove from %s to %s" % (f,t)
class Kyle(Person, RandomPersonABC):
def drive(self, f, t):
print "Kyle drove from %s to %s" % (f,t)
class RandomPerson(Person):
identity = None
def __new__(cls):
cls.identity = random.choice((John,Kyle))
new = super().__new__(cls)
new.__dict__.update(cls.identity.__dict__)
return new
You could just implement the RandomPerson class to have a member called _my_driver or whatever else you wanted. You would just call their drive method from the RandomPerson.drive method. It could look something like this:
class RandomPerson(Person):
# instantiate either John or Kyle, and inherit it.
def __init__(self):
self._my_person = John() if random.random() > 0.50 else Kyle()
def drive(self, f, t):
self._my_person.drive(f,t)
Alternatively, if you want to be more strict about making sure that the class has exactly the same methods as Kyle or John, you could set the method in the constructor like the following:
class RandomPerson(Person):
# instantiate either John or Kyle, and inherit it.
def __init__(self):
self._my_person = John() if random.random() > 0.50 else Kyle()
self.drive = self._my_person.drive
In your most recent comment on my other answer you said:
I'm gonna go with changing the class of the object, like you pointed out: rand_person = random.choice((John, Kyle)) and self.__class__ = rand_person. I've moved the methods of RandomPerson back into Person, and RandomPerson works now like a factory-ish generating class.
If I may say so, this is an odd choice. First of all, swapping out the class after object creation doesn't seem very pythonic (it's overly complicated). It would be better to generate the object instance randomly instead of assigning the class after the fact:
class RandomPerson(): # Doing it this way, you also don't need to inherit from Person
def __new__(self):
return random.choice((Kyle,John))()
Secondly, if the code has been refactored so that you no longer require a RandomPerson object, why have one at all? Just use a factory function:
def RandomPerson():
return random.choice((Kyle,John))()
Related
If I had a parent class attribute that all of the child classes are going to inherit, can I set a default so that when the object is created, it automatically take the default from the parent class and no argument has to be given when creating it?
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
def __init__(self, sick, cure):
super(F2, self).__init__(sick)
self.cure = cure
a = F2("bed rest")
print(a.sick)
print(a.cure)
this is just a sample bit of code to show what I mean. I want every child to inherit the "sick" from the parent so I do not have to send that argument in when creating the object. Is this possible? Is there a different way of doing this same thing? Would it be better to make "sick" a class attribute?
the problem with your code is, that you are declaring F2.__init__ to have two explicit arguments, even though you only want to pass one.
If you want to be able to optionally override the creation argument of F1 you need to handle that yourself (see F3)
class F1(object):
def __init__(self, sick="flu"):
self.sick = sick
class F2(F1):
def __init__(self, cure):
super(F2, self).__init__()
self.cure = cure
class F3(F1):
def __init__(self, cure, sick=None):
if sick is None:
super(F3, self).__init__()
else:
super(F3, self).__init__(sick)
self.cure = cure
a = F2("bed rest")
print("%s -> %s" % (a.sick, a.cure))
b = F3("inhale")
print("%s -> %s" % (b.sick, b.cure))
c = F3(sick="curiosity", cure="none")
print("%s -> %s" % (c.sick, c.cure))
Using super is the standard way of doing this in Python. If you want to override, just override...
class F2(F1):
def __init__(self, sick, cure):
super(F2, self).__init__(sick)
self.cure = cure
self.sick = sick + 1
Adding class attribute could be an option, depending on your need. From your description, I'd say it sounds better, because the default value of sick never change, and that's probably what you need.
Using class attribute does not affect overriding, because when assigning attribute on an instance, class attribute is not touched. An example:
>>> class F:
... a = 1
...
>>> f1, f2 = F(), F()
>>> f2.a = 2
>>> f1.a
1
Let's say we have a class A, a class B that inherits from A and classes C, D and E that inherit from B.
We want all of those classes to have an attribute _f initialized with a default value, and we want that attribute to be mutable and to have a separate value for each instance of the class, i.e. it should not be a static, constant value of A used by all subclasses.
One way to do this is to define _f in A's __init__ method, and then rely on this method in the subclasses:
class A:
def __init__(self):
self._f = 'default_value'
class B(A):
def __init__(self):
super(B, self).__init__()
class C(B):
def __init__(self):
super(C, self).__init__()
Is there any nice Pythonic way to avoid this, and possibly avoid using metaclasses?
If your goal is to simplify subclass constructors by eliminating the need the call the base class constructor, but still be able to override the default value in subclasses, there's a common paradigm of exploiting the fact that Python will return the class's value for an attribute if it doesn't exist on the instance.
Using a slightly more concrete example, instead of doing...
class Human(object):
def __init__(self):
self._fingers = 10
def __repr__(self):
return 'I am a %s with %d fingers' % (self.__class__.__name__, self._fingers)
class MutatedHuman(Human):
def __init__(self, fingers):
super(MutatedHuman, self).__init__()
self._fingers = fingers
print MutatedHuman(fingers=11)
print Human()
...you can use...
class Human(object):
_fingers = 10
def __repr__(self):
return 'I am a %s with %d fingers' % (self.__class__.__name__, self._fingers)
class MutatedHuman(Human):
def __init__(self, fingers):
self._fingers = fingers
print MutatedHuman(fingers=11)
print Human()
...both of which output...
I am a MutatedHuman with 11 fingers
I am a Human with 10 fingers
The important point being that the line self._fingers = fingers in the second example doesn't overwrite the default value set on class Human, but merely hides it when referenced as self._fingers.
It's slightly hairy when the variable refers to a mutable type, such as a list. You have to be careful not to perform a operation on the default value which will modify it, although it's still safe to do a self.name = value.
What's neat about this approach is it tends to lead to fewer lines of code than other approaches, which is usually a Good Thing (tm).
I am creating a module where I need to define a bunch of objects that will be used in the same module.
My ultimate goal is for something like this to work;
m = Mod()
obj1 = m.T1('text')
obj2 = m.T2(23)
m.togheter(obj1, obj2)
The problem I have is that I need to keep track of an ID in my subclasses.
I've gotten this far, which gives me an AttributeError: 'super' object has no attribute '_cid' from return super(Mod.ModObj, self)._cid
class Mod(object):
current_cid = 0
#property
def _cid(self):
c = self.current_cid
self.current_cid += 1
return c
def togheter(self, obj1, obj2):
# Do something with obj1.text and obj2.number here...
return True
class ModObj(object):
#property
def _cid(self):
return super(Mod.ModObj, self)._cid
class T1(ModObj):
def __init__(self, text):
self.text = text
print self._cid
class T2(ModObj):
def __init__(self, number):
self.number = number
print self._cid
m = Mod()
m.T1('text')
m.T2(23)
print m.current_cid # Should return 2
What is wrong here? I tried several other "trial and error" ways as well, but I am starting to think that I am doing this the completely wrong way...
ModObj doesn't inherit from Mod; it's just a nested class that inherits from object, and object indeed does not have a property (or any attribute) named _cid.
Your class ModObj is not a subclass of Mod, but a member. You probably want to say class ModObj(Mod).
Also note that as long as you do not override _cid in your subclass, there is no need to use super at all, as the superclass members automatically exist in the subclass (that's the point of class inheritance).
Finally - is that really what you want? It seems to me that you want each Mod instance to have a unique ID, and for each ModObj instance to inherit the ID of a specific Mod instance. Class inheritance will not do that. You might be looking for a parent-child relation.
I'm working in Python 2.7.8. What follows is a slight variant of the problem I'm working on.
I have a large number of custom classes that I've written where the inheritance is like a tree. The behavior is well encapsulated by the following example:
import random
class Animal(object):
def __init__(self, name):
self.name = name
self.can_own_pets = False #most Animals cannot own pets
self.get_features()
def give_pet(self, pet):
if not self.can_own_pets:
print(self.name+' cannot own a pet!')
else:
self.pets.append(pet)
def is_hungry(self):
return random.choice([True, False])
def get_features(self):
"""
In some classes, get features will be a function
that uses self.name to extract features.
In my problem, the features are extracted
with regular expressions that are determined by
by the class.
"""
pass
class Human(Animal):
def __init__(self, name):
super(Human, self).__init__(name)
self.can_own_pets = True
self.pets = []
class Dog(Animal):
def __init__(self, name):
super(Dog, self).__init__(name)
def bark(self):
print 'WOOF'
def get_features(self):
if 'chihuahua' in self.name:
self.is_annoying = True
elif 'corgi' in self.name:
self.adorable = True
My program needs to take in a large number of animals and delegate them to the correct classes -- I need the correct attributes and methods. What I would like to do is modify the Animal constructor so that if the name argument is something like "Finn the Dog" or "Jake the Human", it (the constructor) returns an instance of the class "Dog" or "Human", complete with the appropriate methods and attributes. Now, I know that I could easily write a function that takes a string and class as arguments, constructs a dictionary where the keys are the names of the subclasses of the given class, looks up the element of the dictionary that is contained in the string, and returns an object of that class. My question is whether or not there is a way to code this into the Animal class itself, which seems more elegant to me (as well as easier to maintain).
Here's an implementation --
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in _get_all_subclasses(scls):
yield scls
class Animal(object):
#staticmethod
def from_string(s):
for cls in _get_all_subclasses(Animal):
# Somehow pick the class based on the string... This is a really simple example...
if cls.__name__ in s:
return cls()
raise ValueError('Bummer. Animal has not been discovered.')
class Dog(Animal):
pass
class Cat(Animal):
pass
class Lion(Cat):
pass
print Animal.from_string('is a Dog')
print Animal.from_string('is a Cat')
print Animal.from_string('Lions!!!')
print Animal.from_string('Lockness Monster')
There are limitations here
All of the constructors need to be pretty much the same which means that Cat.__init__ needs to basically do the same thing that Human.__init__ does.
After you create the instance, your code needs to have logic to handle Cat, Human, Dog, etc. In some cases that's Ok (e.g. the code really only cares that it is working with an Animal), but frequently it isn't (after all, Cats can walk on fences, but Humans can't).
Generally, the principle that I like to live by is to try to make the inputs to my functions permissive (is it a list or a tuple? Who cares! Duck Typing FTW!) but to try to have really well defined outputs. I think that this makes interfaces easier to use in the long haul and the code that I wrote above would probably not pass a code review if I was the reviewer :-).
To build upon mgilson's answer
You can override the __new__ method so that you can instantiate the classes like normal without a static method.
class Animal(object):
#classmethod
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in scls._get_all_subclasses():
yield scls
def __new__(cls, name):
cls_ = cls
for subcls in Animal._get_all_subclasses():
if subcls.__name__ in name:
cls_ = subcls
break
instance = object.__new__(cls_)
if not issubclass(cls_, cls):
instance.__init__(name)
return instance
I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>