Как получить(вернуть) значение переменной из функции в python 3?
Совсем не могу понять логику.
Написал короткий код для эксперимента.
Что я делаю не так?
Спасибо.
- Вопрос задан более трёх лет назад
- 34325 просмотров
- Вконтакте
- Вконтакте
Есть три варианта:
1. Использовать глобальную переменную
2. Вернуть тербуемое значение как значение функции и присвоить в переменную которая передана
3. Вернуть значение в списке переданном как параметр
Первый вариант — не слишком хорош т.к. глобальных переменных в большой программе может быть очень много и это приводит к сложностям сопровождения кода программы.
Второй вариант — довольно удобен, но нужно не забывать присваивать значение возвращаемое из функции.
Третий вариант — вообще экзотика, но и он иногда бывает востребован, особенно в рекурсиях или при работе с потоками (когда из потока хочется получить результат).
Ключевое слово global в Python
В этой статье вы узнаете, для чего нужно ключевое слово global и когда его использовать. А еще мы подробнее поговорим о глобальных переменных.
Поэтому перед прочтением этой статьи ознакомьтесь со статьей «Глобальные, локальные и нелокальные переменные в Python».
Что это такое
Ключевое слово global позволяет изменять переменную вне текущей области видимости в Python. global используется для создания глобальной переменной и изменения ее в локальной области видимости.
Что нужно знать прежде, чем работать с global
- Когда мы создаем переменную внутри функции, она по умолчанию является локальной.
- Когда мы определяем переменную вне функции, она по умолчанию является глобальной. В этом случае не нужно использовать ключевое слово global .
- Ключевое слово global нужно для получения доступа к глобальной переменной и изменения ее внутри функции, то есть внутри локальной области видимости.
- Использовать ключевое слово global вне функции бессмысленно.
Как использовать global
Пример 1. Получаем доступ к глобальной переменной внутри функции
Вывод:
Все работает! Но что если нам нужно изменить глобальную переменную внутри функции?
Пример 2. Изменяем глобальную переменную внутри функции
Вывод:
Python сообщает нам, что мы использовали локальную переменную c до ее объявления. Дело в том, что получить доступ к глобальной переменной внутри функции мы можем, а вот изменять ее в локальной области видимости — уже нет.
Для этого и нужно ключевое слово global .
Пример 3. Изменяем глобальную переменную внутри функции с помощью global
Вывод:
В приведенной выше программе мы определяем c как глобальную переменную внутри функции add() с помощью ключевого слова `global`.
Внутри функции мы также увеличиваем переменную c ` на 2, то есть выполняем действие c = c + 2 . И, наконец, выводим на экран глобальную переменную c .
Как мы видим, глобальная переменная c изменилась не только внутри функции, но и в глобальной области видимости. И там, и там c = 2 .
Глобальные переменные в модулях Python
В Python принято создавать единый модуль config.py для хранения глобальных переменных и обмена информацией между модулями Python в одной программе.
Вот как можно использовать глобальные переменные между модулями Python.
Пример 4. Используем глобальную переменную между модулями
Создаем файл config.py , в нем будем хранить глобальные переменные.
Создаем файл update.py , чтобы изменять глобальные переменные.
Создаем файл main.py . Его будем использовать, чтобы отслеживать изменения значений глобальных переменных.
Теперь запустим файл main.py .
Вывод:
Итак, мы создали 3 файла: config.py , update.py , и main.py .
Модуль config.py хранит глобальные переменные a и b . В файле update.py мы импортируем модуль config.py и изменяем значения a и b . Точно так же в файл main.py мы импортируем config.py и update.py . Наконец, мы печатаем и проверяем значения глобальных переменных независимо от того, изменились они или нет.
Как использовать global во вложенных функция
Пример 5. Используем глобальные переменные во вложенных функциях
Вывод:
В приведенной выше программе мы объявили глобальную переменную внутри вложенной функции bar() . Внутри функции foo() ключевое слово global никак не влияет на переменную x .
До и после вызова bar() переменная x принимает значение локальной переменной, т. е. x = 20 . Вне функции foo() переменная x примет значение, определенное в функции x , т. е. x = 25 . Так произойдет потому, что мы использовали ключевое слово global , чтобы создать глобальную переменную x внутри функции bar() , то есть в локальной области видимости.
Если мы сделаем какие-либо изменения внутри функции bar() , изменения отобразятся и за пределами локальной области видимости, то есть за пределами функции foo() .
Как использовать переменную из функции python
Область видимости или scope определяет контекст переменной, в рамках которого ее можно использовать. В Python есть два типа контекста: глобальный и локальный.
Глобальный контекст
Глобальный контекст подразумевает, что переменная является глобальной, она определена вне любой из функций и доступна любой функции в программе. Например:
Здесь переменная name является глобальной и имеет глобальную область видимости. И обе определенные здесь функции могут свободно ее использовать.
Локальный контекст
В отличие от глобальных переменных локальная переменная определяется внутри функции и доступна только из этой функции, то есть имеет локальную область видимости:
В данном случае в каждой из двух функций определяется локальная переменная name. И хотя эти переменные называются одинаково, но тем не менее это две разных переменных, каждая из которых доступна только в рамках своей функции. Также в функции say_hi() определена переменная surname, которая также является локальной, поэтому в функции say_bye() мы ее использовать не сможем.
Скрытие переменных
Есть еще один вариант определения переменной, когда локальная переменная скрывают глобальную с тем же именем:
Здесь определена глобальная переменная name. Однако в функции say_hi определена локальная переменная с тем же именем name. И если функция say_bye использует глобальную переменную, то функция say_hi использует локальную переменную, которая скрывает глобальную.
Если же мы хотим изменить в локальной функции глобальную переменную, а не определить локальную, то необходимо использовать ключевое слово global :
nonlocal
Выражение nonlocal прикрепляет идентификатор к переменной из ближайщего окружающего контекста (за исключением глобального контекста). Обычно nonlocal применяется во вложенных функциях, когда надо прикрепить идентификатор за переменной или параметром окружающей внешней функции. Рассмотрим ситуацию, где это выражение может пригодиться:
Здесь вложенная локальная функция inner() выводит на консоль значение переменной n , которая определена во внешней функции outer(). Затем в функции outer() вызывается внутренняя функция inner().
При вызове функции outer() здесь мы ожидаемо увидим на консоли два раза число 5. Однако в данном случае вложенная функция inner() просто получает значение. Теперь возьмем другую ситуацию, когда вложенная функция присваивает значение переменной:
При присвоении значения во вложенной функции: n = 25 будет создаваться новая переменная n, которая скроет переменную n из окружающей внешней функции outer. В итоге мы получим при выводе два разных числа. Чтобы во вложенной функции указать, что идентификатор во вложенной функции будет представлять переменную из окружающей функции, применяется выражение nonlocal :
# Функции с параметрами
В программировании особе внимание уделяется концепции о локальных и глобальных переменных, а также связанное с ними представление об областях видимости. Соответственно, локальные переменные видны только в локальной области видимости, которой может выступать отдельно взятая функция. Глобальные переменные видны во всей программе. «Видны» – значит, известны, доступны. К ним можно обратиться по имени и получить связанное с ними значение.
К глобальной переменной можно обратиться из локальной области видимости. К локальной переменной нельзя обратиться из глобальной области видимости, потому что локальная переменная существует только в момент выполнения тела функции. При выходе из нее, локальные переменные исчезают. Компьютерная память, которая под них отводилась, освобождается. Когда функция будет снова вызвана, локальные переменные будут созданы заново.
Вернемся к нашей программе из прошлого урока, немного упростив ее для удобства:
Сколько здесь переменных? Какие из них являются глобальными, а какие – локальными?
Здесь пять переменных. Глобальной является только figure. Переменные a и b из функции rectangle() , а также a и h из triangle() – локальные. При этом локальные переменные с одним и тем же идентификатором a, но объявленные в разных функциях, – разные переменные.
Следует отметить, что идентификаторы rectangle и triangle , хотя и не являются именами переменных, а представляют собой имена функций, также имеют область видимости. В данном случае она глобальная, так как функции объявлены непосредственно в основной ветке программы.
В приведенной программе к глобальной области видимости относятся заголовки объявлений функций, объявление и присваивание переменной figure, конструкция условного оператора.
К локальной области относятся тела функций. Если, находясь в глобальной области видимости, мы попытаемся обратиться к локальной переменной, то возникнет ошибка. Добавьте в конце кода команду:
Однако мы можем обращаться из функций к глобальным переменным:
В данном случае из тел функций происходит обращение к имени figure, которое, из-за того, что было объявлено в глобальной области видимости, видимо во всей программе.
Наши функции не совсем идеальны. Они должны вычислять площади фигур, но выводить результат на экран им не следовало бы. Вполне вероятна ситуация, когда результат нужен для внутренних нужд программы, для каких-то дальнейших вычислений, а выводить ли его на экран – вопрос второстепенный.
Если функции не будут выводить, а только вычислять результат, то его надо где-то сохранить для дальнейшего использования. Для этого подошли бы глобальные переменные. В них можно записать результат. Напишем программу вот так:
Итак, мы ввели в программу глобальную переменную result и инициировали ее нулем. В функциях ей присваивается результат вычислений. В конце программы ее значение выводится на экран. Мы ожидаем, что программа будет прекрасно работать. Однакo:
… что-то пошло не так.
Дело в том, что в Python присвоение значения переменной совмещено с ее объявлением. (Во многих других языках это не так.) Поэтому, когда имя result впервые упоминается в локальной области видимости, и при этом происходит присваивание ей значения, то создается локальная переменная result . Это другая переменная, никак не связанная с глобальной result .
Когда функция завершает свою работу, то значение локальной result теряется, а глобальная не была изменена.
Когда мы вызывали внутри функции переменную figure, то ничего ей не присваивали. Наоборот, мы запрашивали ее значение. Интерпретатор Питона искал ее значение сначала в локальной области видимости и не находил. После этого шел в глобальную и находил.
В случае с result он ничего не ищет. Он выполняет вычисления справа от знака присваивания, создает локальную переменную result , связывает ее с полученным значением.
На самом деле можно принудительно обратиться к глобальной переменной. Для этого существует команда global :
В таком варианте программа будет работать правильно.
Однако менять значения глобальных переменных в теле функции – плохая практика. В больших программах программисту трудно отследить, где, какая функция и почему изменила их значение. Программист смотрит на исходное значение глобальной переменной и может подумать, что оно остается таким же. Сложно заметить, что какая-то функция поменяла его. Подобное ведет к логическим ошибкам.
Чтобы избавиться от необходимости использовать глобальные переменные, для функций существует возможность возврата результата своей работы в основную ветку программы. И уже это полученное из функции значение можно присвоить глобальной переменной в глобальной области видимости. Это делает программу более понятной.
Как функция принимает и возвращает данные, будет рассмотрено в следующих уроках.
# Упражнения
В языке Python можно внутри одной функции определять другую. Напишите программу по следующему описанию.
В основной ветке программы вызывается функция cylinder() , которая вычисляет площадь цилиндра. В теле cylinder() определена функция circle() , вычисляющая площадь круга по формуле πr2. В теле cylinder() у пользователя спрашивается, хочет ли он получить только площадь боковой поверхности цилиндра, которая вычисляется по формуле 2πrh, или полную площадь цилиндра. В последнем случае к площади боковой поверхности цилиндра должен добавляться удвоенный результат вычислений функции circle() .
Как вы думаете, можно ли из основной ветки программы вызвать функцию, вложенную в другую функцию? Почему?
# Возврат значений из функции. Оператор return
Функции могут передавать какие-либо данные из своих тел в основную ветку программы. Говорят, что функция возвращает значение. В большинстве языков программирования, в том числе Python, выход из функции и передача данных в то место, откуда она была вызвана, выполняется оператором return.
Если интерпретатор Питона, выполняя тело функции, встречает return, то он «забирает» значение, указанное после этой команды, и «уходит» из функции:
В данной программе в основную ветку из функции возвращается значение локальной переменной full . Не сама переменная, а ее значение, в данном случае – какое-либо число, полученное в результате вычисления площади цилиндра.
В основной ветке программы это значение присваивается глобальной переменной square. То есть выражение square = cylinder() выполняется так:
Вызывается функция cylinder() .
Из нее возвращается значение.
Это значение присваивается переменной square.
Не обязательно присваивать результат переменной, его можно сразу вывести на экран:
Здесь число, полученное из cylinder() , непосредственно передается функции print() . Если мы в программе просто напишем cylinder() , не присвоив полученные данные переменной или не передав их куда-либо дальше, то эти данные будут потеряны. Но синтаксической ошибки не будет.
В функции может быть несколько операторов return. Однако всегда выполняется только один из них. Тот, которого первым достигнет поток выполнения. Допустим, мы решили обработать исключение, возникающее на некорректный ввод. Пусть тогда в ветке except обработчика исключений происходит выход из функции без всяких вычислений и передачи значения:
Если попытаться вместо цифр ввести буквы, то сработает return, вложенный в except. Он завершит выполнение функции, так что все нижеследующие вычисления, в том числе return full, будут опущены. Пример выполнения:
Но постойте! Что это за слово None , которое нам вернул «пустой» return? Это ничего, такой объект – «ничто». Он принадлежит классу NoneType . До этого мы знали четыре типа данных, они же четыре класса: int , float , str , bool . Пришло время пятого.
Когда после return ничего не указывается, то по умолчанию считается, что там стоит объект None . Но никто вам не мешает явно написать return None .
Более того. Ранее мы рассматривали функции, которые вроде бы не возвращали никакого значения, потому что в них не было оператора return . На самом деле возвращали, просто мы не обращали на него внимание, не присваивали никакой переменной и не выводили на экран. В Python всякая функция что-либо возвращает. Если в ней нет оператора return , то она возвращает None. То же самое, как если в ней имеется «пустой» return .
# Возврат нескольких значений
В Питоне позволительно возвращать из функции несколько объектов, перечислив их через запятую после команды return :
Из функции cylinder() возвращаются два значения. Первое из них присваивается переменной sCyl, второе – fCyl. Возможность такого группового присвоения – особенность Python, обычно не характерная для других языков:
Фокус здесь в том, что перечисление значений через запятую (например, 10, 15, 19) создает объект типа tuple. На русский переводится как «кортеж». Это разновидность структур данных, которые будут изучены позже.
Когда же кортеж присваивается сразу нескольким переменным, то происходит сопоставление его элементов соответствующим в очереди переменным. Это называется распаковкой.
Таким образом, когда из функции возвращается несколько значений, на самом деле из нее возвращается один объект класса tuple. Перед возвратом эти несколько значений упаковываются в кортеж. Если же после оператора return стоит только одна переменная или объект, то ее/его тип сохраняется как есть.
Распаковка не является обязательной. Будет работать и так:
На экран выводится кортеж, о чем говорят круглые скобки. Его также можно присвоить одной переменной, а потом вывести ее значение на экран.
# Упражнения
Напишите программу, в которой вызывается функция, запрашивающая с ввода две строки и возвращающая в программу результат их конкатенации. Выведите результат на экран.
Напишите функцию, которая считывает с клавиатуры числа и перемножает их до тех пор, пока не будет введен 0. Функция должна возвращать полученное произведение. Вызовите функцию и выведите на экран результат ее работы.
# Параметры и аргументы функции
В программировании функции могут не только возвращать данные, но также принимать их, что реализуется с помощью так называемых параметров, которые указываются в скобках в заголовке функции. Количество параметров может быть любым.
Параметры представляют собой локальные переменные, которым присваиваются значения в момент вызова функции. Конкретные значения, которые передаются в функцию при ее вызове, будем называть аргументами. Следует иметь в виду, что встречается иная терминология. Например, формальные параметры и фактические параметры. В Python же обычно все называют аргументами.
Рассмотрим схему и поясняющий ее пример:
Когда функция вызывается, то ей передаются аргументы. В примере указаны глобальные переменные num1 и num2. Однако на самом деле передаются не эти переменные, а их значения. В данном случае числа 100 и 12. Другими словами, мы могли бы писать mathem(100, 12). Разницы не было бы.
Когда интерпретатор переходит к функции, чтобы начать ее исполнение, он присваивает переменным-параметрам переданные в функцию значения-аргументы. В примере переменной a будет присвоено 100, b будет присвоено 12.
Изменение значений a и b в теле функции никак не скажется на значениях переменных num1 и num2. Они останутся прежними. В Python такое поведение характерно для неизменяемых типов данных, к которым относятся, например, числа и строки. Говорят, что в функцию данные передаются по значению. Так, когда a присваивалось число 100, то это было уже другое число, не то, на которое ссылается переменная num1. Число 100 было скопировано и помещено в отдельную ячейку памяти для переменной a.
Существуют изменяемые типы данных. Для Питона, это, например, списки и словари. В этом случае данные передаются по ссылке. В функцию передается ссылка на них, а не сами данные. И эта ссылка связывается с локальной переменной. Изменения таких данных через локальную переменную обнаруживаются при обращении к ним через глобальную. Это есть следствие того, что несколько переменных ссылаются на одни и те же данные, на одну и ту же область памяти.
Необходимость передачи по ссылке связана в первую очередь с экономией памяти. Сложные типы данных, по сути представляющие собой структуры данных, обычно копировать не целесообразно. Однако, если надо, всегда можно сделать это принудительно.
# Произвольное количество аргументов
Обратим внимание еще на один момент. Количество аргументов и параметров совпадает. Нельзя передать три аргумента, если функция принимает только два. Нельзя передать один аргумент, если функция требует два обязательных. В рассмотренном примере они обязательные.
Однако в Python у функций бывают параметры, которым уже присвоено значение по-умолчанию. В таком случае, при вызове можно не передавать соответствующие этим параметрам аргументы. Хотя можно и передать. Тогда значение по умолчанию заменится на переданное:
При втором вызове cylinder() мы указываем только один аргумент. Он будет присвоен переменной-параметру h. Переменная r будет равна 1.
Согласно правилам синтаксиса Python при определении функции параметры, которым присваивается значение по-умолчанию должны следовать (находиться сзади) за параметрами, не имеющими значений по умолчанию.
А вот при вызове функции, можно явно указывать, какое значение соответствует какому параметру. В этом случае их порядок не играет роли:
… figure3 = cylinder(10, 2) figure4 = cylinder(r=2, h=10) print(figure3) print(figure4) В данном случае оба вызова – это вызовы с одними и теми же аргументами-значениями. Просто в первом случае сопоставление параметрам-переменным идет в порядке следования. Во-втором случае – по ключам, которыми выступают имена параметров.
В Python определения и вызовы функций имеют и другие нюансы, рассмотрение которых мы пока опустим, так как они требуют более глубоких знаний, чем у нас есть на данный момент. Скажем лишь, что функции может быть определена так, что в нее можно передать хоть ни одного аргумента, хоть множество:
Опять же, судя по скобкам, здесь возникает упомянутый в прошлом уроке кортеж.
# Упражнения
Напишите программу, которая:
- просит ввести число,
- проверяет возможность преобразовать введенные данные в число,
- преобразовывает значение в число и выводит число в консоль.
В программе должны быть определены следующие четыре функции:
- Функция get_input() не имеет параметров, запрашивает ввод с клавиатуры и возвращает в основную программу полученную строку.
- Функция test_input() имеет один параметр. В теле она проверяет, можно ли переданное ей значение преобразовать к целому числу. Если можно, возвращает логическое True . Если нельзя – False .
- Функция str_to_int() имеет один параметр. В теле преобразовывает переданное значение к целочисленному типу. Возвращает полученное число.
- Функция print_int() имеет один параметр. Она выводит переданное значение на экран и ничего не возвращает.
В основной ветке программы вызовите первую функцию. То, что она вернула, передайте во вторую функцию. Если вторая функция вернула True , то те же данные (из первой функции) передайте в третью функцию, а возвращенное третьей функцией значение – в четвертую.
Напишите преобразователь римских цифр (I, II, . L) в арабские (1, 2, . 50):
- в консоли просят ввести римское число;
- функция is_rim_number(num) принимает на вход число, проверяет является ли введенное значение римской цифрой и возвращает True — если является или False — если нет;
- функция rim_to_int(num) принимает на вход число, преобразует римскую цифру в целое число и возвращает полученное число.
- вывести ответ в консоль.
Напишите программу преобразования арабских целых чисел от 1 до 900 в римские.
Напишите программу преобразования римских цифр от 1 до 900 в арабские.
Напишите программу калькулятор для римских цифр, с операциями сложения и вычитания. Программа должна уметь работать с цифрами от I до L: