I've been googling to no avail, maybe I'm just not searching for the right thing... What I have is many subclasses from a base. This base would have a method that gets an instance of a class from an imported module. What I want is for the method in the base class to grab the instance of from the module imported in the subclass.
I have a structure like this:
root
|--Base
|----foo.py
|----bar.py
|--Child1
|----foo.py
|----bar.py
|--Child2
|----foo.py
|----bar.py
Where basically there are a few children that all inherit from Base. What I'm wondering is if it's possible to have a method inherited from Base that uses the subclass's import as such for base classes:
# file Base/foo
from root.Base import bar
class Foo(object):
def get_bar_instance(self):
return bar.Bar(param)
And:
# file Base/bar
class Bar(object):
def do_some_stuff(self):
print("Base")
And then in subclasses:
# file Child1/foo
from root.Base import foo
from root.Child1 import bar
class Foo(foo.Foo):
""" Some stuff for subclass only"""
And:
# file Child1/bar
from root.Base import bar
class Bar(bar.Bar):
def do_some_stuff(self):
print("Child1")
If I were to do:
from root.Child1 import foo
temp_foo = foo.Foo()
temp_bar = temp_foo.get_bar_instance()
temp_bar.do_some_stuff()
I would want "Child1" to be printed. Is this possible? Or is there no way to "override" a parent's imports in a submodule. It's kind of hard to explain because it isn't just a print method... I was hoping to have the method in the parent class rather than have the method in every single child
Related
I have an interesting problem. I would like to write a class, which when inherited provides to all children classes the following behavior:
sets its self.id attribute to a UUID value
-- if this is the first time class got instantiated, a new UUID is generated
-- the UUID value is reused for the same class, when it is instantiated many times
Now, the fun part: I want the mechanism above to work, regardless of the path used to instantiate this class. Let's assume the following:
from .Package.Class1 import Class1
from TopPackage.Package.Class1 import Class1
from .Package.Class2 import Class2
from TopPackage.Package.Class2 import Class2
In both situations, I would like Class1 to generate the same self.id value in both import styles. I would also like Class2 to generate a different self.id value from Class1, but the same between its own import styles.
So far, I wrote the following code for a class classes 1 and 2 would inherit from:
class ClassWithId(ABC):
_EXISTING_OBJECT_IDS = dict()
def __init__(self):
if self in ClassWithId._EXISTING_OBJECT_IDS.keys():
self.id = ClassWithId._EXISTING_OBJECT_IDS[self]
else:
self.id = uuid.uuid4()
ClassWithId[self] = self.id
However, I have a few problems in here:
ClassWithId must inherit from class ABC because it is also an interface for classes 1 and 2
trying to put self as key in dict() results in TypeError: 'ABCMeta' object does not support item assignment
I am generally unsure, if this approach is going to be resistant to different import styles, because from Python's perspective class type .Package.Class1.Class1 and TopPackage.Package.Class1.Class1 are 2 different objects
Any ideas?
UPDATE:
I have integrated Elrond's suggestion into my code, and but different import levels (package-wise) yield different UUID values for the same class:
<class 'StageTwo.Steps.SsTestHandler1.SsTestHandler1'> 3583c89c-5ba8-4b28-a909-31cc27628370
<class 'tests.TestStages.StageTwo.Steps.SsTestHandler1.SsTestHandler1'> f4ead4a0-f5f7-4d95-8252-0de47104cb2f
<class 'StageTwo.Steps.SsTestHandler2.SsTestHandler2'> 8bd9a774-0110-4eee-a30c-a4263ad546cf
<class 'tests.TestStages.StageTwo.Steps.SsTestHandler2.SsTestHandler2'> 773d84c4-82a3-4684-92b5-51509e6db545
Maybe I forgot to mention, but my ClassWithId is inherited by ClassX and ClassY down the line, and it is these 2 classes, which are expected to be resistant to the situation I have shown above (being imported with different path, yet still retaining the same UUID).
You will need to use a metaclass for this:
import uuid
import abc
class BaseMeta(abc.ABCMeta):
def __new__(mcs, name, bases, attrs):
attrs['_class_uuid'] = uuid.uuid4()
return super().__new__(mcs, name, bases, attrs)
class Base(metaclass=BaseMeta):
def __init__(self):
print(self.__class__.__name__, self._class_uuid)
Now all classes that inherit from Base will be assigned a uuid via the _class_uuid property, once per subclass:
from package1.class1 import Class1
from package2.class2 import Class2
Class1() # 6e0852c8-61c9-4f8b-9817-eeeda4b49d56
Class1() # 6e0852c8-61c9-4f8b-9817-eeeda4b49d56
Class2() # 73012f1a-a984-4f76-96f1-ef5225a38fbe
Class2() # 73012f1a-a984-4f76-96f1-ef5225a38fbe
Using absolute/relative imports shouldn't make a difference in either case.
from Python's perspective class type .Package.Class1.Class1 and TopPackage.Package.Class1.Class1 are 2 different objects
If I understand what you're saying here, I don't think this statement is true. Hopefully, my example below will clarify.
There might be other approaches, such as using the class name as your dictionary key, but perhaps a more extendable approach is with a metaclass.
I placed everything in one file, for the sake of simplicity, but the approach remains the same for a module with multiple levels:
TopPackage.py:
import uuid
class ABC:
pass
def id_assigner(class_name, class_parents, class_attrs):
class_attrs['id'] = str(uuid.uuid4())
return type(class_name, class_parents, class_attrs)
class Class1(ABC, metaclass=id_assigner):
pass
class Class2(ABC, metaclass=id_assigner):
pass
def foo():
c2 = Class2()
print('c2.id from foo: ', c2.id)
And a script to test it:
import TopPackage
c1_a = TopPackage.Class1()
c1_b = TopPackage.Class1()
print(c1_a.id)
print(c1_b.id)
c2_a = TopPackage.Class2()
c2_b = TopPackage.Class2()
print(c2_a.id)
print(c2_b.id)
TopPackage.foo()
The call to TopPackage.foo(), I hope, shows that using Class2 from different location will result in the same class definition, and hence the same id. When I run this test script an example output I get is:
c69b17e0-9ff0-4276-bcce-6ac4f5e5a2e5
c69b17e0-9ff0-4276-bcce-6ac4f5e5a2e5
86fbe02e-d411-4ba1-b292-d2b1ec2100bd
86fbe02e-d411-4ba1-b292-d2b1ec2100bd
c2.id from foo: 86fbe02e-d411-4ba1-b292-d2b1ec2100bd
I am programming a bokeh application. I want to split the functionalities into different files. But I want to have some attributes accesible from every class, these attributes should be shared and always updated. For example an attribute which stores a dataframe that all the plots are going to use. So I think I have at least two possible solutions:
Use a big class and include the attributes and methods of other files:
class Bigclass(object):
from bk_plots import p1, p2, p3
from bk_data import d1, d2, d3
from bk_layout import ly1, ly2
from bk_events import ev1, ev2
# unfortunately, "from classdefn import *" is an error or warning
num = 42 # add more members here if you like
Note: this solution was copied from here (partial classes)
Or I could use inheritance. The parent will have the shared attributes. The perk of this system is that I would need to send the rest of the object references to every subclass
class Parent():
shared = 'parent'
class Plot(Parent):
def __init__(self):
Parent.shared = 'plots' # update class variable from this class
# I would need to have references to the objects of other classes
class Data(Parent):
def __init__(self):
Parent.shared = 'second'
# [...]
Is there a better way to do this? Which option will bring me less problems?
Finally I have created an my_bokeh_app folder. There I have an __init__.py file with this content for the initialization:
from my_bokeh_app.bokeh_data import BokehData
from my_bokeh_app.bokeh_plots import BokehPlots
from my_bokeh_app.bokeh_table import BokehDataTable
from my_bokeh_app.bokeh_events import BokehEvents
from my_bokeh_app.bokeh_layout import BokehLayout
BokehData()
BokehPlots()
BokehDataTable()
BokehEvents()
BokehLayout()
I have created a Class to share data among all the objects. This is the class:
class BokehSharedData(object):
# ------------------- CLASS VARIABLES ---------------------- #
# This variables are shared. So all the children can access them
data_source = None
bk_layout = None
bk_data = None
bk_plot = None
bk_table = None
bk_events = None
In every class I make a reference to the BokehSharedData class. I also inherit from that class to access to the class variables.
from my_bokeh_app.bokeh_shared_data import BokehSharedData
class BokehData(BokehSharedData):
def __init__(self, **kwargs):
self.env = BokehSharedData
self.env.bk_data = self
# If for example I want to access to the source attribute from the rest of objects
# I could make this shortcut on the shared class
self.env.data_source = ColumnDataSource(...)
def update_data_source(self):
# [...]
And I could read the shared attributes or execute methods from other object:
from my_bokeh_app.bokeh_shared_data import BokehSharedData
class BokehPlots(BokehSharedData):
def __init__(self, **kwargs):
self.env = BokehSharedData
self.env.bk_plots = self
# I could use self.env.data_source here or run some method of BokehData class like this
self.env.bk_data.update_data_source()
The complete app where you can see all the classes working is here
I'm trying to subclass a class from another python script.
I've done the following when subclassing from within the same file, and it works.
widge.py
class widget(object):
def __init__(self,bob):
#do something
class evenWidgetier(widget):
def __init__(self, bob):
widget.__init__(self,bob)
#do something
But once I add in inheritance from another file..
superWidget.py
import widge
class superWidgety(widge.evenWidgetier):
def __init__(self, bob):
widge.widget.__init__(self,bob)
#do something
I get an error:
unbound method __init__() must be called with widget instance as first argument
Is there a way I can subclass a class from another package that works?
.
And out of curiosity, what's the deal?
Substantively this looks identical to me. I can call a class from another file by using the widge.widget(), so that method seems established. And I can subclass when the class is in the same file by referencing the class in the declaration. What is it about using a class from an import in a declaration that breaks? Why does it see itself as the right method when in the same file, but sees itself as an unbound method when imported?
The specifically, my code is this (stripping the parts that shouldn't affect this.
Attributor.py
class Tracker(object):
def __init__(self, nodeName=None, dag=None):
#Tracking stuff
class Transform(Tracker):
#Does stuff with inherited class
timeline_tab.py
import Attributor as attr
class timeline(attr.Transform):
#some vars
def __init__(self, nodeName=None):
attr.Transform.__init__(self,nodeName=nodeName)
#Additional init stuff, but doesn't happen because error on previous line
In superWidget.py change the SuperWidget to use super
import widge
class superWidgety(widge.evenWidgetier):
def __init__(self, bob):
super(SuperWidget,self).__init__(bob)
#do something
Suppose I need to implement an abstract Python interface which then will have many derived classes (each named equally but written in different modules), and in base class I heed to have a common method which will use a particular imported derived class' static method.
So my toy modules look like this:
abstract_class.py
from abc import ABCMeta, abstractmethod
from derived_class import Derived
class Abstract:
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
def bar(self):
Derived.foo()
derived_class.py
from abstract_class import Abstract
class Derived(Abstract):
#staticmethod
def foo():
print 'Good news everyone!'
if __name__ == '__main__':
derived_object = Derived()
derived_object.bar()
Then of course when I'm trying to run derived_class.py, I get the Abstract name import error.
How do I properly organize this?
On the other hand, if you absolutely needed to do this without an object instance, it's possible to do with classmethods rather than staticmethods.
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
#staticmethod
#abstractmethod
def foo(label: str):
raise NotImplementedError()
#classmethod
def foo_agnostic(cls, label: str):
"""
NOTE: Here, this method doesn't have a reference to an instance of the class.
Instead, it only has a reference to the class itself; but that is enough
to call the abstract static foo() method.
"""
cls.foo(label)
class MyDerivedClass(MyAbstractClass):
#staticmethod
def foo(label: str):
print(label)
if __name__ == "__main__":
instance = MyDerivedClass()
instance.foo("Test 1") # Outputs "Test 1"
instance.foo_agnostic("Test 2") # Outputs "Test 2"
MyDerivedClass.foo_agnostic("Test 3") # Outputs "Test 3"
... in base class I heed to have a common method which will use a
particular imported derived class' static method
If I understand your question correctly, I'd say that this functionality is available out of the box with one small exception: Don't use a static method; just use a regular instance method.
Defining an abstract method in the base class will ensure that derived classes contain an implementation for that method. And, out of the box, the method defined in the derived class will get called when you call derived_object.bar().
I want to use imports inside a class that is then inherited by another class so that I don't have to manually define my imports in each file. I am trying it like this but its not working, any advice is appreciated:
class Djangoimports ():
def __init__(self):
from django.template import Context
print Context
class Init1 (Djangoimports):
def __init__(self):
Djangoimports.__init__(self)
self.c = Context(self.constructor_dict) # just example of trying to use the imported "Context"
>>>>> global name 'Context' is not defined
I have tried variations of trying to use "self" but can't figure out how to appropriately use this with the import from as its not the same as a class attribute / method where I normally use 'self'
This works fine for me.
But you're better off doing this:
>>> class Test(object):
... from functools import partial
...
>>> Test().partial
<type 'functools.partial'>
Note that doing it your way, you have to initialize them on a per instance basis and assign to self, like so:
def Test(object):
def __init__(self):
from functools import partial
self.partial = partial
either way, you can now access bar in other methods on that class or a derived one as self.bar.
In Python, an import just adds to current namespace. The namespace is lost once you return from the function, but you can preserve the pointer appending it to 'self'.
You can do:
class Djangoimports ():
def __init__(self):
from django.template import Context
self.Context = Context
class Init1 (Djangoimports):
def __init__(self):
Djangoimports.__init__(self)
self.c = self.Context(self.constructor_dict)