Разделение больших функций на более читаемые, более мелкие функции является частью написания кода Pythonic - должно быть очевидно, что вы пытаетесь выполнить, а более мелкие функции легче читать, проверять наличие ошибок, поддерживать и повторно использовать.
Как всегда, вопросы, «которые имеют лучшую производительность», всегда должны решаться profiling the code, то есть они часто зависят от подписи методов и того, что делает ваш код.
например. если вы передаете большой словарь в отдельную функцию вместо ссылки на локальный фрейм, вы получите разные характеристики производительности, чем вызов функции void
от другого.
Например, вот некоторые тривиальное поведение:
import profile
import dis
def callee():
for x in range(10000):
x += x
print("let's have some tea now")
def caller():
callee()
profile.run('caller()')
let's have some tea now
26 function calls in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.000 0.000 0.000 0.000 :0(decode)
2 0.000 0.000 0.000 0.000 :0(getpid)
2 0.000 0.000 0.000 0.000 :0(isinstance)
1 0.000 0.000 0.000 0.000 :0(range)
1 0.000 0.000 0.000 0.000 :0(setprofile)
2 0.000 0.000 0.000 0.000 :0(time)
2 0.000 0.000 0.000 0.000 :0(utf_8_decode)
2 0.000 0.000 0.000 0.000 :0(write)
1 0.002 0.002 0.002 0.002 <ipython-input-3-98c87a49b247>:4(callee)
1 0.000 0.000 0.002 0.002 <ipython-input-3-98c87a49b247>:9(caller)
1 0.000 0.000 0.002 0.002 <string>:1(<module>)
2 0.000 0.000 0.000 0.000 iostream.py:196(write)
2 0.000 0.000 0.000 0.000 iostream.py:86(_is_master_process)
2 0.000 0.000 0.000 0.000 iostream.py:95(_check_mp_mode)
1 0.000 0.000 0.002 0.002 profile:0(caller())
0 0.000 0.000 profile:0(profiler)
2 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
против
import profile
import dis
def all_in_one():
def passer():
pass
passer()
for x in range(10000):
x += x
print("let's have some tea now")
let's have some tea now
26 function calls in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.000 0.000 0.000 0.000 :0(decode)
2 0.000 0.000 0.000 0.000 :0(getpid)
2 0.000 0.000 0.000 0.000 :0(isinstance)
1 0.000 0.000 0.000 0.000 :0(range)
1 0.000 0.000 0.000 0.000 :0(setprofile)
2 0.000 0.000 0.000 0.000 :0(time)
2 0.000 0.000 0.000 0.000 :0(utf_8_decode)
2 0.000 0.000 0.000 0.000 :0(write)
1 0.002 0.002 0.002 0.002 <ipython-input-3-98c87a49b247>:4(callee)
1 0.000 0.000 0.002 0.002 <ipython-input-3-98c87a49b247>:9(caller)
1 0.000 0.000 0.002 0.002 <string>:1(<module>)
2 0.000 0.000 0.000 0.000 iostream.py:196(write)
2 0.000 0.000 0.000 0.000 iostream.py:86(_is_master_process)
2 0.000 0.000 0.000 0.000 iostream.py:95(_check_mp_mode)
1 0.000 0.000 0.002 0.002 profile:0(caller())
0 0.000 0.000 profile:0(profiler)
2 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
Два используют один и тот же Numbe r вызовов функций, и нет разницы в производительности, что подтверждает мое утверждение о том, что действительно важно проверить в определенных обстоятельствах.
Вы можете видеть, что у меня есть неиспользованный импорт для модуля disassembly. Это еще один полезный модуль, который позволит вам увидеть, что делает ваш код (попробуйте dis.dis(my_function)
).Я бы опубликовал профиль тестового кода, который я сгенерировал, но он только покажет вам больше деталей, которые не имеют отношения к решению проблемы или не узнают, что на самом деле происходит в вашем коде.
Что делает ваше профилирующее шоу? https://docs.python.org/3/library/profile.html –
Обычно я использую встроенные функции, когда хочу закрыть. Я также использую их, когда встроенная функция не имеет возможности использовать вне своей закрывающей функции. – acushner
@tristan, я меньше интересовался вычислительной производительностью, большей внутренней памятью, я думаю? Но об этом было бы интересно узнать. –