категории | RSS
  

В данной статье речь пойдет об объявлении и использовании функций внути других функций. Ничего не поняли? Не беда, читайте дальше, поймете!

Надеюсь вы умеете создавать и использовать функции. Если нет, то эта статья не для вас, учимся пользовться функциями и только тогда возвращаемся к этой статье.

Итак, функции, если вы еще незнали, можно объявлять не только в основном коде, но и в других функциях. Для наглядности рассмотрип следующий пример:

import appuifw
def summa():
def a():
a=appuifw.query(u'Vvedite a','number')
return a
def b():
b=appuifw.query(u'Vvedite a','number')
return b
print a()+b()

summa()


Разберем код:
Мы создаем функцию summa() которая должна будет считать сумму любых двух чисел. Далее мы создали еще две функции: a() и b(). Заметте, эти две функции созданны внутри функции summa(). В этих функциях выводяться окошки, в которых пользователю предлагаеться ввести числа для вычисления суммы и возвращаеться число введеное пользователем. Далее идет строка где вычисляеться сумма этих двух чисел, и выводиться на экран командой print. Эта строка принадлежит уже функции summa().

Перед переходом к рассмотрению более сложных примеров использования вложенных функций, рассмотрим некоторые особенности данного подхода.
Вложенные функции могут использоваться только внутри тех функции, в которых они были созданы. Рассмотрим предыдущий пример: мы создали функцию summa(), а в ней еще две функции a() и b() (на случай если вы забыли). Внутри функции summa(), мы можем спокойно исспользовать эти две функции. Но, вне summa(), мы не можем их использовать.

def summa():
def a():
a=appuifw.query(u'Vvedite a','number')
return a
def b():
b=appuifw.query(u'Vvedite a','number')
return b
print a()+b()

summa()


Скажем я ввел число a=4, а число b=1, на экран выведиться сумма этих чисел - 5. Теперь попробуем воспользоваться функцией a() вне функции summa().

a()


В результате произойдет ошибка:

Traceback (most recent call last):
File "E:\eff20111\inspect.py", line 213, in inspect
File "d:\iPro7_Inspecting\default.py", line 10, in ?
a()
NameError: name 'a' is not defined

Что значит функции с именем 'a' не обнаруженно.

Теперь о переменных
Любые переменные объявленные в основной функции, в том числе и глобальные, могут быть использованы во вложенной функции:

import appuifw
x='Hello'
def hello():
global x
name=appuifw.query(u'Your name','text')
def prt():
print x,name
prt()

hello()


В тоже время переменные объявленные во вложенной функции, не могут быть использованы в основной:

def a():
def b():
name='Python'
print name

a()


Результат:

Traceback (most recent call last):
File "E:\eff20111\inspect.py", line 213, in inspect
File "d:\iPro7_Inspecting\default.py", line 6, in ?
a()
File "d:\iPro7_Inspecting\default.py", line 4, in a
print name
NameError: global name 'name' is not defined

Так же обстоят дела и с глобальными переменными, объявленными во вложенной функции.
Если вам необходимо использовать переменные, в том числе и глобальные, как в основной так и во вложенной функциях, объявляйте их в осовой. Если же эти переменные необходимы только во вложенной, то и объявляйте только во вложенной функции.

Теперь рассмотрим более практические примеры исспользования вложенмых функций: создание меню на listbox.

import appuifw,e32#импорт необходимых модулей

#далее идут функцию для элементов меню
#пример Canvas
def canvas():
appuifw.app.body=kan=appuifw.Canvas()
kan.text((10,30),u'Primer Canvas',0xff0000,'title')
appuifw.app.exit_key_handler=menu

#пример text
def text():
appuifw.app.body=txt=appuifw.Text()
txt.add(u'Primer text')
appuifw.app.exit_key_handler=menu

#функция выхода
def exit():
import os
os.abort()

#собственно само меню
def menu():
#функция которая будет выполняться при выборе элемента listbox
def select():
id=lsbx.current()
if id==0:
canvas()
elif id==1:
text()
else:
exit()

#список элементов меню
list=[u'Canvas',u'Text',u'Exit']
#сам listbox
appuifw.app.body=lsbx=appuifw.Listbox(list,select)

menu()
e32.Ao_lock().wait()#чтобы увидеть результат в консоли


Рассмотрим преимущества данной реализации:
- при выборе элемента listbox выполняеться необходимая функция;
- из функции можно вернуться назад, в наше меню на listbox;

Чтобы вы лучше поняли преимуществ данной реализации, рассмотрим еще несколько и их недостатки..

Создать просто listbox, в не функции, и функцию которая будет вызываться при выборе элемента меню:

def select():
id=lsbx.current()
if id==0:
canvas()
elif id==1:
text()
else:
exit()

list=[u'Canvas',u'Text',u'Exit']
appuifw.app.body=lsbx=appuifw.Listbox(list,select)


При данной реализации меню создаеться, и при выборе элемента меню запускаеться необходимая нам функция. А главное все предельно просто, без всяких там вложенных функций. Но, запустив функцию, скажем canvas() мы не сможем вернуться в наше меню, потому что оно было не в функции и не может быть вызвано еще раз.

