Is it possible, when instantiating an object, to pass-in a class which the object should derive from?
For instance:
class Red(object):
def x(self):
print '#F00'
class Blue(object):
def x(self):
print '#00F'
class Circle(object):
def __init__(self, parent):
# here, we set Bar's parent to `parent`
self.x()
class Square(object):
def __init__(self, parent):
# here, we set Bar's parent to `parent`
self.x()
self.sides = 4
red_circle = Circle(parent=Red)
blue_circle = Circle(parent=Blue)
blue_square = Square(parent=Blue)
Which would have similar effects as:
class Circle(Red):
def __init__(self):
self.x()
without, however, affecting other instances of Circle.
Perhaps what you are looking for is a class factory:
#!/usr/bin/env python
class Foo(object):
def x(self):
print('y')
def Bar(parent=Foo):
class Adoptee(parent):
def __init__(self):
self.x()
return Adoptee()
obj=Bar(parent=Foo)
I agree with #AntsAasma. You should probably consider using dependency injection. Atleast in the example given (which I'm sure is greatly simplified to illustrate your problem), the color of a shape is better represented by via a has-a relationship rather than with a is-a relationship.
You could implement this via passing in the desired color object to the constructor, storing a reference to it, and delegating the function call to this object. This greatly simplifies the implementation while still retaining the desired behavior. See an example here:
class Red(object):
def x(self):
print '#F00'
class Blue(object):
def x(self):
print '#00F'
class Shape(object):
def __init__(self,color):
self._color=color
def x(self):
return self._color.x()
class Circle(Shape):
def __init__(self, color):
Shape.__init__(self,color)
self.x()
class Square(Shape):
def __init__(self, color):
Shape.__init__(self,color)
self.x()
self.sides = 4
red_circle = Circle(color=Red())
blue_circle = Circle(color=Blue())
blue_square = Square(color=Blue())
Edit: Fixed names of constructor arguments in sample code
It sounds like you are trying to use inheritance for something that it isn't meant for. If you would explain why you want to do this, maybe a more idiomatic and robust way to achieve your goals can be found.
If you really need it, then you could use type constructor, e.g. within a factory function (or inside __new__ method, but this is probably safer approach):
class Foo(object):
def x(self):
print 'y'
class Bar(object):
def __init__(self):
self.x()
def magic(cls, parent, *args, **kwargs):
new = type(cls.__name__, (parent,), cls.__dict__.copy())
return new(*args, **kwargs)
obj = magic(Bar, parent = Foo)
As everybody else says, that's a pretty weird usage, but, if you really want it, it's surely feasible (except for the mysterious Bar that you pull out of thin air in comments;-). For example:
class Circle(object):
def __init__(self, parent):
self.__class__ = type('Circle', (self.__class__, parent), {})
self.x()
This gives each instance of Circle its own personal class (all named Circle, but all different) -- this part is actually the key reason this idiom is sometimes very useful (when you want a "per-instance customized special method" with new-style classes: since the special method always gets looked up on the class, to customize it per-instance you need each instance to have a distinct class!-). If you'd rather do as much class-sharing as feasible you may want a little memoizing factory function to help:
_memo = {}
def classFor(*bases):
if bases in _memo: return _memo[bases]
name = '_'.join(c.__name__ for c in bases)
c = _memo[bases] = type(name, bases, {})
return c
(here I'm also using a different approach to the resulting class's name, using class names such as Circle_Red and Circle_Blue for your examples rather than just Circle). Then:
class Circle(object):
def __init__(self, parent):
self.__class__ = classFor(Circle, parent)
self.x()
So the technique is smooth and robust, but I still don't see it as a good match to the use case you exemplify with. However, it might be useful in other use cases, so I'm showing it.
Related
Hello!
I need each child class to has own set of constants. I've found a "proper" way with properties and overloading setter methods, but:
I need to define constructor in child classes (which I don't need) and assign values in constructor;
Every instance of class will have copy of this constants in memory (senseless resource consumption);
It looks weird when you define setter, getter and property at all just to use it as constant.
I've done something like this:
class BaseClass:
def get_a(self):
raise NotImplementedError("Oooops")
def get_b(self):
raise NotImplementedError("Oooops")
class FirstClass(BaseClass):
def get_a(self):
return "a"
def get_b(self):
return "b"
class SecondClass(BaseClass)
def get_a(self):
return "A"
def get_b(self):
return "B"
class SomeClass:
def some_method(self, class_param):
return "{}-{}".format(class_param.get_a, class_param.get_b)
This method also doesn't solve problems of method with properties (except last), just more compact. There's other way, which I find not good:
class BaseClass:
pass
class FirstClass(BaseClass):
A_CONST = "a"
B_CONST = "b"
class SecondClass(BaseClass)
A_CONST = "A"
B_CONST = "B"
class SomeClass:
def some_method(self, class_param):
return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)
In fact, it solve all problems and pretty compact, BUT it violates rule of inheritance (isn't it?).
Question:
What is the proper way to do this?
P.S. Provided code is simplified example, base class contains methods which I use in child class, please don't write me that base class is useless here.
If you want your base class to indicate that it needs to be subclassed with certain attributes, you can make it an abstract base class.
from abc import ABC, abstractmethod
class Base(ABC):
#property
#abstractmethod
def a(self):
raise NotImplementedError
#property
#abstractmethod
def b(self):
raise NotImplementedError
You will then not be allowed to instantiate Base or its subclasses unless they override the abstract methods. You can do either
class First(Base):
a = 1
b = 2
to assign class attributes with those names, or
class Second(Base):
#Base.a.getter
def a(self):
return 3
#Base.b.getter
def b(self):
return 4
The benefit of the second approach is that it will raise an error if you try to assign to the property
Second().a = 5 # AttributeError
your second version looks fine to me… each language has their own conventions around what a "class" or "object" means, and this looks reasonably "Pythonic"
one minor comment about the first version, is that Python doesn't care about "overloading", you don't need to include:
class BaseClass:
def get_a(self):
raise NotImplementedError("Oooops")
at all, i.e. it's fine to have:
class BaseClass:
pass
as well in your first version.
another potentially useful tool here is the property decorator, e.g:
class FirstClass(BaseClass):
#property
def a(self):
return "a"
print(FirstClass().a)
would output "a"
If the key_name : [A_CONST, B_CONST] remains same for child classes, super() will take care of all your concerns (1., 2., 3.).
A 'pythonic' solution would include, to remove duplication's, of any, setter and getter in child classes and let BaseClass() handle these common-tasks.
class BaseClass(object):
def __init__(self, a, b):
self._a_const = a
self._b_const = b
#property
def A_CONST(self):
return self._a_const
#property
def B_CONST(self):
return self._b_const
class FirstClass(BaseClass):
def __init__(self, _aconst, _bconst):
# Let Base class object hold my constants but FirstClass Constructor
# is setting the value. Look SecondClass
super(FirstClass, self).__init__(_aconst, _bconst)
class SecondClass(BaseClass):
def __init__(self, _aconst, _bconst):
# Magic happens here
super(SecondClass, self).__init__(_aconst, _bconst)
class SomeClass():
def some_method(self, class_param):
return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)
firstobj = FirstClass("a", "b")
secondobj = SecondClass("A", "B")
print(SomeClass().some_method(firstobj))
print(SomeClass().some_method(secondobj))
I'm trying to come up with a way to allow specification of any number of class attributes upon instantiation, very similar to a dictionary. Ideal use case:
>>> instance = BlankStruct(spam=0, eggs=1)
>>> instance.spam
0
>>> instance.eggs
1
where BlankStruct is defined as:
class BlankStruct(Specifiable):
#Specifiable.specifiable
def __init__(self, **kwargs):
pass
I was thinking of using a parent class decorator, but am lost in a mind-trip about whether to use instance methods, class methods or static methods (or possibly none of the above!). This is the best I've come up with so far, but the problem is that the attributes are applied to the class instead of the instance:
class Specifiable:
#classmethod
def specifiable(cls, constructor):
def constructor_wrapper(*args, **kwargs):
constructor(*args, **kwargs)
cls.set_attrs(**kwargs)
return constructor_wrapper
#classmethod
def set_attrs(cls, **kwargs):
for key in kwargs:
setattr(cls, key, kwargs[key])
How can I make such a parent class?
NOTE:
Yes, I know what I'm trying to do is bad practice. But sometimes you just have to do what your boss tells you.
Yes, you can do the following, however I do NOT recommend as this clearly goes against the explicit is better than implicit principle:
class BlankStruct:
def __init__(self, **attrs):
self.__dict__.update(**attrs)
def __getattr__(self, attr):
return self.__dict__.get(attr, None)
f = BlankStruct(spam=0, eggs=1)
A more complete response is available here and inspired this answer.
I would recommend being explicit in terms of the properties you want your class to have. Otherwise, you are left with a class that has a high degree of variability, which likely detracts for it's usefulness.
I believe you can do this without decorators:
class Specifiable:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
class BlankStruct(Specifiable):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Do other stuff.
I've searched for this for a few hours today but didn't get a recent and satisfactorily definitive answer.
Suppose we have two particular classes that have both overlapping method names and specific individual methods. Getting rid of the unnecessary parts let's work with the following classes.
class A():
def __init__(self, a_arg1, a_arg2):
self.a_arg1 = a_arg1
self.a_arg2 = a_arg2
#property
def gimme_1(self):
return self.a_arg1
#property
def gimme_2(self):
return self.a_arg2
#property
def prop(self):
return 'A'
and also
class B():
def __init__(self, b_arg1, b_arg2, b_arg3):
self.b_arg1 = b_arg1
self.b_arg2 = b_arg2
self.b_arg3 = b_arg3
#property
def give_1(self):
return self.b_arg1
#property
def give_2(self):
return self.b_arg2
#property
def give_3(self):
return self.b_arg3
#property
def prop(self):
return 'B'
My goal is to make a third class that can morph into one of these, namely, it will have all the methods that these two have and act as if it is one of them whichever is requested. That's the motivation for the title of the question.
class C(A, B):
def __init__(self, some_list):
self.some_list = some_list
#property
def gimme_1(self):
return self.some_list[0]
#property
def gimme_2(self):
return self.some_list[1]
#property
def give_1(self):
return self.some_list[0] ** 2
#property
def give_2(self):
return self.some_list[1] ** 2
#property
def give_3(self):
return self.some_list[2]
#property
def prop(self):
return 'C'
Concrete questions:
Do we have to initialize the parents for this particular instance? If yes how should the super() be used.
This would really help me getting away with isinstance(x, A) or isinstance(x, B) type of querying. Is there any best practice that discourages such usage? Notice that the Pythonic duck typing is really not so relevant for me in my case. There are a lot of branching necessarily happening for different computational algorithms. Hence I'm really using classes as data-bundling containers but not using them as state recorders. In other words, there is hardly ever change in their instance data. But their data is used in different branches depending on which class they are. Therefore getting the right kind of object is essential for me.
Instead of rewriting the methods, why not take advantage of the benefits of inheritance? Let the parent __init__s take care of setting up instance values, and let them provide the method implementations.
class C(A, B):
def __init__(self, arg1, arg2, arg3):
A.__init__(self, arg1, arg2)
B.__init__(self, arg1**2, arg2**2, arg3)
#property
def prop(self):
return 'C'
I want to create method (say copy) in a class (Parent) that will return an object of either the class or the subclass that invokes it. I want type(x) == type(x.copy()).
None of the approaches I tried were satisfactory.
Using the superclass constructor returns the superclass (make senses but I figured it was worth a try).
Creating a function init_me in each subclass that the super class uses but that defeats the purpose of inheritance.
I started to explore __new__ and __init__, but quickly decided Python must have a better way.
Sample code
class Parent(object):
def __init__(self, p1=p1_default, p2=p2_default, p3=p3_default):
... # common stuff
self._special_suff()
def copy_works_if_subclass_does_extra(self):
return self.init_me()
def copy_only_does_superclass(self):
return Parent()
def copy_with_init(self):
return self.__init__()
def whoami(self):
print('I am just a parent')
class Dad(Parent):
def _special_stuff():
... # Dad special stuff
return
def whoami(self):
print('I am a dad')
def init_me(self):
return Dad()
class Mom(Parent):
def _special_stuff():
... # Mom special stuff
return
def whoami(self):
print('I am a mom')
If I understand correctly, you're trying to write a copy method in your base class that will still work when called on an instance of a derived class. This can be made to work, but it's only easy if your child classes only expect the same set of arguments as the base class. If their __init__ method expects different arguments you'll need separate copy methods for each derived class.
Here's a quick example of how it can work. The trick is to call type(self) to get the right class, and then call the class with appropriate constructor arguments to get the new instance:
class Base(object):
def __init__(self, arg1, arg2, arg3):
self.attr1 = arg1
self.attr2 = arg2
self.attr3 = arg3
def copy(self):
cls = type(self)
return cls(self.attr1, self.attr2, self.attr3)
class Derived(Base):
def __init__(self, arg1, arg2, arg3):
super().__init__(arg1, arg2, arg3)
self.some_other_attr = "foo"
In practice this tends not to work as well, since the Derived class will usually want to take an extra argument to set up its extra attribute. An option that might work in that situation is to use the copy module rather than writing your own copy method. The function copy.copy will be able to copy many Python instances without any special support.
You are overcomplicating things a lot. Minimal example with a simple constructor implemented on the child class:
import copy
class Parent():
def whoami(self):
print('Just a parent')
def __init__(self, name):
self.name = name
def copy(self):
# Maybe copy.deepcopy instead
return copy.copy(self)
class Dad(Parent):
def whoami(self):
print('I am a dad')
def __init__(self, name):
super().__init__(name)
self.gender = 'Male'
You don't even need a constructor in Python if you don't need. Or you can have one on the superclass and nothing on the child.
Some usage:
>>> dad = Dad("Clark Griswold")
>>> dad.name
'Clark Griswold'
>>> dad.whoami()
I am a dad
>>> isinstance(dad, Dad)
True
>>> isinstance(dad, Parent)
True
>>> type(dad.copy()) == type(dad)
True
I've got a class of the form:
class MyClass(object):
def curves(self):
def plot(self):
plot a graph
return something
return a pd.DataFrame
What I want to do is define something I can call with instance_of_my_class.curves.plot()
Do I need to define curves as an object to make this possible? I'm looking for the shortest way to do it, as this is syntactic sugar only.
Thanks.
In order to add a level of hierarchy, curves needs to be an actual object, yes. There is no difference between foo.curves.plot() and the following:
c = foo.curves
c.plot()
So foo.curves needs to be an object that has a plot method.
Also, since the method is called on the curves object, the method will be bound to that object. So unless you set it up that way, the curves object will not have access to your actual class.
You could pass the instance in the curves constructor though:
class Curves (object):
def __init__ (self, parent):
self.parent = parent
def plot (self):
self.parent._plot()
class MyClass (object):
def __init__ (self):
self.curves = Curves(self)
def _plot (self):
print('Actual plot implementation')
Then you can use it as foo.curves.plot():
>>> foo = MyClass()
>>> foo.curves.plot()
Actual plot implementation
You could also automate this a bit by using a descriptor for curves. For example, this is a possible solution:
class Accessor (object):
def __init__ (self, prefix = ''):
self.prefix = prefix
def __get__ (self, instance, owner):
return AccessorDelegate(instance, self.prefix)
class AccessorDelegate (object):
def __init__ (self, instance, prefix):
self.instance = instance
self.prefix = prefix
def __getattr__ (self, name):
return getattr(self.instance, self.prefix + name)
The benefit is obviously that you only need to define those a single time and then they’ll work for all your classes. You would use it like this in your class:
class MyClass (object):
curves = Accessor('_curves_')
def _curves_plot(self):
print('Implementation of curves.plot')
Used exactly as above:
>>> foo = MyClass()
>>> foo.curves.plot()
Implementation of curves.plot