Что такое функция в python
Перейти к содержимому

Что такое функция в python

  • автор:

Function Introduction

Analytics Vidhya

A function is a group of related statements that performs a specific task in any language like C,C++,Python and Java. Functions break our program into smaller and modular chunks. As our program grows larger and larger, functions make it more organized, manageable and ready to use it again and again.

Syntax of Function in Python

function definition consists of the following components:

  • Keyword def marks the start of the function header in python.
  • A function name to uniquely identify the function.
  • Arguments through which we pass values to a function. They are optional.
  • A colon (:) to mark the end of the function header.
  • Docstring describe what the function does its optional but it always give clarity about function.
  • One or more valid python statements that make up the function body. Statements must have the same indentation level (usually 4 spaces) or tab.
  • An optional return statement to return a value from the function.
  • docstring can be print using function_name.__doc__ method.
  • The return statement is used to exit a function and go back to the place from where it was called. This statement can contain an expression that gets evaluated and the value is returned. If there is no expression in the statement or the return statement itself is not present inside a function, then the function will return the None object.

Example of a function

How to call a function in python?

Once we have defined a function, we can call it from another function, program or even the Python prompt. To call a function we simply type the function name with appropriate parameters.

Docstrings

The first string after the function header is called the docstring and is short for documentation string. It is briefly used to explain what a function does.it can be print using function_name.__doc__ method.

The return statement

The return statement is used to exit a function and go back to the place from where it was called.

Syntax of return

This statement can contain an expression that gets evaluated and the value is returned. If there is no expression in the statement or the return statement itself is not present inside a function, then the function will return the None object.

Scope and Lifetime of variables

Scope of a variable is the portion of a program where the variable is recognized. Parameters and variables defined inside a function are not visible from outside the function. Hence, they have a local scope.

The lifetime of a variable is the period throughout which the variable exits in the memory. The lifetime of variables inside a function is as long as the function executes.

They are destroyed once we return from the function. Hence, a function does not remember the value of a variable from its previous calls.

Here is an example to illustrate the scope of a variable inside a function.

output of the fuction:

Here, we can see that the value of x is 100 initially. Even though the function func() changed the value of x to 20 , it did not affect the value outside the function.

This is because the variable x inside the function is different (local to the function) from the one outside. Although they have the same names, they are two different variables with different scopes.

On the other hand, variables outside of the function are visible from inside. They have a global scope.

We can read these values from inside the function but cannot change (write) them. In order to modify the value of variables outside the function, they must be declared as global variables using the keyword global .

Types of Functions

Basically, we can divide functions into the following two types:

  • Build in functions — Functions that are built into Python.
  • User defined functions- Functions defined by the users themselves.

Arguments

In the user defined functions , we first define a function and calling it. Otherwise, the function call will result in an error. Here is an example.

Here, the function add () has two parameters. Since we have called this function with two arguments, it runs smoothly and we do not get any error. If we call it with a different number of arguments, the interpreter will show an error message. Below is a call to this function with one and no arguments along with their respective error messages.

Variable Function Arguments

In Python, there are other ways to define a function that can take variable number of arguments which are given below:

Python Default Arguments

Function arguments can have default values in Python.

We can provide a default value to an argument by using the assignment operator (=). Here is an example.

In this function, the parameter name does not have a default value and is required (mandatory) during a call. the parameter msg has a default value of "Good morning!" . So, it is optional during a call. If a value is provided, it will overwrite the default value. Any number of arguments in a function can have a default value. But once we have a default argument, all the arguments to its right must also have default values. This means to say, non-default arguments cannot follow default arguments. For example, if we had defined the function header above as:

Python Keyword Arguments

When we call a function with some values, these values get assigned to the arguments according to their position.

For example, in the above function greet() , when we called it as greet("sam", "How do you do?") , the value "sam" gets assigned to the argument name and similarly "How do you do?" to msg. Python allows functions to be called using keyword arguments. When we call functions in this way, the order (position) of the arguments can be changed. Following calls to the above function are all valid and produce the same result.

As we can see, we can mix positional arguments with keyword arguments during a function call. But we must keep in mind that keyword arguments must follow positional arguments. Having a positional argument after keyword arguments will result in errors. For example, the function call as follows:

Python Arbitrary Arguments

Sometimes, we do not know in advance the number of arguments that will be passed into a function. Python allows us to handle this kind of situation through function calls with an arbitrary number of arguments. In the function definition, we use an asterisk (*) before the parameter name to denote this kind of argument. Here is an example.

Keyword Arguments

Kwargs allows you to pass keyworded variable length of arguments to a function you should use **kwargs if you want to handle named arguments in a function.

Python Recursion

A function can call other functions and it is even possible for the functions to call itself. these type of constructions termed as recursion functions. example of recursive function is given below:

In the above example, factorial() is a recursive function as it calls itself. Each function multiplies the number with the factorial of the number below it until it is equal to one. This recursive call can be explained in the following steps.

