Python, how to flexibly create subclass? - python

The detail question is I have a plenty of classes, say A, B, C, D...Z, they're all derived from 'Base'. They all have a method set_value. Now I need to have some subclasses to override set_value of A...Z, the implement of new set_value are the same for all. Theoretically, I can do something like class AA(A), class BB(B)... but it's tedious and not compact, I am not sure if one or all of A...Z need a subclass, I only want to create it when I create an object of the subclass.
In C++, I can do this easily via template:
template<class T>
class CCustom : public T
{
};
CCustom<vector<int> > obj1;
CCustom<list<char> > obj2;
Add some demo Python scripts here to help explain my question:
class Base:
def set_value(self):
pass
class A(Base):
def set_value(self):
print('A.set_value')
class B(Base):
def set_value(self):
print('B.set_value')
class C(Base):
def set_value(self):
print('C.set_value')
def more_set_value():
print('all subclasses do this')
class AA(A):
def set_value(self):
more_set_value()
super().set_value()
class BB(B):
def set_value(self):
more_set_value()
super().set_value()
class CC(C):
def set_value(self):
more_set_value()
super().set_value()
a = AA()
b = BB()
c = CC()
a.set_value()
b.set_value()
c.set_value()
You can see AA, BB and CC are almost same. It's boring when there are hundreds this kind of class need to put in my project. I reckon there must be a way to write a factory function, to create AA, BB and CC dynamically, so that I can do following:
AA = create_custom_subclass(A)
a = AA()
a.set_value()

Classes are first-class citizens in Python, i.e. you can treat them like any other object. For example you can do a simple factory:
def create_custom_subclass(cls):
class sub(cls):
def set_value(self):
more_set_value()
super().set_value()
return sub
AA = create_custom_subclass(A)
a = AA()
a.set_value()
Or you can do a mixin (uses less memory then a factory):
class Mixin:
def set_value(self):
more_set_value()
super().set_value()
class AA(Mixin, A):
pass

It's not entirely clear to me what it is you want to do, but I'll try to give you some pointers so to speak.
Unlinke C++, Python uses a dynamic type system, i.e. a variable can be assigned an object of any type. This gives you a whole range of possibilities.
class CustomClass(object):
def __init__(self, obj_of_t_class):
self.obj_of_t_class = obj_of_t_class
def set_value(self, value):
self.obj_of_t_class.some_method(value)
# do something else here
As long as obj_of_t_class has the methods you try to call, Python doesn't care if it's of type A, B or Z.
This should be roughly equivalent to what you want to do with the C++ template class.

Related

Refactoring a class method to be under an abstract base class and splitting the logic without changing the base class method signature?

