Spójrz na dwa sposoby strukturyzacji moich funkcji:

class myClass:
    def _myFunc(self):
        pass

    def myFunc2(self):
        self._myFunc()

class myClass:
    def myFunc2(self):
        def myFunc():
            pass

        myFunc()

Czy druga opcja będzie wolniejsza? Muszę tylko zadzwonić do MyFunc z MyFunc2, więc lubię ukryć go z mojej dokumentacji modułu, mogłem użyć podkreślenia za to, ale myślałem, że będzie czyszczony, aby mieć go w funkcji. Z drugiej strony może być konieczne zadzwonić do MyFunc2 kilkaset razy na sekundę, więc "przedefiniowanie" Myfunc podczas dzwoniących MyFunc2 za każdym razem może być wolno ... jest to dobre zgadywanie?

6
user975135 19 październik 2011, 19:12

4 odpowiedzi

Najlepsza odpowiedź

Lokalna funkcja w drugim wariancie nie zostanie skompilowana w kółko i jest skompilowana raz wraz z całym plikiem, a jego korpus jest przechowywany w obiekcie kodu. Jedyną rzeczą, która dzieje się podczas wykonywania funkcji zewnętrznej, jest to, że obiekt kodu jest zawinięty w nowy obiekt funkcyjny, który jest następnie związany z nazwą lokalną myFunc.

Może istnieć różnica między dwoma wariantami, jeśli myFunc() przyjmuje domyślne parametry. Ich definicja zostanie wykonana w kółko w drugim wariancie, co skutkuje możliwym trafieniem wydajności.

Przesadny przykład:

from time import sleep

class MyClass:
    def _my_func(self, x=sleep(1)):
        pass
    def my_func2(self):
        self._my_func()

class MyClass2:
    def my_func2(self):
        def my_func(x=sleep(1)):
            pass
        my_func()

Wraz z kodem Daft powyżej, myClass.myFunc2() powróci natychmiast, podczas gdy myClass2.myFunc2() zajmuje sekundę do wykonania.

3
Sven Marnach 19 październik 2011, 15:48

Korzystanie z Pythona 2.6.5 na 64-bitowej Ubuntu nie ma dostrzegalnej różnicy:

# version 1
In [2]: %timeit c1.myFunc2()
1000000 loops, best of 3: 461 ns per loop

# version 2
In [3]: %timeit c2.myFunc2()
1000000 loops, best of 3: 464 ns per loop
7
NPE 19 październik 2011, 15:15

Kropkowane wyszukiwanie (A.K.A. Wiązanie atrybutu) zawsze trwa dłużej niż zagnieżdżone wyszukiwanie zakresu. Pierwsza wiąże się z serii Słownik wyszukiwania i tworzenia nowego obiektu (metoda związana lub niejawna). Ta ostatnia używa zmiennych komórek i są zaimplementowane za pomocą wyszukiwania tablicy.

2
Raymond Hettinger 19 październik 2011, 19:43

Pomimo innych odpowiedzi, które twierdzą, że nie ma efektu, myślałem, że powinienem sprawdzić. Znalazłem bardzo wyraźną zaletę, aby określić funkcję na zewnątrz.

import random
def ff1(i):
    r1 = random.random()
    r2 = random.random()
    if r1 < 0.5:
        return i*r2
    else:
        return i/r2

def f1(i):
    return ff1(i)

def f2(i):
    def ff2(i):
        r1 = random.random()
        r2 = random.random()
        if r1 < 0.5:
            return i*r2
        else:
            return i/r2
    return ff2(i)
%%timeit -r 10 -n 10 
x = 0.5
for i in xrange(10000):
    x = f1(x)

10 pętli, najlepiej 10: 4,2 ms na pętlę

%%timeit -r 10 -n 10
x = 0.5
for i in xrange(10000):
    x = f2(x)

10 pętli, najlepiej 10: 5,33 ms na pętlę

%%timeit -r 1 -n 1 
x = 0.5
for i in xrange(1000000):
    x = f1(x)

1 pętle, najlepsze z 1: 438 ms na pętlę

%%timeit -r 1 -n 1
x = 0.5
for i in xrange(1000000):
    x = f2(x)

1 pętle, najlepsze z 1: 574 ms na pętlę

0
jvd10 7 lipiec 2016, 14:28