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

Создание функции:

  • функции создаются с помощью зарезервированного слова def

  • за def следуют имя функции и круглые скобки

  • внутри скобок могут указываться параметры, которые функция принимает

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

  • первой строкой, опционально, может быть комментарий, так называемая docstring

  • в функциях может использоваться оператор return

    • он используется для прекращения работы функции и выхода из нее

    • чаще всего, оператор return возвращает какое-то значение

https://raw.githubusercontent.com/natenka/pyneng-book/master/images/09_function_basics.png https://raw.githubusercontent.com/natenka/pyneng-book/master/images/09_function_basics_dark.png

Пример функции:

def configure_intf(intf_name, ip, mask):
    print('interface', intf_name)
    print('ip address', ip, mask)

Функция configure_intf создает конфигурацию интерфейса с указанным именем и IP-адресом. У функции есть три параметра: intf_name, ip, mask. При вызове функции в эти параметры попадут реальные данные.

Примечание

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

Вызов функции#

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

Примечание

Параметры - это переменные, которые используются при создании функции. Аргументы - это фактические значения (данные), которые передаются функции при вызове.

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

In [2]: configure_intf('F0/0', '10.1.1.1', '255.255.255.0')
interface F0/0
ip address 10.1.1.1 255.255.255.0

In [3]: configure_intf('Fa0/1', '94.150.197.1', '255.255.255.248')
interface Fa0/1
ip address 94.150.197.1 255.255.255.248

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

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

In [4]: items = [40, 2, 0, 22]

In [5]: sorted(items)
Out[5]: [0, 2, 22, 40]

In [6]: sorted_items = sorted(items)

In [7]: sorted_items
Out[7]: [0, 2, 22, 40]

Примечание

Обратите внимание на строку Out[5] в ipython: таким образом ipython показывает, что функция/метод что-то возвращает и показывает, что именно возвращает.

Если же попытаться записать в переменную результат функции configure_intf, в переменной окажется значение None:

In [8]: result = configure_intf('Fa0/0', '10.1.1.1', '255.255.255.0')
interface Fa0/0
ip address 10.1.1.1 255.255.255.0

In [9]: print(result)
None

Чтобы функция могла возвращать какое-то значение, надо использовать оператор return.

Оператор return#

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

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

In [10]: def configure_intf(intf_name, ip, mask):
    ...:     config = f'interface {intf_name}\nip address {ip} {mask}'
    ...:     return config
    ...:

In [11]: result = configure_intf('Fa0/0', '10.1.1.1', '255.255.255.0')

In [12]: print(result)
interface Fa0/0
ip address 10.1.1.1 255.255.255.0

In [13]: result
Out[13]: 'interface Fa0/0\nip address 10.1.1.1 255.255.255.0'

Теперь в переменой result находится строка с командами для настройки интерфейса.

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

Ещё один важный аспект работы оператора return: после return, функция завершает работу, а значит выражения, которые идут после return, не выполняются.

Например, в функции ниже, строка «Конфигурация готова» не будет выводиться, так как она стоит после return:

In [14]: def configure_intf(intf_name, ip, mask):
    ...:     config = f'interface {intf_name}\nip address {ip} {mask}'
    ...:     return config
    ...:     print('Конфигурация готова')
    ...:

In [15]: configure_intf('Fa0/0', '10.1.1.1', '255.255.255.0')
Out[15]: 'interface Fa0/0\nip address 10.1.1.1 255.255.255.0'

Функция может возвращать несколько значений. В этом случае, они пишутся через запятую после оператора return. При этом фактически функция возвращает кортеж:

In [16]: def configure_intf(intf_name, ip, mask):
    ...:     config_intf = f'interface {intf_name}\n'
    ...:     config_ip = f'ip address {ip} {mask}'
    ...:     return config_intf, config_ip
    ...:

In [17]: result = configure_intf('Fa0/0', '10.1.1.1', '255.255.255.0')

In [18]: result
Out[18]: ('interface Fa0/0\n', 'ip address 10.1.1.1 255.255.255.0')

In [19]: type(result)
Out[19]: tuple

In [20]: intf, ip_addr = configure_intf('Fa0/0', '10.1.1.1', '255.255.255.0')

In [21]: intf
Out[21]: 'interface Fa0/0\n'

In [22]: ip_addr
Out[22]: 'ip address 10.1.1.1 255.255.255.0'

Документация (docstring)#

Первая строка в определении функции - это docstring, строка документации. Это комментарий, который используется как описание функции:

In [23]: def configure_intf(intf_name, ip, mask):
    ...:     '''
    ...:     Функция генерирует конфигурацию интерфейса
    ...:     '''
    ...:     config_intf = f'interface {intf_name}\n'
    ...:     config_ip = f'ip address {ip} {mask}'
    ...:     return config_intf, config_ip
    ...:

In [24]: configure_intf?
Signature: configure_intf(intf_name, ip, mask)
Docstring: Функция генерирует конфигурацию интерфейса
File:      ~/repos/pyneng-examples-exercises/examples/06_control_structures/<ipython-input-23-2b2bd970db8f>
Type:      function

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