Advantages of Recursion

  • Recursive functions make the code look clean and elegant.
  • A complex task can be broken down into simpler sub-problems using recursion.
  • Sequence generation is easier with recursion than using some nested iteration.

Disadvantages of Recursion

  • Sometimes the logic behind recursion is hard to follow through.
  • Recursive calls are expensive (inefficient) as they take up a lot of memory and time.
  • Recursive functions are hard to debug.

Lambda Functions

In Python, an anonymous function is a functions that is defined without a name. While normal functions are defined using the def keyword in Python, anonymous functions are defined using the lambda keyword. Hence, anonymous functions are also called lambda functions.

Syntax of Lambda Function in python

Lambda functions can have any number of arguments but only one expression. The expression is evaluated and returned. Lambda functions can be used wherever function objects are required.

Example of Lambda Function in python

suppose we want to find out square of a number then we can do that in following way using lambda function.

In the above program, lambda x: x ** 2 is the lambda function. Here x is the argument and x ** 2 is the expression that gets evaluated and returned.

Use of Lambda Function in python

We use lambda functions when we require a nameless function for a short period of time. In Python, we generally use it as an argument to a higher-order function (a function that takes in other functions as arguments). Lambda functions are used along with built-in functions like filter() , map() etc.

example with filter():

The filter() function in Python takes in a function and a list as arguments. The function is called with all the items in the list and a new list is returned which contains items for which the function evaluates to True . Here is an example use of filter() function to filter out only even numbers from a list.

example with map():

The map() function in Python takes in a function and a list. The function is called with all the items in the list and a new list is returned which contains items returned by that function for each item. Here is an example use of map() function to double all the items in a list.

example with reduce():

The reduce(fun,seq) function is used to apply a particular function passed in its argument to all of the list elements mentioned in the sequence passed along.This function is defined in “functools” module.

Python Global, Local and Nonlocal variables

Global Variables

In Python, a variable declared outside of the function or in global scope is known as a global variable. This means that a global variable can be accessed inside or outside of the function. Let’s see an example of how a global variable is created in Python.

Example 1: Create a Global Variable

What if you want to change the value of x inside a function?

The output shows an error because Python treats x as a local variable and x is also not defined inside double () .

Local Variables

A variable declared inside the function’s body or in the local scope is known as a local variable.

Example 2: Accessing local variable outside the scope

The output shows an error because we are trying to access a local variable y in a global scope whereas the local variable only works inside foo() or local scope.

Example 3: Create a Local Variable

Normally, we declare a variable inside the function to create a local variable.

Example 4: Using Global and Local variables in the same code

Example 5: Global variable and Local variable with same name

Nonlocal Variables

Nonlocal variables are used in nested functions whose local scope is not defined. This means that the variable can be neither in the local nor the global scope.

Let’s see an example of how a global variable is created in Python.

We use nonlocal keywords to create nonlocal variables.

Example 6: Create a nonlocal variable

In the above code, there is a nested inner() function. We use nonlocal keywords to create a nonlocal variable. The inner() function is defined in the scope of another function outer() .

Note : If we change the value of a nonlocal variable, the changes appear in the local variable.

Global Keyword

In Python, global keyword allows you to modify the variable outside of the current scope. It is used to create a global variable and make changes to the variable in a local context.

Функции в Python

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

(от англ. function) – это блок программного кода на языке Python , который определяется один раз и далее может быть использован многократно.

Каждая хорошо спроектированная функция по сути решает какую-то одну конкретную задачу, что дает возможность программистам разбивать сложную систему на достаточно простые и легко управляемые части. При этом достаточно всего лишь один раз определить функцию и далее ее можно будет использовать практически в любом месте программы, зачастую заменяя довольно объемные избыточные копии блоков одного и того же программного кода вызовами созданной ранее функции. Как следствие, при необходимости внесения изменений в код, делать это придется уже не во многих местах программы, а только в одном – в теле самой функции (см. пример №1 ).

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

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

Создание и вызов функций

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

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

Помимо обычных инструкций в любом месте тела функции может содержаться необязательная инструкция return , которая предназначена для выхода из функции и возврата результата вызывающей программе в месте вызова функции. В случае отсутствия инструкции return функция будет завершать свою работу по достижении потоком управления конца тела функции. Однако технически функция все равно будет неявно возвращать результат в виде объекта None , который обычно просто игнорируется.

Также для использования в функциях предназначена специальная инструкция yield, которая превращает обычную функцию в функцию-генератор. Однако здесь мы заострять внимание на ней не будем, поскольку данный вопрос был подробно рассмотрен нами в предыдущем параграфе.

После того, как функция будет определена, ее можно начинать использовать, многократно вызывая практически в любое время и в любом месте скрипта. Осуществляются такие вызовы при помощи имени функции и круглых скобок с передаваемыми в функцию значениями аргументов, которые также должны перечисляться через запятую (см. пример №1 ).

