Title: Repeated functionality/code in Python classes, initializers and methods
Tags: python;class;python-3.x;initialization
Question: I am trying to implement a repeated functionality in classes (including their initializers) and methods in an efficient and Pythonic way.
I am subclassing and overriding methods (as seen here). I have counters defined and augmented assignments on each class.
My code
class StructuralAnalysis(object):
def __init__(self):
self.counter_results = []  # probably a dict would be better
def generate_structural_metrics(self):
# declare counters
cnum = 0
cstr = 0
cbytes = 0
...
...
...
for node in ast.walk(self.tree):
if isinstance(node, ast.Num):
cnum += 1
elif isinstance(node, ast.Str):
cstr += 1
elif isinstance(node, ast.Bytes):
cbytes += 1
elif ...
elif ...
elif ...
self.counter_results = [cnum, cstr, cbytes, .......]
# some counters may require some further calculations
return self.counter_results
My question is whether the above could be implemented in a more Pythonic and/or efficient way; like having a different class method for each counter that each overridden method will call to perform the augmented assign? This in order to avoid a -potentially- large amount of counter declarations and repeated code. Any suggestions would be great.
Comment: @biobirdman no idea what that is. Just exploring 'best' approaches on implemented repeated functionality in classes really..

Comment: are you looking for meta programming in python ?


Here is another answer: I wouldn't use a bunch of classes, since the overhead probably is too big (assuming most only keep a single counter, for that ast type).
However, I would check if there is a way to get the ast type via a function (so not a boolean for isinstance, but type(var). When you have the ast type you can use the dictionary you already had as idea to write something like
counters = {}
for node in ast.walk(self.tree):
counters[type(node)] += 1
This will iterate through all nodes and add the counters into a dictionary.
For the additional calculations you can make another dictionary:
counter_calculations = {}
counter_calculations[ast.BYTE] = perform_additional_calculations_byte
For each type add the function reference if there is a function needed. This way you can call very easily the extra calculations needed for a type (you can use it in the same iterator).
if (type(node) in counter_calculations:
counter_calculations[type(node)]()
Then implement the functions, for example for a byte:
def perform_additional_calculations_byte(byte_node):
... some calculations
For the counter results to return you can return the counters dictionary.
Comment for this answer: All your code I adapted into what I think is the solution you are looking for (or do I miss a code chunk?)
Comment for this answer: If you need the isinstance (because you want to 'group'  some classes as a type for example, you can make a different function who converts a class/type to an ast type you want to use and put that in the dictionary.
Comment for this answer: I struggle to understand what you suggest (newbie in Python). Could you please take a few minutes to implement what you are saying onto the small code chunk I put in my description as an example?
Comment for this answer: I understood what you suggest. Very clever. However, for this specific case I do need to have all the `isinstance` checks, so I guess this is not an ideal solution for me. I will accept your answer if no other suggestions are presented.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 2, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2016:00:06/10/16', 'FavoriteCount': 0.0, 'PostTypeId': 1, 'Tags': '<python><class><python-3.x><initialization>', 'Title': 'Repeated functionality/code in Python classes, initializers and methods', 'ViewCount': 64, 'id': 37743065, 'user_AboutMe': None, 'user_AccountId': None, 'user_DisplayName': None, 'user_Reputation': None, 'user_Views': None, 'user_id': None}}