Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder1.news.weretis.net!feeder.erje.net!1.eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed3a.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail 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; 'subject:not': 0.03; 'essentially': 0.04; '===': 0.09; 'function,': 0.09; 'lookup': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'python': 0.11; 'def': 0.12; 'mostly': 0.14; 'bypassing': 0.16; 'evaluating': 0.16; 'footing.': 0.16; 'from:addr:behnel.de': 0.16; 'from:addr:stefan_ml': 0.16; 'from:name:stefan behnel': 0.16; 'func():': 0.16; 'internally': 0.16; 'received:80.91.229.3': 0.16; 'received:dip0.t-ipconnect.de': 0.16; 'received:plane.gmane.org': 0.16; 'received:t-ipconnect.de': 0.16; 'code.': 0.18; 'basically': 0.19; 'file,': 0.19; 'pieces': 0.19; 'replacing': 0.19; 'stefan': 0.19; 'import': 0.22; 'tests': 0.22; 'print': 0.22; 'header:User- Agent:1': 0.23; 'comparing': 0.24; 'equivalent': 0.26; 'header:X -Complaints-To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'skip:( 20': 0.30; 'code': 0.31; 'assert': 0.31; "d'aprano": 0.31; 'object.': 0.31; 'python2.7': 0.31; 'steven': 0.31; 'another': 0.32; 'equal': 0.35; 'but': 0.35; 'executing': 0.36; 'doing': 0.36; 'possible': 0.36; 'subject:?': 0.36; 'so,': 0.37; 'two': 0.37; 'easily': 0.37; 'generic': 0.38; 'to:addr:python- list': 0.38; 'does': 0.39; 'expensive': 0.39; 'to:addr:python.org': 0.39; 'received:org': 0.40; "you're": 0.61; 'name': 0.63; 'more': 0.64; 'here': 0.66; 'results': 0.69; 'cut': 0.74; 'itself?': 0.84; 'received:87.139': 0.84 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Stefan Behnel Subject: Re: Calling a function is faster than not calling it? Date: Mon, 11 May 2015 08:11:55 +0200 References: <554f2bb6$0$13011$c3e8da3$5496439d@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: p578baff2.dip0.t-ipconnect.de User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 In-Reply-To: <554f2bb6$0$13011$c3e8da3$5496439d@news.astraweb.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20+ Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 58 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1431324725 news.xs4all.nl 2878 [2001:888:2000:d::a6]:53662 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:90348 Steven D'Aprano schrieb am 10.05.2015 um 11:58: > Why is calling a function faster than bypassing the function object and > evaluating the code object itself? And not by a little, but by a lot? > > Here I have a file, eval_test.py: > > # === cut === > from timeit import Timer > > def func(): > a = 2 > b = 3 > c = 4 > return (a+b)*(a-b)/(a*c + b*c) > > > code = func.__code__ > assert func() == eval(code) > > t1 = Timer("eval; func()", setup="from __main__ import func") > t2 = Timer("eval(code)", setup="from __main__ import code") > > # Best of 10 trials. > print (min(t1.repeat(repeat=10))) > print (min(t2.repeat(repeat=10))) > > # === cut === > > > Note that both tests include a name lookup for eval, so that as much as > possible I am comparing the two pieces of code on an equal footing. > > Here are the results I get: > > > [steve@ando ~]$ python2.7 eval_test.py > 0.804041147232 > 1.74012994766 > [steve@ando ~]$ python3.3 eval_test.py > 0.7233301624655724 > 1.7154695875942707 > > Directly eval'ing the code object is easily more than twice as expensive > than calling the function, but calling the function has to eval the code > object. Well, yes, but it does so directly in C code. What you are essentially doing here is replacing a part of the fast C code path for executing a Python function by some mostly equivalent but more general Python code. So, you're basically replacing a function call by another function call to eval(), plus some extra generic setup overhead. Python functions know exactly what they have to do internally in order to execute. eval() cannot make the same streamlined assumptions. Stefan