Функции и методы в Python: передача функции в функцию. Декоратор
Эта статья посвящена теме декораторов в Python. Поговорим о том, что это такое, уделим особое внимание свойствам функций в Python, на базе которых реализована данная идея, а также рассмотрим декораторы, которые принимают аргументы и возвращают значение из функции.
Что надо знать о методах и функциях в Python?
Говоря о функциях в Python, нужно упомянуть два аспекта: 1) функция в Python — есть объект специального вида, который можно передавать в виде аргумента другим функциям; 2) внутри функций в Python вы можете создавать другие функции, а также вызывать их, возвращая результат посредством return.
Теперь давайте поговорим об этом подробнее.
Функция как объект в Python
В языке программирования Python часто практикуется передача одной функции в виде аргумента другой функции. Представьте, что есть список целых чисел, и вы желаете на его базе получить другой список с элементами, которые будут квадратами первого списка. Вот, как это можно реализовать в Python:
>>> # исходный список >>> a = [1, 2, 3, 4, 5] >>> # функция, которая возводит в квадрат переданное ей число >>> sq = lambda x: x**2 >>> # проверка работы функции в Python >>> print(sq(5)) 25 >>> # получение списка квадратов >>> b = list(map(sq, a)) >>> print(b) [1, 4, 9, 16, 25]В нашем примере мы передали функции map в виде первого аргумента функцию sq. Последняя будет по очереди применяться ко всем элементам нашего списка a.
Кроме того, в Python функция является специальным объектом, имеющим метод __call__() . Представьте, что мы создали следующий класс:
class DemoCall(): def __call__(self): return "Hello!"Объект такого класса в Python мы сможем вызывать как функцию:
>>> hello = DemoCall() >>> hello() 'Hello!'Функция внутри функции в Python
Функции в Python мы можем создавать, вызывать и возвращать из других функций. Кстати, на этом основана идея замыкания (closures) в Python.
Давайте создадим функцию, умножающую 2 числа:
def mul(a): def helper(b): return a * b return helperВ этой функции в Python реализованы два важных свойства: 1) внутри функции mul() мы создаём ещё одну функцию helper() ; 2) функция mul() возвращает нам функцию helper() в качестве результата работы.
Вызов этой функции в Python:
>>>mul(4)(2) 8Особенность заключается в том, что мы можем создавать на базе функции mul() собственные кастомизированные функции. Давайте создадим функцию в Python, умножающую на 3:
>>>three_mul = mul(3) >>>three_mul(5) 15В результате была построена функция three_mul() , умножающая на 3 любое переданное ей число.
Декоратор функции в Python
Конструктивно речь идёт о некоторой функции, в качестве аргумента которого выступает другая функция. Декоратор в Python добавляет дополнительный функционал к функции, не меняя её содержимое.
Создание
Представьте, что мы имеем пару простых функций в Python:
def first_test(): print("Test function 1") def second_test(): print("Test function 2")При этом мы желаем их дополнить таким образом, чтобы перед вызовом основного кода нашей функции печаталась строчка “Start function”, а в конце – строка “Stop function”.
Реализовать поставленную задачу можно несколькими методами. Во-первых, мы можем добавить необходимые строки в конец и начало каждой функции. Но вряд ли это удобно, ведь если мы пожелаем их убрать, придётся модифицировать тело функции.
Теперь поговорим о втором пути. Для начала создадим функцию:
def simple_decore(fn): def wrapper(): print("Start function") fn() print("Stop function") return wrapperТеперь нужно обернуть функции в оболочку:
first_test_wrapped = simple_decore(first_test) second_test_wrapped = simple_decore(second_test)Обратите внимание, что функции first_test и second_test не поменялись.
>>> first_test() Test function 1 >>> second_test() Test function 2Наши функции second_test_wrapped и first_test_wrapped обладают функционалом, который нам и нужен.
>>> first_test_wrapped() Start function Test function 1 Stop function >>> first_test_wrapped() Start function Test function 1 Stop functionТеперь, если надо, чтобы так работали функции с именами first_test и second_test, делаем следующее:
first_test = first_test_wrapped second_test = second_test_wrapped>>> first_test() Start function Test function 1 Stop function >>> second_test() Start function Test function 2 Stop functionВыполненные нами действия и являются реализацией идеи декоратора.
Правда, вместо строк:
def first_test(): print("Test function 1") first_test_wrapped = simple_decore(first_test) first_test = first_test_wrappedмы можем написать иначе:
@simple_decore def first_test(): print("Test function 1")В нашем случае @simple_decore – это не что иное, как декоратор функции.
Передаём аргументы в функцию с помощью декоратора
Бывает, что функция требует наличие аргумента, поэтому мы можем передать его через декоратор. Давайте создадим декоратор, принимающий аргумент и выводящий информацию о декорируемой нами функции и её аргументе.
def param_transfer(fn): def wrapper(arg): print("Start function: " + str(fn.__name__) + "(), with param: " + str(arg)) fn(arg) return wrapperЧтобы продемонстрировать работу, создадим функцию, выводящую квадратный корень переданного ей числа, а в качестве декоратора, укажем созданный param_transfer:
@param_transfer def print_sqrt(num): print(num**0.5)Теперь давайте выполним данную функцию с аргументом 4:
>>> print_sqrt(4) Start function: print_sqrt(), with param: 4 2.0Декораторы для методов класса в Python
С декоратором можно объявлять и методы классов. Давайте выполним модификацию декоратора param_transfer:
def method_decor(fn): def wrapper(self): print("Start method: " + str(fn.__name__)) fn(self) return wrapperТеперь приступим к созданию класса для представления 2-мерного вектора (математического). В классе определим метод norm() , выводящий модуль вектора.
class Vector(): def __init__(self, px = 0, py = 0): self.px = px self.py = py @method_decor def norm(self): print((self.px**2 + self.py**2)**0.5)Что же, осталось продемонстрировать работу нашего метода:
>>> vc = Vector(px=10, py=5) >>> vc.norm() Start method: norm 11.180339887498949Возвращаем результат работы функции через декоратор
Зачастую создаваемые функции выполняют возвращение какого-либо значения. Чтобы это стало возможным осуществить через декоратор, нужно специальным образом построить нашу внутреннюю функцию:
def decor_with_return(fn): def wrapper(*args, **kwargs): print("Start method: " + str(fn.__name__)) return fn(*args, **kwargs) return wrapperВозможно применение этого декоратора и для оборачивания функций, принимающих различные аргументы и возвращающие значение:
@decor_with_return def calc_sqrt(val): return val**0.5Осталось выполнить функцию calc_sqrt() с параметром 16:
>>> tmp = calc_sqrt(16) Start method: calc_sqrt >>> print(tmp)Python-сообщество
- Начало
- » Python для новичков
- » Python - разница между функцией и методом
#1 Май 3, 2014 10:17:24
setevoy От: Kiev, UA Зарегистрирован: 2013-02-22 Сообщения: 10 Репутация: 0 Профиль Отправить e-mail
Python - разница между функцией и методом