Пример №1. Создание и вызов функций в Python (часть 1).

Следует иметь в виду, что в отличие от некоторых других языков программирования в Python функции становятся доступными для использования только после того, как до них дойдет поток выполнения программы. Если попытаться вызвать функцию до ее определения в коде программы, интерпретатор возбудит исключение. При этом создавать функции можно практически везде, где могут появляться инструкции, включая условные инструкции и определения других функций (см. пример №2 ).

Пример №2. Создание и вызов функций в Python (часть 2).

Аргументы функций

Как было сказано выше, в случаях, когда функция определяется с аргументами, их имена перечисляются через запятую в круглых скобках после имени определяемой функции. Далее, в моменты вызовов функции, все определенные имена автоматически становятся ее локальными переменными, которым присваиваются переданные в функцию значения. При этом по умолчанию сопоставление аргументов производится слева направо в соответствии с их позициями, а самих аргументов допускается передавать ровно столько, сколько имен было указано в заголовке функции при ее определении (см. пример №3 ).

Пример №3. Передача аргументов функциям (часть 1).

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

  • def func(arg_1, arg_2, . ): – рассмотренный нами стандартный случай определения функции. Во время вызова такая функция ожидает получить строго определенное количество аргументов, сопоставление которых будет происходить либо по их позициям, либо по именам. При этом в случае использования в вызове функции именованных аргументов их разрешается указывать в любом порядке, но только после того, как будут переданы все имеющиеся позиционные аргументы, которые в любом случае будут сопоставляться как и положено, т.е. слева направо в соответствии с их позициями (см. пример №4 ).

Пример №4. Стандартная передача аргументов функциям.

  • def func(arg_1, arg_2, . arg_1=val_1, arg_2=val_2, . ) – эта форма записи используется для определения функций, у которых предусмотрены аргументы со значениями по умолчанию. Перечисляются такие аргументы после обычных позиционных аргументов (если они имеются), а их наличие позволяет вызывать функцию без передачи им значений, т.к. в таком случае будут просто использованы значения по умолчанию. Во всем остальном для таких функций справедливы правила стандартного режима передачи аргументов (см. пример №5 ).

Пример №5. Передача аргументов со значениями по умолчанию.

  • def func(arg_1, . arg_n, *args) – при вызовах функции, определенной таким способом, все дополнительные аргументы будут объединяться в кортеж с именем args . Если передаваемых аргументов будет меньше n , будет вызвана ошибка. Сама запись *args должна идти после перечисления всех позиционных аргументов, включая и позиционные аргументы со значениями по умолчанию (см. пример №6 ).

Пример №6. Сбор аргументов функции в кортеж.

  • def func(arg_1, . arg_n, *args, name_arg_1, . name_arg_m) – здесь также все дополнительные аргументы будут объединяться в кортеж с именем args , но при этом все аргументы name_arg_1, . name_arg_m должны будут передаваться функции только именованными. Если собирать аргументы в кортеж не требуется, но функция проектируется для именованных аргументов, разрешается использовать синтаксис def func(arg_1, . arg_n, *, name_arg_1, . name_arg_m) , где все аргументы после звездочки, опять же, должны будут передаваться функции только именованными (см. пример №7 ).

Пример №7. Определение функции с именованными аргументами.

  • def func(arg_1, . arg_n, *args, name_arg_1, . name_arg_m, **name_args) – это наиболее общая форма определения функции с позиционными и именованными аргументами: при вызовах такой функции все дополнительные позиционные аргументы будут объединяться в кортеж с именем args , а все дополнительные именованные аргументы будут объединяться в словарь с именем name_args (см. пример №8 ).

Пример №8. Сбор именованных аргументов в словарь.

Следует помнить, что форма записи arg=val в определении функции означает, что данный аргумент определяется со значением по умолчанию, а в вызове функции запись представляет собой передачу аргумента по имени. Кроме того, формы записей *args и **name_args также имеют разный смысл для определения и вызова функции: в первом случае они собирают аргументы в кортеж и словарь, а во втором случае указывают интерпретатору на необходимость распаковки последовательностей в отдельные аргументы и пары (см. пример №9 ).

Пример №9. Передача аргументов функциям (часть 2).

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

  • в заголовке определяемой функции аргументы должны указываться в следующем порядке: позиционные аргументы ( arg_1, arg_2, . ), позиционные аргументы со значениями по умолчанию ( arg_1=val_1, arg_2=val_2, . ), аргумент со звездочкой для сбора дополнительных позиционных аргументов в кортеж ( *args ), именованные аргументы ( name_arg_1, name_arg_2, . ), именованные аргументы со значениями по умолчанию ( name_arg_1=val_1, name_arg_2=val_2, . ) и аргумент с двумя звездочками для сбора дополнительных именованных аргументов в словарь ( **name_args );
  • при вызове функции порядок передачи аргументов должен быть следующим: обычные позиционные аргументы ( arg_1, arg_2, . ), позиционные аргументы в форме *args (будут распакованы интерпретатором в значения arg_1, arg_2, . ), обычные именованные аргументы ( name_arg_1=val_1, name_arg_2=val_2, . ) и в самом конце именованные аргументы в форме **name_args (будут распакованы интерпретатором в пары name_arg_1=val_1, name_arg_2=val_2, . ).

