Path: csiph.com!feeder.erje.net!2.eu.feeder.erje.net!ecngs!testfeeder.ecngs.de!81.171.118.64.MISMATCH!peer04.fr7!news.highwinds-media.com!fu-berlin.de!uni-berlin.de!not-for-mail From: "Martin A. Brown" Newsgroups: comp.lang.python Subject: Re: how to optimize the below code with a helper function Date: Mon, 4 Apr 2016 07:07:20 -0700 Lines: 160 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Trace: news.uni-berlin.de NyDNlZhyWvuKbydmUPrbQgIAIn5p1UIjAJYgV9hI+zoQ== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'args': 0.04; 'sys': 0.05; '__name__': 0.07; 'main()': 0.07; 'skip:/ 10': 0.07; 'subject:code': 0.07; 'cc:addr:python-list': 0.09; '__future__': 0.09; 'although,': 0.09; 'func': 0.09; 'logger': 0.09; 'observation': 0.09; 'testcases': 0.09; 'variables,': 0.09; 'python': 0.10; 'def': 0.13; "'__main__':": 0.16; 'arguments:': 0.16; 'd.items():': 0.16; 'dictionary,': 0.16; 'division,': 0.16; 'from:addr:martin': 0.16; 'function?': 0.16; 'guessing': 0.16; 'i.e': 0.16; 'idea:': 0.16; 'jumps': 0.16; 'luck,': 0.16; 'main():': 0.16; 'received:hsd1.or.comcast.net': 0.16; 'received:io': 0.16; 'received:or.comcast.net': 0.16; 'received:psf.io': 0.16; 'yank': 0.16; 'string': 0.17; 'helper': 0.18; 'skip:l 30': 0.18; 'test.': 0.18; 'variable': 0.18; 'all,': 0.20; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; 'martin': 0.22; 'function,': 0.22; 'rid': 0.22; 'simpler': 0.22; 'code,': 0.23; '(or': 0.23; 'seems': 0.23; '(you': 0.23; 'this:': 0.23; 'import': 0.24; 'header:In-Reply-To:1': 0.24; 'sort': 0.25; 'testing': 0.25; 'command': 0.26; 'sense': 0.26; 'external': 0.27; 'figure': 0.27; 'error': 0.27; 'logging': 0.27; 'parameters': 0.27; 'question': 0.27; 'data,': 0.27; 'sequence': 0.27; 'received:24': 0.28; 'function': 0.28; "skip:' 10": 0.28; 'looks': 0.29; 'command- line': 0.29; 'dictionary': 0.29; "i'm": 0.30; 'code': 0.30; 'becomes': 0.30; 'call.': 0.30; 'putting': 0.30; 'guess': 0.31; 'operations': 0.31; 'probably': 0.31; 'operate': 0.32; 'though,': 0.32; 'url:python': 0.33; 'call,': 0.33; 'optimize': 0.33; 'received:comcast.net': 0.33; 'similar': 0.33; 'case,': 0.34; 'file': 0.34; 'handle': 0.34; 'skip:d 20': 0.34; 'gets': 0.35; 'could': 0.35; 'something': 0.35; 'expected': 0.35; 'but': 0.36; 'should': 0.36; 'there': 0.36; 'url:org': 0.36; 'basic': 0.36; 'cases': 0.36; 'data.': 0.36; 'keyword': 0.36; 'subject:: ': 0.37; 'done.': 0.37; 'charset:us-ascii': 0.37; 'mean': 0.38; 'skip:o 20': 0.38; 'end': 0.39; 'why': 0.39; 'test': 0.39; 'data': 0.39; 'subject:the': 0.39; 'easily': 0.39; 'well.': 0.40; 'where': 0.40; 'subject:with': 0.40; 'your': 0.60; 'received:network': 0.61; 'further': 0.62; 'more': 0.63; 'different': 0.63; 'sample': 0.63; 'times': 0.63; 'here': 0.66; 'wish': 0.71; 'greetings': 0.71; '100': 0.79; '**kw)': 0.84; '**kw):': 0.84; '>function': 0.84; 'avoid.': 0.84; 'dict()': 0.84; 'scenarios,': 0.84; 'subject:below': 0.84; 'url:tutorial': 0.91 X-X-Sender: mabrown@macron.wonderfrog.net In-Reply-To: X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: X-Mailman-Original-References: X-Received-Bytes: 9505 X-Received-Body-CRC: 3376190949 Xref: csiph.com comp.lang.python:106439 Greetings (again) Ganesh, I notice that you ask about how to optimize the code, but I think what you mean is you want simpler code that is less repetitive and less copy/paste error-prone. Is that correct? Below, I make a few suggestions about how to simplify, although, there probably is further simplification that could be done. >I am on python 2.7.10 and Linux. Noted. I tested my answer to your question on a Python 2.7, as well. >I have a python function where the similar kind of pattern >repeating 100 of times When you have a repetitive sequence of operations (or test cases, it looks like), you can often figure out a way to store the parameters as data. When the parameters become data, then, the code becomes simpler. >Sample code snippet: > >test01_log = os.path.join(LOG_DIR, "test01.log") > cls.get_baddr['test01'] = failure.run_tool( > test01_log, object="inode", offset="18", size="4", > optype="set") > >test02_log = os.path.join(LOG_DIR, "test02.log") > cls.get_baddr['test02'] = failure.run_tool( > test02_log, lin=lin_02, object="lin", offset="100", size="5", > optype="set") > ..............................................------------------------ > >test100_log = os.path.join(LOG_DIR, "test100.log") > cls.get_baddr['test100'] = failure.run_tool( > test02_log, baddr=lin_02, object="baddr", offset="100", size="5", > optype="set") I observe that here in the failure.run_tool() call, the logfile is test02_log. I would have expected it to be test100_log. I'm guessing that this is exactly the sort of copy/paste error that you wish to avoid. >(1) Any tips how I can optimize this i.e test case, should have a helper >function that all test cases call. One function that jumps out very easily (to my eye) is a function to create the logfile name from the test case name. You will see how I do that in the sample, so that you can call the run_tool function as you are currently calling it. (You might consider putting the logfile name generation into the run_tool function, though, in which case, run_tool gets even simpler and you can get rid of my function, addLogFilename. Hopefully, that makes sense to you....) >(2) Also note that failure.run_tool function can have variable >number of argments how to handle this in the helper function? A variable number of arguments: this seems like the perfect case for using keyword arguments! https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments I have one additional observation about your sample code, Ganesh. When I read this: cls.get_baddr['test01'] = failure.run_tool( test01_log, object="inode", offset="18", size="4", optype="set") I am guessing that you are calling an external program in your test. I also notice that you have string contents in your variables, for example, offset="18". (That's part of why I guess you are calling an external program as part of your test.) If you are calling an external command in 'run_tool', why not put the exact command-line you want to execute into the test data. This would simplify your code and makes the test more transparent, as well. d = dict() d['test01'] = dict(cmd=['some_command', '--offset', '18', '--size', '4'], optype="set", object='inode') Then, in run_tool, something like this: subprocess.Popen(cmd, shell=False, stderr=logfile) But, these suggestions are all, basically, different riffs on the same basic idea: Where you have many testing scenarios, try to figure out a way to store all of the test cases in data and then have the test runner operate on the data. Good luck, -Martin #! /usr/bin/python from __future__ import absolute_import, division, print_function import os import sys import logging logging.basicConfig(stream=sys.stderr, level=logging.INFO) logger = logging.getLogger(__name__) LOG_DIR = '/var/log/frobnitz' def createTestCases(LOG_DIR): '''create a test case data dictionary with parameters''' d = dict() d['test01'] = dict(object="inode", offset="18", size="4", optype="set") lin_02 = "something" d['test02'] = dict(object="lin", lin=lin_02, offset="18", size="5", optype="set") d['test100'] = dict(object="baddr", baddr=lin_02, offset="100", size="5", optype="set") return addLogFilename(d, LOG_DIR) def run_tool(logfile, **kw): logger.info('%s would execute with %r', logfile, kw) def addLogFilename(d, logdir): '''put the logfile name into the test case data dictionary''' for casename, args in d.items(): args['logfile'] = os.path.join(logdir, casename + '.log') return d def main(): testcases = createTestCases(LOG_DIR) get_baddr = dict() for casename, kw in testcases.items(): # -- yank the logfile name out of the dictionary, before calling func logfile = kw.pop('logfile') get_baddr[casename] = run_tool(logfile, **kw) if __name__ == '__main__': main() # -- end of file -- Martin A. Brown http://linux-ip.net/