Сразу извиняюсь за столь нубский вопрос - просто до классов ещё не дошёл, а вопрос гложет
К примеру, для списков (list) есть и функции (пример - len(list)), и методы (пример - list.append(obj)) - в чём между ними разница?
> Help on built-in function len in module __builtin__: // т.е. он таки функция (модуля?);
> Help on method_descriptor in list: // т.е. это таки метод (класса?);
Именно между понятием и действиями - функции и метода?
#2 Май 3, 2014 10:20:00
FishHook От: Зарегистрирован: 2011-01-08 Сообщения: 8312 Репутация: 568 Профиль Отправить e-mail
Python - разница между функцией и методом
Методы - это функции, являющиеся атрибутами классов. Любой метод - функция, но не каждая функция - метод. Никакой принципиальной разницы между ними в питоне нет, это просто такая терминология.
Отредактировано FishHook (Май 3, 2014 10:23:02)
Чем метод отличается от функции в Python?
В отличие от функции, метод узко специализирован и может быть применен только к объектам, которые его поддерживают. Например, метод списков append() может быть применен только к ним. Применение данного метода к другим объектам, которые его не поддерживают (строки или кортежи) вызовет ошибку. Но есть и такие методы, которые хорошо работают с несколькими типами объектов, например метод count() может применяться к строкам, спискам или кортежам
13 февраля 2023
Метод по сути это та же функция, но так как она определена внутри класса, и первым её аргументом является self , то она становится связанным методом bound method , получившим доступ к атрибутам связанного объекта (экземпляра класса).
# Обычная функция: def greet(name): print(f'Hello, name>') class Person: # Инициализатор класса, требующий присваивать значение атрибута name при инстанцировании объекта def __init__(self, name): self.name = name # Связанный метод, имеющий доступ к атрибуту name: def greet(self): print(f'Hello , self.name>. ') bob = Person('Bob') # Вызов связанного метода класса: bob.greet() # => Hello , Bob. # Вызов функции, не имеющий доступа к атрибутам объекта: greet(bob) # => Hello, # Вызов обычной функции, которой можно передать любое значение: greet('Bob') # => Hello, Bob greet(23) # => Hello, 23 greet('apple') # => Hello, apple
Чем отличается "метод" от "функции"
Неоднократно видел использование термина "метод" для обозначения функций-членов классов в противоположность термину "функция" для обозначения "свободных" функций нечленов. С другой стороны, в текстах о Си++, часто всё называют "функцией" и члены и нечлены. Собственно, какова разница между терминами "метод" и "функция", почему в Си++ члены не называют "методами"?
Отслеживать
задан 30 окт 2017 в 7:28
6,853 2 2 золотых знака 23 23 серебряных знака 43 43 бронзовых знака
почему в Си++ члены не называют "методами"? - так и хочется пошутить про потому что они ч. но не буду
30 окт 2017 в 7:34
Метод - это функция, которая член класса. И это вся разница вроде)
30 окт 2017 в 7:34
@andreymal можно как ответ делать. терминология-faq с эпичным ответом)
30 окт 2017 в 7:40
@АлексейШиманский я не уверен, что так во всех языках, и предпочту воздержаться от ответа. Эпичный ответ с примерами и исключениями (если таковые существуют) от кого-нибудь уверенного будет более полезным)
30 окт 2017 в 7:43
@andreymal А процедура - член класса тогда как называется?
30 окт 2017 в 8:25
6 ответов 6
Сортировка: Сброс на вариант по умолчанию
И чего так много слов то? Все просто:
Метод всегда является функцией, а функция не всегда является методом.
Отслеживать
ответ дан 30 окт 2017 в 9:12
81.2k 7 7 золотых знаков 72 72 серебряных знака 153 153 бронзовых знака
Это как "Большой палец - всегда палец, но палец не всегда большой?" (c) ТБВ
30 окт 2017 в 9:46
Точно, именно так 🙂
30 окт 2017 в 10:14
Нет единой устоявшейся техники наименования сущностей в языках программирования и каждый язык, чтобы немного отличаться от других, по историческим причинам имеет свой набор названий и соглашений.
Так как программирование пришло с математики, то начальные корни нужно искать там. А там были функции и процедуры. Функция на основании своих аргументов генерирует какой-то результат. sin , cos - яркие примеры. Функция без аргументов - вырожденный вариант и обычно это константа. В математике обычно функции являются чистыми - то есть, у них нет побочных эффектов. То есть, вызов функции с одними и теми же аргументами дает один и тот же результат.
Параллельно существуют процедуры. Процедура - это последовательность действий, приводящая к определенному результату (да, обычная программа - это также может быть процедура, хотя. ). В паскале и фортране принято, что процедура не возвращает результат. Но я считаю, что это исключительно соглашение, потому что иначе нужно было бы делать как в C/C++ и вводить пустой тип (void).
почему в Си++ члены не называют "методами"?
Во многих языках 60-70 годов не было ООП в том понимании, которое известно сейчас. С++ изначально был просто "фронтом" (то есть надстройкой) над обычным Си. Был долгий период, когда это уже был не Си, но и ещё и не C++. Компилятора C++ не было, а был транслятор в Си. Видимо, поэтому там закрепилось функция класса/переменная класса. Сейчас Страуструп предлагает N4174, и если его примут, то грань между обычными функциями и функциями класса размоется ещё больше.
В других языках - Java и семейство, проектировались, когда уже ООП был немного сформированным. От обычных функций они решили отказаться и, видимо, чтобы не вызывать путаницу, обозвали все методами. Да, потом им пришлось функции все-таки вернуть назад, но, чтобы ничего не сломать, назвали это статическими методами.
Собственно, какова разница между терминами "метод" и "функция"
Правильный ответ - историческая. Как правильно называть сущности в разных языках, нужно уточнять в их документации.
многие автора книг по с++ называют функции класса методами. Как быть?
Тут все сложно. Например, Эккель так делает видимо потому, что он ещё и много книг о Java написал. Также не стоит забывать, что многие книги мы читаем в переводе, а они "исправляют", потому что переводчику так понятнее.
так можно ли называть функции класса с++ методами?
Это точно так же, как использовать мат/обсценную лексику в высшем обществе. Или пытаться объясниться с гопниками языком Тургенева и стихами Пушкина/Блока.
P.S. метод - слово многозначное и вполне можно услышать от C++ программистов такое "это метод для получения данных с сервера, реализован в виде 5 функций и двух классов".