Области видимости в Python

Как мы знаем, все имена в Python становятся доступны для использования только после того, как им будет присвоено какое-нибудь значение. Так вот, место, где переменной присваивается значение, как раз и определяет область ее видимости. Но поскольку значения переменным могут быть присвоены в трех разных местах текущего модуля, то и областей видимости выделяют тоже три.

  • Если присваивание переменной выполняется внутри инструкции def , переменная становится локальной для этой функции. Это касается как аргументов функции, так и переменных, созданных в теле функции. доступны только внутри своей функции, т.е. в текущей локальной области видимости, и недоступны за ее пределами, включая другие локальные области видимости невложенных в нее функций.
  • Если присваивание производится в пределах объемлющей инструкции def , переменная становится локальной для данной объемлющей функции и нелокальной для данной вложенной функции. В общем случае такая переменная будет доступна внутри любой вложенной функции при отсутствии в ней локальной переменной с таким же именем.
  • Если присваивание производится на верхнем уровне модуля (файла скрипта) за пределами всех инструкций def , переменная становится глобальной для всего файла. В общем случае будет доступна внутри любой функции текущего модуля при отсутствии в ней локальной переменной с таким же именем (см. пример №10 ).

Пример №10. Области видимости в Python (часть 1).

Как видим, глобальная переменная glob_var доступна и в объемлющей функции, и во вложенной. Точно также локальная для функции func_1 переменная loc_var доступна в локальной области вложенной функции func_2 (для нее она является нелокальной переменной). Но если мы попробуем использовать локальные переменные в объемлющей или глобальной области видимости, то наверняка получим ошибку, т.к. локальные переменные доступны только в своей области видимости (см. пример №11 ).

Пример №11. Области видимости в Python (часть 2).

Наличие обособленных локальных областей видимости и приоритет в них локальных переменных над глобальными и нелокальными переменными с теми же именами позволяет избежать неоднозначности и конфликта имен. Этому содействует и невозможность использования для функций из одного и того же пространства имен локальных переменных одной функции в области видимости другой (см. пример №12 ).

Пример №12. Области видимости в Python (часть 3).

Для случаев, когда возникает необходимость использования внутри функций именно глобальных или нелокальных переменных вместо локальных с теми же именами, в Python предусмотрены инструкции и . Все что нужно – это просто перечислить после ключевых слов требуемые имена через запятую (см. пример №13 ).

Пример №13. Использование инструкций global и nonlocal.

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

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

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

  • globals() – возвращает словарь со значениями переменных из текущей глобальной области видимости модуля, в котором ключами служат имена этих переменных. Стоит заметить, что функция возвращает такой словарь даже в тех случаях, когда она вызывается из локальных областей видимости функций и методов (см. пример №14 ).
  • locals() – обновляет и возвращает словарь со значениями переменных, использующихся в текущей локальной области видимости функции или метода, в котором ключами служат имена этих переменных. Следует иметь в виду, что значения этого словаря изменять не стоит, т.к. изменённые значения все равно могут быть проигнорированы интерпретатором. Кроме того, при использовании этой функции в глобальной области видимости модуля она вернет словарь с глобальными переменными также, как и функция globals() .

Пример №14. Использование функций globals() и locals().

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

lambda-выражения или анонимные функции

Поскольку в Python инструкции не могут использоваться внутри выражений, для этих целей в язык была введена дополнительная возможность в виде специальных конструкций, называемых -выражениями и позволяющих создавать объекты функций там, где интерпретатор ожидает встретить выражение. Эти конструкции еще называют , т.к. в отличие от инструкций def они хоть и создают функции, но не связывают их с именами.

Здесь стоит заметить, что после двоеточия записывается именно выражение, а не блок инструкций. По сути такое выражение сродни тому, что мы помещаем в инструкцию return при определении обычной функции. Это конечно же делает lambda -выражения менее универсальными по сравнению с инструкциями def , но такая реализация предусмотрена намеренно, т.к. lambda -выражения предназначены для создания простых функций, которые бы не усложняли выражения, в то время как инструкции def представляют собой инструменты для решения более сложных задач (см. пример №14 ).

Пример №14. Использование lambda-выражений (часть 1).

Как видим, lambda -выражения действительно очень похожи на обыкновенные функции: в них также действуют специальные режимы сопоставления аргументов, имеется тело с кодом, а на выходе получается объект функции. Однако, повторимся, в теле lambda -выражений может находиться только одно единственное выражение, в то время как использование даже простейших инструкций вообще запрещено. Кроме того, возвращаемый объект функции нужно либо сразу вызывать при помощи круглых скобок, либо присваивать переменной явно. Зато lambda -выражения можно смело использовать внутри других выражений (см. пример №15 ).

