I am attempting to build a framework for parsing a very specific text structure.
The structure that I am processing is rich and has a known schema, similar to xml.
I am attempting to build an framework to do the parsing. The text has various sections and I anticipate that more sections code be added in the future. To Compensate, I am attempting to build a series of derived classed that can be swapped in or out as needed.
I thought everything was going as planned, until I started coding up the first derived class.
The base class has some functionality inside of __init__ that I was expecting that I would get for free in all of the concrete derived classes. That however, doesn't seem to be the case at all.
Here is a simple example to illustrate my problem:
I would expect the output to be:
['memberA', 'memberB', 'memberC'],
['DerivedA', 'DerivedB', 'DerivedC']
class base(object):
def __init__(self):
members = [attr for attr in dir(self) if not callable(attr) and not attr.startswith("__")]
print members
class test(base):
def __init__(self):
self.memberA = None
self.memberB = None
self.memberC = None
class test2(test):
def __init__(self):
self.DerivedA = None
self.DerivedB = None
self.DerivedC = None
t = test()
t2 = test2()
Can someone please explain to my, why the print functionality is not working as I expect it?
EDIT:
in light of the answer below: I now have this question:
What if base.__init(self) instead looked like:
class base(object):
def __init__(self, text):
would I have to define the derived class as:
class test(base):
def __init__(self, text):
base.__init__(self, text)
I was hoping to at least get the parameter object referance for free
In Python, you must call the base class's __init__ explicitly inside test.__init__:
class test(base):
def __init__(self):
base.__init__(self)
Or, if you wish to support multiple inheritance, use super:
class test(base):
def __init__(self):
super(test, self).__init__()
If the base.__init__ looks like
class base(object):
def __init__(self, text):
then test.__init__ should indeed look like
class test(base):
def __init__(self, text):
base.__init__(self, text)
See Guido van Rossum's blog for why self is explicit in Python.
PS. PEP8 recommends using CapWords for class names.
you are overwriting init in test2
following code will complete overwrite init in test. so there is no longer a print int the init function.
def __init__(self):
self.DerivedA = None
self.DerivedB = None
self.DerivedC = None
Related
This is my current setup:
class Base():
def __init__(self):
pass
# ...other methods
class A(Base):
def __init__(self, dst, fname, alg, src=None):
super().__init__()
# I then use these instance variables throughout instance methods.
self.src = [] if src is None else src
self.dst = dst
self.fname = fname
self.alg = alg
# ...other methods
class B(Base):
def __init__(self, fname):
super().__init__()
# I then use these instance variables throughout instance methods.
self.fname = fname
# ...other methods
class C(A, B):
"""Here is my problem.
When I try to inherit A and B this way,
I keep getting those "missing required positional args..." errors
"""
def __init__(self, dst, src=None):
super().__init__()
# I then use these instance variables throughout instance methods.
self.fname = fname
# ...other methods
Here is what I am trying to do right now:
class Base():
def __init__(self, *args, **kwargs):
pass
class A(Base):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class B(Base):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class C(A, B):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
My main question:
What is the "best" (standard, most preferred, efficient, readable etc.) way to handle such situations?
P.S.
I read the following article, Python’s super() considered super!, but I could not derive the best answer for myself after reading it.
Also, I referenced this SO question but the accepted answer does not have different number of params like I do...
By the way, I am willing to hear that my design (class hierarchy) is bad overall. Technically, I could relocate methods that I am trying to inherit from A and B in C to the Base class...I hope (did not try yet)...
Based on your implementation, to remove the error, I think it would be best to explicitly use the base class' required parameters based on the method resolution order (in your case, the base class for the class C should be class A).
class C(A, B):
def __init__(self, dst, src=None):
fname = 'some value'
super().__init__(dst, fname, alg)
This will be the simplest solution that can be done. But if you are willing to make design changes, I would recommend using composition instead of inheritance for python. I assume that you have methods in class A and class B that is needed by class C. With composition, needed functions/operations can just be added to the classes that needs it. It would also prevent code smells like refused bequest
Python has an advantage that supports multiple inheritance, even the box office technology java doesn't supports this feature because it leads to overriding of methods when both extended class have a same method name.
But python overcomes this problem and supporting multiple inheritance. To use multiple inheritance in python, should know the arguments to define in proper way.
class C(A, B):
def __init__(self, dst, src=None):
super().__init__()
self.fname = fname
In the above obove code, Class C inherits Classes A and B. Here first of all super().__init__() navigate to Class A, search for .__init__(), if init() or some other method abc() not in Class A, then next it will look up into Class B,
These navigation go through based on sequential order that you inherits into Class C
Here Solution for you problem is, you defined super class __init__() with parameters in both Class A & B, and calling super class super().__init__() with out parameters in Class C.
I'm trying to write a tracker class where the instances of the tracker class track the sub-classes of another class that are in the scope of the tracker instance.
More concretely, the following is an example of what I am trying to achieve:
class Foo(object): pass
class FooTracker(object):
def __init__(self):
# use Foo.__subclasses__() or a metaclass to track subclasses
# - but how do I filter this to only get the ones in scope?
self.inscope = <something magic goes here>
ft1 = FooTracker()
assert ft1.inscope == []
class Bar(Foo): pass
ft2 = FooTracker()
assert ft2.inscope == [<class '__main__.Bar'>]
def afunction():
class Baz(Foo): pass # the global definition of Bar is now hidden
class Bar(Foo): pass
ft3 = FooTracker()
assert (set(ft3.inscope) == set([<class '__main__.afunction.<locals>.Baz'>,
<class '__main__.afunction.<locals>.Bar'>])
ft4 = FooTracker() # afunction.Baz and afunction.Bar are no longer in scope
assert ft4.inscope == [<class '__main__.Bar'>]
So I want the instances of FooTracker to track the sub-classes of Foo that were in scope at the time the FooTracker object was created.
I've tried a few different things, such as parsing the qualified names of the Foo sub-classes and using exec() to do the name resolution but the fundamental problem is that it always works out the sub-classes relative to the scope within FooTracker.__init__() and not where it was called.
My only other thought was to try something with inspect.currentframe() but even if this were possible it would probably be too much of a hack and would make the code too brittle (e.g., there is a comment in the docs that not all Python implementations will have frame support in the interpreter").
There's no easy way to do exactly what you're asking for. But you might be able to use some Python features to get something with a roughly similar API, without as much hassle.
One option would be to require each subclass to be decorated with a method of your Tracker class. This would make it really easy to keep track of them, since you'd just append each caller of the method to a list:
class Tracker:
def __init__(self):
self.subclasses = []
def register(self, cls):
self.subclasses.append(cls)
return cls
class Foo(): pass
foo_tracker = Tracker()
#foo_tracker.register
class FooSubclass1(Foo): pass
#foo_tracker.register
class FooSubclass2(Foo): pass
print(foo_tracker.subclasses)
This doesn't actually require that the classes being tracked are subclasses of Foo, all classes (and even non-class objects) can be tracked if you pass them to the register method. Decorator syntax makes it a little nicer than just appending each class to a list after you define it, but not by a whole lot (you still repeat yourself a fair amount, which may be annoying unless you make the tracker and method names very short).
A slightly trickier version might get passed the base class, so that it would detect subclasses automatically (via Foo.__subclasses__). To limit the subclasses it detects (rather than getting all subclasses of the base that have ever existed), you could make it behave as a context manager, and only track new subclasses defined within a with block:
class Tracker:
def __init__(self, base):
self.base = base
self._exclude = set()
self.subclasses = set()
def __enter__(self):
self._exclude = set(self.base.__subclasses__())
return self
def __exit__(self, *args):
self.subclasses = set(self.base.__subclasses__()) - self._exclude
return False
class Foo(): pass
class UntrackedSubclass1(Foo): pass
with Tracker(Foo) as foo_tracker:
class TrackedSubclass1(Foo): pass
class TrackedSubclass2(Foo): pass
class UntrackedSubclass2(Foo): pass
print(foo_tracker.subclasses)
If you're using Python 3.6 or later, you can do the tracking a different way by injecting an __init_subclass__ class method into the tracked base class, rather than relying upon __subclasses__. If you don't need to support class hierarchies that are already using __init_subclass__ for their own purposes (and you don't need to support nested trackers), it can be quite elegant:
class Tracker:
def __init__(self, base):
self.base = base
self.subclasses = []
def __enter__(self):
#classmethod
def __init_subclass__(cls, **kwargs):
self.subclasses.append(cls)
self.base.__init_subclass__ = __init_subclass__
return self
def __exit__(self, *args):
del self.base.__init_subclass__
return False
class Foo(): pass
class UntrackedSubclass1(Foo): pass
with Tracker(Foo) as foo_tracker:
class TrackedSubclass1(Foo): pass
class TrackedSubclass2(Foo): pass
class UntrackedSubclass2(Foo): pass
print(foo_tracker.subclasses)
One nice feature of this version is that it automatically tracks deeper inheritance hierarchies. If a subclass of a subclass is created within the with block, that "grandchild" class will still be tracked. We could make the previous __subclasses__ based version work this way too, if you wanted, by adding another function to recursively expand out the subclasses of each class we find.
If you do want to play nice with existing __init_subclass__ methods, or want to be able to nest trackers, you need to make the code a bit more complicated. Injecting a well behaved classmethod in a reversible way is tricky since you need handle both the case where the base class has its own method, and the case where it's inheriting a version from its parents.
class Tracker:
def __init__(self, base):
self.base = base
self.subclasses = []
def __enter__(self):
if '__init_subclass__' in self.base.__dict__:
self.old_init_subclass = self.base.__dict__['__init_subclass__']
else:
self.old_init_subclass = None
#classmethod
def __init_subclass__(cls, **kwargs):
if self.old_init_subclass is not None:
self.old_init_subclass.__get__(None, cls)(**kwargs)
else:
super(self.base, cls).__init_subclass__(**kwargs)
self.subclasses.append(cls)
self.base.__init_subclass__ = __init_subclass__
return self
def __exit__(self, *args):
if self.old_init_subclass is not None:
self.base.__init_subclass__ = self.old_init_subclass
else:
del self.base.__init_subclass__
return False
class Foo:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
print("Foo!")
class Bar(Foo): pass # every class definition from here on prints "Foo!" when it runs
with Tracker(Bar) as tracker1:
class Baz(Bar): pass
with Tracker(Foo) as tracker2:
class Quux(Foo): pass
with Tracker(Bar) as tracker3:
class Plop(Bar): pass
# four Foo! lines will have be printed by now by Foo.__init_subclass__
print(tracker1.subclasses) # will describe Baz and Plop, but not Quux
print(tracker2.subclasses) # will describe Quux and Plop
print(tracker3.subclasses) # will describe only Plop
I am working on a code base that uses oop and I am relavtively new to it. My question specifically is, why NewMenuItem not inherit from File?
code bunk to play with code: https://codebunk.com/b/350127244/
"""Build class hierarchy and get values from decendants"""
import inspect
def selftest():
class Menu(object):
def __init__(self):
super(Menu, self).__init__()
self.value = "Menu"
class MenuBar(Menu):
#having object in there makes it a new style object, which allows us to use super
def __init__(self):
super(MenuBar, self).__init__()
self.value = "MenuBar"
class File(MenuBar):
def __init__(self):
Menu.__init__()
super(File, self).__init__()
self.value = "File"
self.FileValue = "File here!"
class New(Menu):
def __init__(self):
Menu.__init__()
pass
class NewMenuItem(Menu):
def __init__(self):
"""
Q 1- Why do I need self here?
Menu.__init__(self)
"""
Menu.__init__(self)
pass
def show_vals(self):
print(self.value)
"""
Q 2 -why wont this work?
def show_vals2(self):
print(self.FileValue)
"""
example = File.New.NewMenuItem()
example.show_vals()
"""
Q 3 - Why do I get this error with this line?
inspect.getmro(example)
AttributeError: 'ManageProduct' object has no attribute '__bases__'
"""
I'm trying to understand what is happening line by line, but what I don't get is why NewMenuItem doesn't inherit from File.
I tried hard-coding the instantiation of File,like so:
File.init()
but then I get an error unless I pass the File object:
File.__init__(File())
I guess what I am struggling with is:
-inheritance trees
-super classes
-why we need to hard-code instantiations in this case
Keep in mind that this is the code I have come across. I am not sure why this is the way it is.
Inheritance and scope are two completely different things. NewMenuItem is defined inside the scope of the class New, inside of the scope of the class File, but it inherits from Menu, which inherits from object. So while NewMenuItem will only be accessible through the class File and again through New, it will inherit its methods from Menu, and super will refer to Menu.
I'm trying to inherit attributes from a super class but they are not being initialized correctly:
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
super(Thing, self).__init__()
print self.attribute1
This throws an error since attribute1 is not an attribute of OtherThing, even though Thing.attribute1 exists. I thought this was the correct way to inherit and extend a super class. Am I doing something wrong? I don't want to create an instance of Thing and use its attributes, I need it to inherit this for simplicity.
You have to give, as argument, the class name (where it is being called) to super():
super(OtherThing, self).__init__()
According to Python docs:
... super can be used to refer to parent classes without naming them
explicitly, thus making the code more maintainable.
so you are not supposed to give the parent class.
See this example from Python docs too:
class C(B):
def method(self, arg):
super(C, self).method(arg)
Python3 makes this easy:
#!/usr/local/cpython-3.3/bin/python
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
#super(Thing, self).__init__()
super().__init__()
print(self.attribute1)
def main():
otherthing = OtherThing()
main()
When I create a parent class and child class as shown below, why don't the arguments from the parent class automatically get pulled in by the child class?
I understand that explicit is better, but I'm wondering in what circumstance this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testParentParam1,testParentParam2,testChildParam1,testChildParam2):
pass
Is better than this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testChildParam1,testChildParam2):
pass
Derived classes extend base classes. That means they might need more/less/different information at construction time to do their extending. Consider:
class BaseTextDocument(object):
def __init__(self, content):
self.content = content
class WordDocument(object):
def __init__(self, path, word_version="guess_from_file"):
content = parse_word_document(path, word_version)
super(WordDocument, self).__init__(content)