Mix-in class tree file not running the self test code. - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Mix-in class tree file not running the self test code. (/thread-12013.html) |
Mix-in class tree file not running the self test code. - arjunsingh2908 - Aug-05-2018 Hi, I am learning Python classes and I have hit a roadblock in one particular file. So, I coded a file(listtree.py) which has a self-test code with a module listed below(testmixin.py). When I am running listtree.py, I am getting an error which I cannot understand(listed below). Please let me know if anyone can help me out on this. Have been staring at it for an hour but no luck. -Arjun #!python # File: listtree.py (2.X + 3.X) class ListTree: """ Mix-in that returns an __str__ trace of the entire class tree and all its objects' attrs at and above self; run by print(), str() returns constructed string; uses __X attr names to avoid impacting clients; recurses to superclasses explicitly, uses str.format()for clarity; """ def __attrnames(self, obj, indent): spaces = ' ' * (indent+ 1) result = '' for attr in sorted(obj.__dict__): if attr.startswith('__') and attr.endswith('__'): result += spaces + '{0}\n'.format(attr) else: result += spaces + '{0}={1}\n'.format(attr, getattr(obj, attr)) return result def __listclass(self, aClass, indent): dots = '.' * indent if aClass in self.__visited: return '\n{0}<Class {1}:, address {2}: (see above)>\n'.format( dots, aClass.__name__, id(aClass)) else: self.__visited[aClass] = True here = self.__attrnames(aClass, indent) above = '' for super in aClass.__bases__: above += self.__listclass(super, indent+4) return '\n{0}<Class {1}, address {2}: \n{3}{4}{5}>\n'.format( dots, aClass.__name__, id(aClass), here, above, dots) def __str__(self): self.__visited = {} here = self.__attrnames(self, 0) above = self.__listclass(self.__class__, 4) return '<Instance of {0}, address {1}:\n{2]{3}>'.format( self.__class.__name__, id(self), here, above) if __name__ == '__main__': import testmixin testmixin.tester(ListTree) #!python # File: testmixin.py (2.X + 3.X) """ Generic lister mixin tester: similar to transitive reloader in Chapter 25, but passes a class object to tester (not function), and testbyNames adds loading of both module and class by name string here, in keeping with Chapter 31's factory pattern. """ import importlib def tester(listerclass, sept=False): class Super: def __init__(self): # Superclass __init__ self.data1 = 'spam' # Create instance attrs def ham(self): pass class Sub(Super, listerclass): # Mix in ham and a __str__ def __init__(self): # Listers have access to self Super.__init__(self) self.data2 = 'eggs' # More instance attrs self.data3 = 42 def spam(self): # Define another method here pass instance = Sub() # Return instance with lister's __str__ print(instance) # Run mixed-in __str__ (or via str(x)) if sept: print('-' * 80) def testbyNames(modname, classname, sept=False): modobject = importlib.import_module(modname) # Import by namestring listerclass = getattr(modobject, classname) # Fetch attr by name string tester(listerclass, sept) if __name__ == '__main__': testbyNames('listtree', 'ListTree', False)
RE: Mix-in class tree file not running the self test code. - Retrubtion - Aug-10-2018 Howdy Arjun! On line 51 of your listtree.py file you have a typo. self.__class.__name__, Should instead be self.__class__.__name__, The error message alerts you of this by saying AttributeError: 'Sub' object has no attribute '_ListTree__class' Without the trailing '__' on __class__ python 'mangles' the method call for self.__class to make it call a private method 'self._ListTree__class' 'self' in this case is the Sub class from testmixin.py the interpreter throws the error before moving to the .__name__ portion of your code on line 51. Hope this helped sort your problem. -Retrubtion RE: Mix-in class tree file not running the self test code. - arjunsingh2908 - Aug-11-2018 Aaaaarrrrggg....That was stupid, it sort of camouflaged and being a beginner I couldn't spot it...Dammnn.. Thank you so much man, this really helps me move past it...really appreciate it... -Arjun RE: Mix-in class tree file not running the self test code. - arjunsingh2908 - Aug-14-2018 Hey Retribution, Sorry to bug you again but, I corrected the line 51 to self.__class__.__name__. Unfortunately I am getting a subsequent error which is as follows; Please let me know where did I screw up this time. #!python # File: listtree.py (2.X + 3.X) class ListTree: """ Mix-in that returns an __str__ trace of the entire class tree and all its objects' attrs at and above self; run by print(), str() returns constructed string; uses __X attr names to avoid impacting clients; recurses to superclasses explicitly, uses str.format()for clarity; """ def __attrnames(self, obj, indent): spaces = ' ' * (indent+ 1) result = '' for attr in sorted(obj.__dict__): if attr.startswith('__') and attr.endswith('__'): result += spaces + '{0}\n'.format(attr) else: result += spaces + '{0}={1}\n'.format(attr, getattr(obj, attr)) #result += spaces + '%s=%s\n' % (attr, getattr(obj, attr)) return result def __listclass(self, aClass, indent): dots = '.' * indent if aClass in self.__visited: return '\n{0}<Class {1}:, address {2}: (see above)>\n'.format( dots, aClass.__name__, id(aClass)) else: self.__visited[aClass] = True here = self.__attrnames(aClass, indent) above = '' for super in aClass.__bases__: above += self.__listclass(super, indent+4) return '\n{0}<Class {1}, address {2}: \n{3}{4}{5}>\n'.format( dots, aClass.__name__, id(aClass), here, above, dots) def __str__(self): self.__visited = {} here = self.__attrnames(self, 0) above = self.__listclass(self.__class__, 4) return '<Instance of {0}, address {1}:\n{2]{3}>'.format( self.__class__.__name__, id(self), here, above) if __name__ == '__main__': import testmixin testmixin.tester(ListTree) #!python # File: testmixin.py (2.X + 3.X) """ Generic lister mixin tester: similar to transitive reloader in Chapter 25, but passes a class object to tester (not function), and testbyNames adds loading of both module and class by name string here, in keeping with Chapter 31's factory pattern. """ import importlib def tester(listerclass, sept=False): class Super: def __init__(self): # Superclass __init__ self.data1 = 'spam' # Create instance attrs def ham(self): pass class Sub(Super, listerclass): # Mix in ham and a __str__ def __init__(self): # Listers have access to self Super.__init__(self) self.data2 = 'eggs' # More instance attrs self.data3 = 42 def spam(self): # Define another method here pass instance = Sub() # Return instance with lister's __str__ print(instance) # Run mixed-in __str__ (or via str(x)) if sept: print('-' * 80) def testbyNames(modname, classname, sept=False): modobject = importlib.import_module(modname) # Import by namestring listerclass = getattr(modobject, classname) # Fetch attr by name string tester(listerclass, sept) if __name__ == '__main__': testbyNames('listinstance', 'ListInstance', True) # Test all three here testbyNames('listinherited', 'ListInherited', True) testbyNames('listtree', 'ListTree', False)
|