I'm currently working on redesigning a class to be under an abstract base class. The current class has a method func that does some logic for two things, say A and B.
(note that all the code below is very simplified. There's a lot more functionality than what is shown)
class current_class:
def func(self):
# does stuff for A
# does stuff for B
During logic A, it loads a large dataset into a dictionary, say, dataset and later dataset.keys() is used for logic B, but other than that, A and B are independent of each other.
I will create an alternate class, say, another_class that is similar to current_class, but this class doesn't need B and only needs A. So something like
class another_class:
def func(self):
# does stuff for A
And then both will be under an abstract base class base. Since both inherited classes involves A, I plan on just creating a method in base class that does A, say, func_A. But I'm having trouble with figuring out the best way to approach this so that the function signatures conform and without having to reload dataset for B.
If another_class also needed the logic for B, I think we can just return dataset.keys() from func_A and use it in func_B, but another_class doesn't.
So I don't know if there's a good way to conform this without having different signatures for the methods.
So in code, I have the following two ideas:
1)
class base:
#abstractmethod
def func(self):
pass
def func_A(self):
# does stuff for A and gets the dataset
return dataset.keys()
class current_class:
def func_B(self, keys):
# does stuff for B
def func(self):
keys = self.func_A
self.func_B(keys)
class current_class:
def func(self):
_ = self.func_A() # the return is unused...
class base:
#abstractmethod
def func(self):
pass
class current_class:
def func_A(self):
# does stuff for A and gets the dataset
return dataset.keys()
def func_B(self, keys):
# does stuff for B
def func(self):
keys = self.func_A()
self.func_B(keys)
class current_class:
def func_A(self):
# does same stuff as func_A for current_class, and doesn't return anything
def func(self):
self.func_A()
I don't like the first design because func_A only needs to return something for one of the subclasses and not for all of them. I also don't like the second design because we have to separately implement func_A in each inherited class even though they're identical methods, except one needs to return something and the other doesn't.
It's not a big deal to ignore the return value of a function that is primarily called for its side effects. Just define func_A once in the base class and let both child classes use it as appropriate to their needs.
class Base:
#abstractmethod
def func(self):
pass
def func_A(self):
# does stuff for A and gets the dataset
return dataset.keys()
class Child1:
def func_B(self, keys):
# does stuff for B
def func(self):
keys = self.func_A
self.func_B(keys)
class Child2:
def func(self):
self.func_A()
If there is more in func_A that isn't necessary for Child2, then it should of course be split up to avoid doing unnecessary work in Child2.func. But simply returning a value is not in anyway time- or space-intensive, and should not be a concern.

Python Classes: turn all inherited methods private

Class Bar inherits from Foo:
class Foo(object):
def foo_meth_1(self):
return 'foometh1'
def foo_meth_2(self):
return 'foometh2'
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
Is there a way of turning all methods inherited from Foo private?
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
def __foo_meth_1(self):
return 'foometh1'
def __foo_meth_2(self):
return 'foometh2'
Python doesn't have privates, only obfuscated method names. But I suppose you could iterate over the methods of the superclass when creating the instance, removing them from yourself and creating new obfuscatingly named method names for those functions. setattr and getattr could be useful if you use a function to create obfuscated names.
With that said, it's a pretty cthuhlu-oid thing to do. You mention the intent is to keep the namespace cleaner, but this is more like mixing ammonia and chlorine. If the method needs to be hidden, hide it in the superclass. The don't create instances of the superclass -- instead create a specific class that wraps the hidden methods in public ones, which you could name the same thing but strip the leading whitespace.
Assuming I understand your intent correctly, I would suggest doing something like this:
class BaseFoo(object):
def __init__(self):
raise NotImplementedError('No instances of BaseFoo please.')
def _foo(self):
return 'Foo.'
def _bar(self):
return 'Bar.'
class HiddenFoo(BaseFoo):
def __init__(self): pass
class PublicFoo(BaseFoo):
def __init__(self): pass
foo = BaseFoo._foo
bar = BaseFoo._bar
def try_foobar(instance):
print 'Trying ' + instance.__class__.__name__
try:
print 'foo: ' + instance.foo
print 'bar: ' + instance.bar
except AttributeError, e:
print e
foo_1 = HiddenFoo()
foo_2 = PublicFoo()
try_foobar(foo_1)
try_foobar(foo_2)
And if PublicFoo.foo would do something more than BaseFoo.foo, you would write a wrapper that does whatever is needed, and then calls foo from the superclass.
This is only possible with Pyhtons's metaclasses. But this is quite sophisticated and I am not sure if it is worth the effort. For details have a look here
Why would you like to do so?
Since foo() and __foo() are completely different methods with no link between them, Python is unable to understand what you want to do. So you have to explain to it step by step, meaning (like sapth said) to remove the old methods and add new ones.
This is an Object Oriented Design flaw and a better approach would be through delegation:
class Basic:
def meth_1(self):
return 'meth1'
def meth_2(self):
return 'meth2'
class Foo(Basic):
# Nothing to do here
pass
class Bar:
def __init__(self):
self.dg = Basic()
def bar_meth(self):
return 'bar_meth ' + self.__meth_1()
def __meth_1(self):
return self.dg.meth_1()
def __meth_2(self):
return self.dg.meth_2()
While Foo inherits the Basic class because he wants the public methods from him, Bar will only delegate the job to Basic because he doesn't want to integrate Basic's interface into its own interface.
You can use metaclasses, but Boo will no longer be an actual subclass of Foo, unless you want Foo's methods to be both 'private' and 'public' in instances of Bar (you cannot selectively inherit names or delattr members inherited from parent classes). Here is a very contrived example:
from inspect import getmembers, isfunction
class TurnPrivateMetaclass(type):
def __new__(cls, name, bases, d):
private = {'__%s' % i:j for i,j in getmembers(bases[0]) if isfunction(j)}
d.update(private)
return type.__new__(cls, name, (), d)
class Foo:
def foo_meth_1(self): return 'foometh1'
def foo_meth_2(self): return 'foometh2'
class Bar(Foo, metaclass=TurnPrivateMetaclass):
def bar_meth(self): return 'bar_meth'
b = Bar()
assert b.__foo_meth_1() == 'foometh1'
assert b.__foo_meth_2() == 'foometh2'
assert b.bar_meth() == 'bar_meth
If you wanted to get attribute access working, you could create a new Foo base class in __new__ with all renamed methods removed.

