I have a few dozen classes. Here are two of them:
class Class_A(ClassABC):
def __init__(self):
super().__init__()
def from_B(self, b):
#do stuff
def from_C(self, c):
#do stuff
#...
def to_B(self):
rt = Class_B()
rt.from_A(self)
return rt
def to_C(self):
rt = Class_C()
rt.from_A(self)
return rt
#...
class Class_B(ClassABC):
def __init__(self):
super().__init__()
def from_A(self, a):
#do stuff
def from_C(self, c):
#do stuff
def to_A(self):
rt = Class_A()
rt.from_B(self)
return rt
def to_C(self):
rt = Class_C()
rt.from_B(self)
return rt
#...
#class Class_C, Class_D, Class_E, etc,
and here is the ABC:
class ClassABC(metaclass=abc.ABCMeta):
#abc.abstractmethod
def __init__(self):
#do stuff
The problem I have is that all the to_* methods in the subclasses follow the same exact pattern, and it becomes tedious to implement them. I would like to automatically generate them in the ClassABC if possible, but so far I have failed. I also tried creating a class decorater for the subclasses, but that didn't work either. I have, however, managed to auto generate the methods in each subclass using exec(), but I rather have the ABC generate them or use class decoraters. Is there a way to do this?
Note: all the classes are in their own separate module
First of all, your to_* methods aren't going to work because you need to explicitly include self at the beginning of the argument list to be able to use it in the method body. Secondly, I'd go with something akin to JBernardo's suggestion.
def to_class(self, cls):
rt = cls()
rt.from_class(self.__class__)
return rt
def from_class(self, cls):
#do stuff, with different things happening based on what class cls is; this may be a good place to use a dict of functions with the class or classname as keys
Related
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.
I have the following code:
import time
class output_letter():
def output_a(self):
print('a')
def output_b(self):
print('b')
def output_c(self):
print('c')
.............
def output_z(self):
print('z')
class wait_time():
def sleep_2(self):
time.sleep(2)
out = output_letter()
out.output_a()
I would like to tack the functionality of class wait_time.sleep_2 onto the beginning of class output_letter . As an example if I were to create a hypothetical class "combined" , I could do
c=combined()
c.output_a # would wait 2 seconds and then print 'a'
The problem is that I don't want to rewrite all the functions of 'output_letter', I just want to add the same functionality to all of its functions.
Its not clear to me how to do this , or if this is possible with inheritance or composition.
I see how you may want to solve 2 separate tasks based on DRY and SOLID principles:
It should be really easy to apply wait_time in future in many other places
Would be cool to keep output_letter as clean and untouchable as possible
So here's my idea:
1. Create a module that will allow you to apply a decorator for all the methods:
def for_all_methods(decorator):
def decorate(cls):
for attr in cls.__dict__:
if callable(getattr(cls, attr)):
setattr(cls, attr, decorator(getattr(cls, attr)))
return cls
return decorate
2. Isolate wait_time in a module as well:
from time import sleep
class wait_time():
#staticmethod
def sleep_decorator(function):
def wrapper(*args, **kwargs):
#sleep(2)
print("sleeping")
return function(*args, **kwargs)
return wrapper
3. This is how you can use it
#for_all_methods(wait_time.sleep_decorator)
class output_letter():
def output_a(self):
print('a')
def output_b(self):
print('b')
def output_c(self):
print('c')
def output_z(self):
print('z')
So the benefit, we are not actually touching constructors or changing inheritance. All we did, just added a decorator above a class, what is easy to enable or disable when necessary.
If you want to go even further and prevent dealing with an original class directly, you can just create a child combined inherited from the original class and add that decorator signature above its definition.
You can try this DEMO
The code below accomplishes what you want. You can set class variables in the combined class to represent output_letter and wait_time. Then inside of the combined class you have access to all attributes and functions of the other classes.
import time
class output_letter():
def output_a(self):
print('a')
def output_b(self):
print('b')
def output_c(self):
print('c')
class wait_time():
def sleep_2(self):
time.sleep(2)
class combined():
ol = output_letter()
wt = wait_time()
def output_a(self):
self.wt.sleep_2()
self.ol.output_a()
def main():
c=combined()
c.output_a()
if __name__ == '__main__':
main()
You can either create a class instance of wait_time as an attribute in output_letter or call time.sleep in the method itself:
Option 1:
import time
class wait_time():
def sleep_2(self):
time.sleep(2)
class output_letter():
def __init__(self):
self.wait = wait_time()
def output_a(self):
self.wait.sleep_2()
print('a')
def output_b(self):
self.wait.sleep_2()
print('b')
def output_c(self):
self.wait.sleep_2()
print('c')
Option 2:
class output_letter():
def output_a(self):
time.sleep(2)
print('a')
def output_b(self):
time.sleep(2)
print('b')
def output_c(self):
time.sleep(2)
print('c')
Edit: regarding your recent comment and edits, you may want to merely create two instances and call each:
a = outout_letter()
t = wait_time()
t.sleep_2()
a.output_a()
Also, it seems that you are trying to output each letter of the output given a method call with the target letter at the end. To shorten your code and implement wait_time as well, you can use __getattr__:
class Output_Letter:
def __init__(self):
self.t = wait_time()
def __getattr__(self, name):
def wrapper():
self.t.sleep_2()
print name.split('_')[-1]
return wrapper
a = Output_Letter()
a.output_c()
Output:
c
You can subclass multiple classes. In Python 3:
Given
import time
class Letter():
"Print a letter."""
def output_a(self):
print('a')
def output_b(self):
print('b')
def output_c(self):
print('c')
class WaitTime():
"""Set a delay."""
def sleep_2(self):
time.sleep(2)
Code
class Combined(Letter, WaitTime):
"""Combine methods."""
def output_a(self):
super().sleep_2()
super().output_a()
combined = Combined()
combined.output_a()
# 'a' # delayed output
This allows you to keep your original classes. You simply call them in the new Combined class.
Details
The Combined class mixes other classes together. The super() function makes a call to these superior classes to access their methods according to the class method resolution order:
Combined.__mro__
# (__main__.Combined, __main__.Letter, __main__.WaitTime, object)
In order to work in Python 2, some adjustments are required:
class Letter(object):
...
class WaitTime(object):
...
class Combined(Letter, WaitTime):
def output_a(self):
super(Combined, self).sleep_2()
super(Combined, self).output_a()
Minor note: for readability, use CamelCase names for classes. Class names are typically nouns; functions are usually verbs.
None of the classes you've shown in your example are very good OOP design. There's no need for a class when your methods don't refer to any state. if you just want a namespace, usually a module is better.
But that doesn't matter too much if your question is really about how to combine the effects of multiple functions. There are many ways to do that. Functions are first-class objects in Python, so you can put them in lists or dictionaries, or pass them as arguments to other functions if you want. You can also make "function factories", functions that return new functions.
Here's how you might be able to use that to build the delayed letter writing functions you want. I'm storing the function results in a couple of dictionaries, but you could do something different with them if you need to.
import itertools
import time
def letter_writer_factory(letter):
"""Return a function that prints the provided letter when it is called"""
def func():
print(letter)
return func
def delay_factory(seconds):
"""Return a function that when called, waits for the specified time"""
def delay():
time.sleep(seconds)
return delay
def function_sequencer_factory(*functions):
"""Return a function that calls each function argument in turn"""
def caller():
for func in functions:
func()
return caller
letters = 'abc'
delay_times = [2, 5, 10]
output_funcs = {c: letter_writer_factory(c) for c in letters}
delay_funcs = {t: delay_factory(t) for t in delay_times}
delayed_output_funcs = {(c, t): function_sequencer_factory(df, of)
for (c, of), (t, df) in itertools.product(output_funcs.items(),
delay_funcs.items())}
#print c after waiting for 10 seconds:
delayed_output_funcs['c', 10]()
This is of course a pretty silly example, but these kinds of functional programming techniques can be used to do some actually useful things in some contexts.
How do you access an instance in an object and pass it to another 'main' object? I'm working with a parser for a file that parses different tags, INDI(individual), BIRT(event), FAMS(spouse), FAMC(children)
Basically there are three classes: Person, Event, Family
class Person():
def __init__(self, ref):
self._id = ref
self._birth : None
def addBirth(self, event):
self._birth: event
class Event():
def __init__(self, ref):
self._id = ref
self._event = None
def addEvent(self, event):
self._event = event
#**event = ['12 Jul 1997', 'Seattle, WA'] (this is generated from a function outside a class)
I want to transfer self._event from the Event class into addBirth method to add it into my person class. I have little knowledge on how classes and class inhertiances work. Please help!
If I understand your question, you want to pass an (for example) Event object to an instance of Person?
Honestly, I don't understand the intent of your code, but you probably just need to pass self from one class instance to the other class instance.
self references the current instance.
class Person:
def __init__(self):
self._events = []
def add_event(self, event)
self._events.append(event)
class Event:
def add_to_person(self, person):
person.add_event(self)
The most proper way to handle situations like this is to use getter and setter methods; data encapsulation is important in OO programming. I don't always see this done in Python where I think it should, as compared to other languages. It simply means to add methods to your classes who sole purpose are to return args to a caller, or modify args from a caller. For example
Say you have class A and B, and class B (caller) wants to use a variable x from class A. Then class A should provide a getter interface to handle such situations. Setting you work the same:
class class_A():
def __init__(self, init_args):
x = 0
def someMethod():
doStuff()
def getX():
return x
def setX(val):
x = val
class class_B():
def init(self):
init_args = stuff
A = class_A(init_args)
x = class_A.getX()
def someOtherMethod():
doStuff()
So if class B wanted the x property of an instance object A of class class_A, B just needs to call the getter method.
As far as passing instances of objects themselves, say if you wanted A to pass an already-created instance object of itself to a method in class B, then indeed, you simply would pass self.
I have class with hundreds of methods
I want create a hierarchy of them that will let easy find method.
For example
class MyClass:
def SpectrumFrequencyStart()...
def SpectrumFrequencyStop()...
def SpectrumFrequencyCenter()...
def SignalAmplitudedBm()...
That I want to call using:
MyClassObject.Spectrum.Frequency.Start()
MyClassObject.Spectrum.Frequency.Stop()
MyClassObject.Signal.Amplitude.dBm()
Consider using a dictionary to map your methods to keys (either hierarchical dictionaries, or simply '.' separated keys).
Another option which may be more elegant is namedtuples. Something like:
from collections import namedtuple
MyClassObject = namedtuple('MyClassObject', ['Spectrum', 'Signal'])
MyClassObject.Spectrum = namedtuple('Spectrum', ['Frequency'])
MyClassObject.Spectrum.Frequency = namedtuple('Frequency', ['Start', 'Stop'])
MyClassObject.Spectrum.Frequency.Start = MyClass.SpectrumFrequencyStart
You can automate this by using inspection and parse the method names by, say camel case, to build the namedtuples automatically.
Pay attention to binding of the methods
This is just a very bad design.
It's clear that Spectrum, Signal, Frequency (and so on) should be all separate classes with much less than "hundreds of methods".
I'm not sure if MyClassObject actually represents something or is effectively just a namespace.
Objects can encapsulate objects of other classes. For example:
class Frequency(object):
def start(self):
pass
def stop(self):
pass
class Spectrum(object):
def __init__(self):
self.frequency = Frequency()
class Amplitude(object):
def dbm(self):
pass
class Signal(object):
def __init__(self):
self.amplitude = Amplitude()
class MyClass(object):
def __init__(self):
self.spectrum = Spectrum()
self.signal = Signal()
my_class_instance = MyClass()
my_class_instance.spectrum.frequency.start()
my_class_instance.spectrum.frequency.stop()
my_class_instance.spectrum.signal.amplitude.dbm()
There's a convention of code formatting in Python PEP 8 therefore I applied it in my example.
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.