Пример №15. Использование lambda-выражений (часть 2).

В нашем примере вложенное lambda -выражение, как и положено вложенным функциям, имеет доступ к переменной x в объемлющем lambda -выражении. Но выглядит код явно замысловато! Поэтому в интересах удобочитаемости кода лучше такие трюки не использовать.

Рекурсивные функции

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

Рекурсивные функции являются вполне обычными функциями со всеми присущими им особенностями. Разница лишь в том, что внутри тела такие функции содержат вызов самой себя. Звучит это как-то странно и непонятно, в особенности для начинающих программистов, поэтому стоит сразу же обратиться к практике. В качестве примера, давайте рассмотрим использование рекурсивной функции в ходе решения классической задачи нахождения факториала числа (см. пример №16 ).

Пример №16. Рекурсивные функции в Python.

В нашем примере код рекурсивной функции содержит условную инструкцию if , которая останавливает рекурсии (вызовы самой себя) только в том случае, когда значение переданного ей аргумента будет равно единице. Если же при текущем вызове функции значение аргумента будет больше единицы, в блоке else условной инструкции if будет предпринята попытка вычисления выражения n*recursive_func(n-1) , использующее вызов функцией самой себя. При этом прежде, чем вернуть конечный результат в точку вызова функции в программе, наша рекурсивная функция будет вызывать себя саму до тех пор, пока в выражении для возврата не останется ее незавершенных вызовов. Например, для n=4 , наш факториал схематически будет формироваться следующим образом: return 4*recursive_func(4-1) -> return 4*(return 3*recursive_func(3-1)) -> return 4*(return 3*(return 2*recursive_func(2-1))) -> return 4*(return 3*(return 2*(return 1))) -> return 4*(return 3*(return 2*1)) -> return 4*(return 3*2*1) -> return 4*3*2*1 .

Следует заметить, что в языке Python рекурсии используются не так часто, как в некоторых других языках программирования, поскольку в Python особое значение придается простым процедурным инструкциям вроде цикла while , который более естественно подходит для решения аналогичных задач. Тем не менее рекурсии могут быть весьма полезными для реализации обхода сложных структур с произвольной организацией данных, поэтому взять их на вооружение однозначно стоит.

Декораторы функций

(от англ. decorator) – это функция, которая используется в качестве «обертки» другой функции с целью изменения ее поведения или расширения функциональности без непосредственного изменения кода самой функции.

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

В качестве примера давайте создадим собственный простейший декоратор и на его основе познакомимся с этим понятием поближе (см. пример №17 ).

Пример №17. Декораторы функций (часть 1).

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

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

Поскольку в Python декораторы используются довольно часто, для упрощения процедуры получения декорированных объектов используется специальный синтаксис, предусматривающий использование имени декоратора с префиксом в виде символа @ непосредственно перед строкой, содержащей заголовок определения декорируемой функции или метода (см. пример №18 ).

Пример №18. Декораторы функций (часть 2).

Благодаря наличию такого синтаксиса нам не пришлось использовать в примере более длинную инструкцию my_func = decorator_func(my_func) , что сделало код более коротким и читабельным.

Атрибуты функций, аннотации и документирование

Поскольку функции в Python являются обычными объектами, мы можем без каких-либо сложностей получать базовый доступ к предопределенным атрибутам функций, а также добавлять, изменять или удалять собственные атрибуты (см. пример №19 ).

Пример №19. Атрибуты функций в Python.

Как видим, для получения списка всех предопределенных атрибутов функции нужно просто воспользоваться встроенной функцией dir . Если же необходим доступ к конкретному атрибуту, следует указать его имя в формате func.attr , где func – имя функции, а attr – имя атрибута. Что касается пользовательских атрибутов, то они создаются и изменяются простым присваиванием требуемого значения имени атрибута, который также записывается после имени функции через точку в формате func.attr . Собственные атрибуты позволяют эффективно и просто хранить информацию о состоянии непосредственно в объекте функции, отказавшись от использования других приемов, таких как применение глобальных или нелокальных переменных и классов. Огромным плюсом при этом является то, что в отличие от нелокальных переменных, атрибуты функции доступны в любом месте программы, где доступна сама функция. Так что в некотором смысле их можно рассматривать, как имитацию статических локальных переменных, имеющихся в некоторых других языках программирования, т.к. они тоже сохраняют свои значения между вызовами функции.

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

Пример №20. Аннотации и документирование функций в Python.

Как видно из примера, синтаксически аннотации функции находятся в заголовке инструкции def в виде произвольных выражений, которые ассоциируются с ее аргументами и возвращаемым значением. Для аргументов аннотации указываются через двоеточие сразу после имени аргумента, а для возвращаемого значения – после пары символов -> вслед за списком аргументов. Все аннотации, если конечно они присутствуют в объявлении функции, интерпретатор собирает в словарь, который затем присоединяет к объекту созданной функции. Имена аргументов в этом словаре становятся ключами, а сами аннотации их значениями. При этом для возвращаемого значения аннотация сохраняется под ключом return .