How to share attributes without an is-a relationship in Python?

I have a number of Python types that describe a hierarchy in the sense that they are increasingly specific in terms of their properties. Instead of trying to describe it in words, here is an example:
class A:
#property
def prop1(self):
return self._prop1
class B:
#property
def prop1(self):
return self._prop1
#property
def prop2(self):
return self._prop2
class C:
#property
def prop1(self):
return self._prop1
#property
def prop2(self):
return self._prop2
#property
def prop3(self):
return self._prop3
So, as you go down the class list, B has all of the properties of A and then some extra ones. C has all of the properties of B and then some extra ones, and so on. I would like to minimize the duplication of the above definitions if possible.
One obvious solution would be to use inheritance, making B a subclass of A and so on. However, the semantics of these types do not follow an is-a relationship; I do not want isinstance(bObject, A) to be True. Is there an alternative way in Python to straightforwardly allow this sharing of attributes without using subclasses?
You can use a decorator:
def has_prop1(cls):
#property
def prop1(self):
return self._prop1
cls.prop1 = prop1
return cls
#has_prop1
class A(object):
pass
Compositing would go like this:
#has_prop1
#has_prop2
class B(object):
pass
Or even like this:
def has_many_properties(cls):
return has_prop1(has_prop2(has_prop3(cls)))
#has_many_properties
class C(object):
pass
You say "I don't want to lie and say that C is an A when it really isn't. The characteristics of the types don't fit the semantics of subclassing." With your obscured example, it's not clear which way to go.
If you're saying this because there's additional functionality in class A that doesn't apply to class C, then I would hoist out the property part of the class compositionally, so you have A, B, C containing AProps, BProps, and CProps respectively, and give the property classes a proper inheritance relationship.
If there's no such additional functionality, and it's not just coincidental that the properties are built up the way you show, then mentally rename class A to class ProvidesProp1, note that class C is-a class that provides prop1, and accept that class C therefore is-a class A.

Inheriting properties of a separate class in Python

I am instantiating a class inside another one:
class A(F):
def __init__(self):
return
b = B()
Class B also inherits class F:
class B(F):
def __init__(self):
return
There are properties of F which have been defined in class A, which I need to access inside class B. (a MySQL connection and a logging handler.)
I would like B to have the properties which have been set to F, when they were instantiated initially in A, so I can use the logging/mysql handlers inside B without re-instantiating them.
How can I go about this? Sorry if the question is unclear.
Put the stuff you want to share in F and both A and B will be able to share it. Eg
class F(object):
def useful(self):
pass
class A(F):
def something(self):
self.useful()
class B(F):
def something_else(self):
self.useful()