Теперь попробуем занести listbox, в функцию:

def select():
id=lsbx.current()
if id==0:
canvas()
elif id==1:
text()
else:
exit()

def menu():
list=[u'Canvas',u'Text',u'Exit']
appuifw.app.body=lsbx=appuifw.Listbox(list,select)

menu()


Таким образом мы сможем вернуться из некой функции в наше меню, но при условии что вы ее запустите. В данной реализации список выведиться на экран, но при выборе элемента произойдет ошибка, что-то типа переменная lsbx не найдена. Если вы внимательно читали о работе функций в Python, то должны знать, что после завершения функции, все переменные, если они не являються глобальными, удаляються (стираються, исчезают). Так вот, при выборе элемента меню функция menu() завершаеться и в месте с ней исчезают и все переменные использованные в ней. Начинаеться выполнение функции select(), но переменной lstb в этой функции, или где либо еще, нет, и поэтому происходит ошибка.

Вывод:
Вложенные функции позволяют создать нам аналоги классов, только с "урезанными" возможностями (вложенные функции, в отличии от функций в классах, нельзя использовать где либо, кромж той функци, в которой они были созданны. Но не смотря на эти ограничения, вложенные функции позволяют создать нам более функциональные программы, и сохранить при этом читаемость кода.

Напоследок хотелось бы пожелать удачи в изучении Python, и программировании на нем.
С ув. Сергей Сахно aka Punk_Joker


Punk_Joker
2011-07-01T06:43:31Z
Здесь находятся
всего 0. За сутки здесь было 0 человек

Комментарии 13

#13   dimy44    

Глобальные переменные в функции не надо объявлять global, если не там она не будет изменяться. Для чтения и так можно юзать


0 ответить

#13   Punk_Joker    

Обновление от 13/07/2011 14:01:46
============
Причина редактирования: редактирование статьи


0 ответить

#13   Punk_Joker    

Virtuos86,
Под этим словами я подрозумевал нечто другое. Но спасибо за замечание. Думал уже вылаживать исправленный вариант, а придеться опять править ее.


0 ответить

#13   Virtuos86    

В отличии от функций в классах, такие функции могут использоваться только в тех функция, в которых они были обьявленны.

А что, про замыкания забыли?

def function():
def inner():
print "I am a function closure."
return inner

closure = function()
closure() # ну вот я использовал вложенную функцию


0 ответить

#13   sawka6600    

Punk_Joker
Думаю это лишнее

Так покажи это. Напиши пример, где к объявленной и существующей в функции переменной можно обратиться, а как только функция отработала, снова вызови эту переменную и продемонстрируй людям ошибку. Если ты вообще считаешь нужным это делать, конечно.


0 ответить

#13   dimy44    

раз переписываешь, я свой коммент удалил как уже неактуальный


0 ответить

#13   Punk_Joker    

dimy44,
Это моя первая статья, и я понимаю что она неочень. И даже рад такой критике. Сегодня уже начну переписывать.
-------------
Добавлено в 01.35: sawka6600,
Думаю это лишнее, т.к переменные созданные во вложенных функциях пропадают уже после завершения этой вложенной функции.
-------------
Добавлено в 01.44: Наконец начал ее переписывать. Все таки много, очень важных аспектов пропустил в статье. Надеюсь на этот раз все учту.


0 ответить

#13   Punk_Joker    

Спасибо за коментарии. Седня или завтра перепишу статью с учетом всех замечаний и в более понятной для новичков форме, потому как сам бы врятли понял ее еще пол года назад.


0 ответить

#13   sawka6600    

Просто интересно: зачем переименовывать уже существующую стандартную функцию (см. ниже)?

def exit():
abort()

По сути, в детском саде есть мальчик с именем Антон. Воспитатель говорит: \"Теперь ты, Антон, не Антон, а Федя.\" У Антона-то выбора нет, так как ему три года всего, а воспитатель - бог в его глазах. И теперь воспитатель может позвать как Федю, так и Антона, а прибежит один и тот же мальчик. То есть, Punk_Joker, теперь ты можешь вызвать функцию abort() двумя способами: abort() и exit(). Надеюсь, я доступно донес мысль?
-----------------------------
Ну а за то, что рассказал про вложенные функции, спасибо. Оно, конечно, становится очевидным само по себе после месяца-другого кодинга, но кому-то это может упростить жизнь. Особенно если бы ты показал, что в месте, где
return 4+2
можно воткнуть диалог с пользователем, спросить, что он хочет ввести, или что-то в этом роде... Ну ты понял, я думаю. Это было первое. И второе - переменные, объявляемые во вложенных функциях, пропадают (обнуляются, стираются, удаляются, умирают) как только завершает свою работу функция-родитель. Есть у тебя там такой намек в статье, но неплохо бы его развить и подтвердить примером.
----------------------------
Ну а в общем ниче, пиши еще wink Плюсик поставлю за старания.


1 ответить

#13   nethunter0    

Имхо это - статья с кусками кода)))


0 ответить

Напомнить пароль