Cтоит обратить внимание на еще один важный момент: в аннотированных аргументах, которые используют значения по умолчанию, аннотация записывается перед значением по умолчанию в формате def func(arg_1: annot_1 = val_1, arg_2: annot_2 = val_2, . ) -> return_annot: .

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

Концепции проектирования функций

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

  • Каждая хорошо спроектированная функция должна иметь одно единственное назначение и решать только одну простую задачу. Например, если функция позволяет одновременно перемножать и складывать числа, то наверняка стоит подумать над тем, чтобы разбить ее на две отдельные и более простые функции.
  • Каждая функция должна иметь относительно небольшой размер. Если ваша функция начинает занимать несколько экранов – это явный признак того, что было бы неплохо разбить ее на несколько более простых частей. Функции с большой глубиной вложенности часто свидетельствует о промахах в проектировании, тем более в языке Python , которому присущи краткость и лаконичность.
  • Используйте для передачи значений функции аргументы, а для возврата результатов – инструкцию return . Функция должна быть максимально независимой от того, что происходит за ее пределами.
  • Старайтесь использовать глобальные переменные внутри тела функции только в том случае, когда это действительно необходимо. Это поможет избежать зависимости от внешних факторов и проблем с согласованностью компонентов программ, что, как следствие, существенно облегчит их отладку в дальнейшем.
  • Следите за тем, чтобы ваши функции не воздействовали на изменяемые аргументы, если вызывающая программа не предполагает этого. Ведь получая в качестве аргументов, например, списки или словари, функции могут оказывать воздействие на части этих изменяемых типов данных. В результате такие функции, опять же, становятся слишком тесно связаны и зависимы от внешней среды, что может сделать их уж слишком специфичными и неустойчивыми.
  • Избегайте непосредственного изменения переменных вашими функциями в других модулях программы. Используйте для этих целей отдельные функции доступа, сведя прямую зависимость к минимуму, как и в случае с глобальными переменными.