Question about python and classes

I have a base class and a few derived in Python:
class Base:
def Foo(self):
pass
# First derived class
class Der1(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
# Second derived class
class Der2(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
The question is:
I have some predefined code in Der1. Almost all functions from Der2 do the same. How can I write this with less code?
I can't add that code to the parent. Parent class shouldn't be touched.
For example, Der2.OwnFoo does the same as Der1.OwnFoo, maybe there is some construction in python just to call OwnFoo from first class and not to write that code again?
I can't change the parent of Der1 and Der2! It should be Base.
Since you can't change the inheritance structure, make a helper class that contains the common code and include it by composition rather than inheritance.
# Common code goes in this new class
class DerHelper:
def __init__(self, parent):
self._parent = parent
def OwnFoo(self):
print 'Do something 1', self._parent
def OwnFoo2(self):
print 'Do something 2', self._parent
def Foo(self):
print 'Do something 3', self._parent
# First derived class
class Der1(Base):
def __init__(self):
# include helper class by composition
self._helper = DerHelper('Der1')
def OwnFoo(self):
self._helper.OwnFoo()
def OwnFoo2(self):
self._helper.OwnFoo2()
def Foo(self):
self._helper.Foo()
# Second derived class
class Der2(Base):
def __init__(self):
# include helper class by composition
self._helper = DerHelper('Der2')
def OwnFoo(self):
self._helper.OwnFoo()
def OwnFoo2(self):
self._helper.OwnFoo2()
def Foo(self):
self._helper.Foo()
Of course, you could pass a reference to the parent instead of a string. I just did it this way for demonstration purposes.
Usage:
d = Der1()
d.OwnFoo()
d.OwnFoo2()
d.Foo()
d = Der2()
d.OwnFoo()
d.OwnFoo2()
d.Foo()
Output:
Do something 1 Der1
Do something 2 Der1
Do something 3 Der1
Do something 1 Der2
Do something 2 Der2
Do something 3 Der2
Make Der2 a subclass of Der1 and you're done.
class Base:
def Foo(self):
pass
# First derived class
class Der1(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
# Second derived class (subclasses Der1)
class Der2(Der1):
pass
Any behavior within Der2 you'd like to specialize can added within the class definition. If you create a new method of the same name in Der2 (e.g. Der2.OwnFoo()), then it will overload the default method that is inherited from Der1.
EDIT: If you can't change the parent, put all of the behavior you want to inherit in the base class keeping in mind that you can overload or customize any of the methods in the subclasses.
In code:
# Base class
class Base:
def Foo1(self):
# Do something 1
def Foo2(self):
# Do something 2
def Foo(self):
# Do something 3
# First derived class, inherits everything from Base
class Der1(Base):
pass
# Second derived class
class Der2(Base):
pass
There is a "trick" you can do to call the original method inherited from the parent, capture the return value and then customize the behavior. This will only work if the method actually returns a value, and can be dangerous if the method manipulates attributes within the class, unless that's what you want and expect it.
In code:
# Second derived class, with customized methods
class Der2(Base):
# Anything that is not explicitly define is inherited from parent
# as-is.
def Foo(self):
# My Foo() overloads Base.Foo() inherited from parent class.
# Do something "special" 3
def Foo1(self):
# Calls parent Base.Foo1() and then manipulates return data.
base_output = Base.Foo1(self)
# Do something "special" 1 with 'base_output'
Is this a homework?
Look at the first line of Der2:
class Der2(Base):
What says what is its parent (e.g. a class it descends and herits methods and attributes from)? How could you change this?
If Der1 and Der2 share a lot of code, then you should put that in a superclass; since Base cannot be touched, introduce a class in between:
class Der(Base):
def OwnFoo(self):
...
class Der1(Der):
...
class Der2(Der):
...
(Depending on you class hierachy, the "derive Der2 from Der1" option that others recommend may also be valid.)
How about making Der2 subclass Der1?

Categories