Краткие итоги параграфа

  • Функция в программировании – это блок программного кода на этом языке, который определяется один раз и далее может быть использован многократно.
  • Функции позволяют существенно уменьшить время и трудозатраты на разработку приложений, а также их дальнейшее сопровождение за счет следующих преимуществ: дают возможность разбить сложную систему на небольшие и легко управляемые части, каждая из которых может разрабатываться отдельно, обеспечивают многократное использование программного кода, уменьшают его избыточность, повышают читабельность исходного кода, упрощают его редактирование.
  • Для создания функций в Python предназначена инструкция , которая создает объект функции и связывает его с именем. В общем виде инструкция имеет следующий формат: Примером определения функции может служить инструкция def f(a, b): return a + b .
  • Инструкция return не является обязательной. При ее отсутствии функция будет завершать свою работу по достижении потоком управления конца тела функции. При этом технически она все равно будет неявно возвращать результат в виде объекта None , однако он обычно просто игнорируется.
  • Осуществляются вызовы функций только после их определения при помощи имени функции и круглых скобок с передаваемыми функции значениями аргументов, которые, если их несколько, должны перечисляться через запятую. Например, для определенной выше функции вызов может иметь вид x = f(43, 85) .
  • В Python имеется целый ряд специальных режимов сопоставления аргументов, при использовании которых следует придерживаться следующих правил:
    • в заголовке определяемой функции аргументы должны указываться в следующем порядке: позиционные аргументы ( arg_1, arg_2, . ), позиционные аргументы со значениями по умолчанию ( arg_1=val_1, arg_2=val_2, . ), аргумент со звездочкой для сбора дополнительных позиционных аргументов в кортеж ( *args ), именованные аргументы ( name_arg_1, name_arg_2, . ), именованные аргументы со значениями по умолчанию ( name_arg_1=val_1, name_arg_2=val_2, . ) и аргумент с двумя звездочками для сбора дополнительных именованных аргументов в словарь ( **name_args );
    • при вызове функции порядок передачи аргументов должен быть следующим: обычные позиционные аргументы ( arg_1, arg_2, . ), позиционные аргументы в форме *args (будут распакованы интерпретатором в значения arg_1, arg_2, . ), обычные именованные аргументы ( name_arg_1=val_1, name_arg_2=val_2, . ) и в самом конце именованные аргументы в форме **name_args (будут распакованы интерпретатором в пары name_arg_1=val_1, name_arg_2=val_2, . ).
    • Если присваивание переменной выполняется внутри инструкции def , переменная становится локальной для этой функции. Это касается как аргументов функции, так и переменных, созданных в теле функции. Локальные переменные доступны только внутри своей функции, т.е. в текущей локальной области видимости, и недоступны за ее пределами, включая другие локальные области видимости невложенных в нее функций.
    • Если присваивание производится в пределах объемлющей инструкции def , переменная становится локальной для данной объемлющей функции и нелокальной для данной вложенной функции. В общем случае такая переменная будет доступна внутри любой вложенной функции при отсутствии в ней локальной переменной с таким же именем.
    • Если присваивание производится на верхнем уровне модуля (файла скрипта) за пределами всех инструкций def , переменная становится глобальной для всего файла. В общем случае глобальная переменная будет доступна внутри любой функции текущего модуля при отсутствии в ней локальной переменной с таким же именем.

    Вопросы и задания для самоконтроля

    1. Дайте определение функции в программировании. Перечислите основные преимущества использования функций. Показать решение.

    Ответ. Функция в программировании – это блок программного кода на этом языке, который определяется один раз и далее может быть использован многократно.

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

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

    2. В какой момент времени интерпретатор Python создает функции? Разрешается ли вызывать функции до момента их определения? Показать решение.

    Ответ. Функция создается, когда поток выполнения программы достигает инструкции def и выполняет ее. Эта инструкция создает объект функции и связывает его с именем функции. С этого момента функция становится доступной для вызовов: для этого нужно к имени функции добавить круглые скобки со значениями аргументов внутри. Вызывать функцию до момента ее определения в Python запрещается. Стоит заметить, что в некоторых других языках программирования такое возможно за счет того, что определения функций поднимаются вверх скриптов. Но в Python вызывать функцию до момента ее определения запрещается!

    3. Когда выполняется непосредственно сам программный код, вложенный в тело функции? Показать решение.

    Ответ. Тело функции выполняется каждый раз при вызове уже определенной функции.

    4. Что возвращает функция, в которой отсутствует инструкция return ? Показать решение.

    Ответ. Инструкция return не является обязательной. При ее отсутствии функция будет завершать свою работу по достижении потоком управления конца тела функции. При этом технически она все равно будет неявно возвращать результат в виде объекта None , однако он обычно просто игнорируется.

    5. Какой из представленных вариантов определения функции не содержит ошибок: dfn f(x, y): return x*y , def f(x, y): return x*y или def f: return x*y . Показать решение.

    Ответ. def f(x, y): return x*y

    6. Каковы будут результаты вызовов функций в коде условия? Объясните свои ответы, а затем запустите скрипт и проверьте себя. Показать решение.

    Функции¶

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

    Именные функции, инструкция def¶

    Функция в Python — объект, принимающий аргументы и возвращающий значение. Обычно функция определяется с помощью инструкции def .

    Определим простейшую функцию:

    Инструкция return говорит, что нужно вернуть значение. В нашем случае функция возвращает сумму x и y .

    Теперь мы ее можем вызвать:

    Функция может быть любой сложности и возвращать любые объекты (списки, кортежи, и даже функции!):

    Функция может и не заканчиваться инструкцией return , при этом функция вернет значение None :

    Аргументы функции¶

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

    Функция также может принимать переменное количество позиционных аргументов, тогда перед именем ставится * :

    Как видно из примера, args — это кортеж из всех переданных аргументов функции, и с переменной можно работать также, как и с кортежем.

    Функция может принимать и произвольное число именованных аргументов, тогда перед именем ставится ** :

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

    Анонимные функции, инструкция lambda¶

    Анонимные функции могут содержать лишь одно выражение, но и выполняются они быстрее. Анонимные функции создаются с помощью инструкции lambda . Кроме этого, их не обязательно присваивать переменной, как делали мы инструкцией def func() :

    lambda-функции, в отличие от обычной, не требуется инструкция return , а в остальном, ведет себя точно так же:

    Встроенные функции, выполняющие преобразование типов¶

    Другие встроенные функции¶

    property(fget=None, fset=None, fdel=None, doc=None)

    round(X [, N]) Округление до N знаков после запятой. setattr(объект, имя, значение) Устанавливает атрибут объекта. sorted(iterable[, key][, reverse]) Отсортированный список. staticmethod(function) Статический метод для функции. sum(iter, start=0) Сумма членов последовательности. super([тип [, объект или тип]]) Доступ к родительскому классу. type(object) Возвращает тип объекта. type(name, bases, dict) Возвращает новый экземпляр класса name . vars([object]) Словарь из атрибутов объекта. По умолчанию — словарь локальных имен. zip(*iters) Итератор, возвращающий кортежи, состоящие из соответствующих элементов аргументов-последовательностей.

    3. Функции языка Python¶

    Функции – это многократно используемые фрагменты программы. Они позволяют дать имя определённому блоку команд с тем, чтобы впоследствии запускать этот блок по указанному имени в любом месте программы и сколь угодно много раз. Это называется вызовом функции. Мы уже использовали много встроенных функций, как то len и range.

    Функция – это, пожалуй, наиболее важный строительный блок любой нетривиальной программы (на любом языке программирования), поэтому в этой главе мы рассмотрим различные аспекты функций.

    Функции определяются при помощи зарезервированного слова def. После этого слова указывается имя функции, за которым следует пара скобок, в которых можно указать имена некоторых переменных, и заключительное двоеточие в конце строки. Далее следует блок команд, составляющих функцию. На примере можно видеть, что на самом деле это очень просто:

    3.1. Параметры функций¶

    Функции могут принимать параметры, т.е. некоторые значения, передаваемые функции для того, чтобы она что-либо сделала с ними. Эти параметры похожи на переменные, за исключением того, что значение этих переменных указывается при вызове функции, и во время работы функции им уже присвоены их значения.

    Параметры указываются в скобках при объявлении функции и разделяются запятыми. Аналогично мы передаём значения, когда вызываем функцию. Обратите внимание на терминологию: имена, указанные в объявлении функции, называются параметрами, тогда как значения, которые вы передаёте в функцию при её вызове, – аргументами.

    3.2. Локальные переменные¶

    При объявлении переменных внутри определения функции, они никоим образом не связаны с другими переменными с таким же именем за пределами функции – т.е. имена переменных являются локальными в функции. Это называется областью видимости переменной. Область видимости всех переменных ограничена блоком, в котором они объявлены, начиная с точки объявления имени.

    3.3. Зарезервированное слово “global”¶

    Чтобы присвоить некоторое значение переменной, определённой на высшем уровне программы (т.е. не в какой-либо области видимости, как то функции или классы), необходимо указать Python, что её имя не локально, а глобально (global). Сделаем это при помощи зарезервированного слова global. Без применения зарезервированного слова global невозможно присвоить значение переменной, определённой за пределами функции.

    Можно использовать уже существующие значения переменных, определённых за пределами функции (при условии, что внутри функции не было объявлено переменной с таким же именем). Однако, это не приветствуется, и его следует избегать, поскольку человеку, читающему текст программы, будет непонятно, где находится объявление переменной. Использование зарезервированного слова global достаточно ясно показывает, что переменная объявлена в самом внешнем блоке.

    3.4. Зарезервированное слово “nonlocal”¶

    Мы увидели, как получать доступ к переменным в локальной и глобальной области видимости. Есть ещё один тип области видимости, называемый “нелокальной” (nonlocal) областью видимости, который представляет собой нечто среднее между первыми двумя. Нелокальные области видимости встречаются, когда вы определяете функции внутри функций.

    Поскольку в Python всё является выполнимым кодом, вы можете определять функции где угодно.

    3.5. Значения аргументов по умолчанию¶

    Зачастую часть параметров функций могут быть необязательными, и для них будут использоваться некоторые заданные значения по умолчанию, если пользователь не укажет собственных. Этого можно достичь с помощью значений аргументов по умолчанию. Их можно указать, добавив к имени параметра в определении функции оператор присваивания (=) с последующим значением.

    Обратите внимание, что значение по умолчанию должно быть константой. Или точнее говоря, оно должно быть неизменным[1] – это объясняется подробнее в последующих главах. А пока запомните это.

    Важно Значениями по умолчанию могут быть снабжены только параметры, находящиеся в конце списка параметров. Таким образом, в списке параметров функции параметр со значением по умолчанию не может предшествовать параметру без значения по умолчанию. Это связано с тем, что значения присваиваются параметрам в соответствии с их положением. Например, def func(a, b=5) допустимо, а def func(a=5, b) – не допустимо.

    3.6. Ключевые аргументы¶

    Если имеется некоторая функция с большим числом параметров, и при её вызове требуется указать только некоторые из них, значения этих параметров могут задаваться по их имени – это называется ключевые параметры. В этом случае для передачи аргументов функции используется имя (ключ) вместо позиции (как было до сих пор).

    Есть два преимущества такого подхода: во-первых, использование функции становится легче, поскольку нет необходимости отслеживать порядок аргументов; во-вторых, можно задавать значения только некоторым избранным аргументам, при условии, что остальные параметры имеют значения аргумента по умолчанию.

    3.7. Переменное число параметров¶

    Иногда бывает нужно определить функцию, способную принимать любое число параметров. Этого можно достичь при помощи звёздочек (сохраните как function_varargs.py):

    3.8. Только ключевые параметры¶

    Если некоторые ключевые параметры должны быть доступны только по ключу, а не как позиционные аргументы, их можно объявить после параметра со звёздочкой (сохраните как keyword_only.py):

    3.9. Оператор “return”¶

    Оператор return используется для возврата[5] из функции, т.е. для прекращения её работы и выхода из неё. При этом можно также вернуть некоторое значение из функции.

    3.10. Строки документации¶

    Python имеет остроумную особенность, называемую строками документации, обычно обозначаемую сокращённо docstrings. Это очень важный инструмент, которым вы обязательно должны пользоваться, поскольку он помогает лучше документировать программу и облегчает её понимание. Поразительно, но строку документации можно получить, например, из функции, даже во время выполнения программы!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *