python: возращаемое значение def
Мне это надо, чтобы в некоторых ситуациях использовать возращаемое def'ом значение сразу же (в качестве функции, или её вызова или еще чего). Кроме того, интересно, насколько аппликативен питон. Конечно, можно использовать лямбду (её возвращаемое значение - сама ф-ция) и присваивать её переменной, но хотелось бы честное поименование функции.
return a + b + c[0]
upd.
Подсветка питоновского кода не понравилась. ГЛючная и страшненькая =)
return 1
def FuncNoRet():
pass
a = FuncRet
print a()
print a
a = FuncNoRet
print a()
print a
Первое: переменной a я присвоил функцию. Всё работает. Это заложено в языке. То же самое можно сделать и с лямбдой.
Второе: даже если я не указал, что функция что-то возвращает, то она все равно возвращает None. Это бывает удобно при работе с контейнером функций (например, так я использовал словарь с функциями в своей Адресной Книге).
Конструкция def является предложением, а не выражением и потому не возвращает результат.
Семантика def в некотором смысле эквивалентна семантике let из ML-семейства, она подразумевает связывание с именем (в текущем контексте), следующим за ним, некоей функции.
Подсветка питоновского кода не понравилась. ГЛючная и страшненькая =)
Это в чем? В книге? :)
..а функция без имени - лябда. Насколько я понимаю.
Не совсем, насколько я понимаю. Лямбда - это функция, содержащая одно выражение (expression). Тут нельзя использовать блоки кода, созданные с помощью if, while и т.п. То есть лямбда не является полноценной функцией.
Можно и у простой функции имя удалить, но от этого она лямбдой не станет:
return 1
a = FuncRet
print a()
del FuncRet
lm = lambda: 2 + 3
print lm # <function <lambda> at 0x...>
print a # <function FuncRet at 0x...>
print FuncRet() # oops
Хотя, возможно, в этом случае я вру с терминологией :)
та не. это я про [ highlight = python ] [ /highlight ]
На питоно-псевдо-коде что-то типа такого (вызов g):
...
def f (fl) :
return [for i in fl :
g(def i
...)]
Конечно, удобнее, когда обьявители функций всё-же являются функциями и возвращает значение, но в данном случае не критично - то, что требуется можно через присвоенные переменным лямбды сделать.
Ну в общем случае это просто безымянная функция. В питоне их решили ограничить одним выражением.
[quote=Лутц]
def creates an object and assigns it to a name. When Python reaches and runs
a def statement, it generates a new function object and assigns it to the function’s
name. As with all assignments, the function name becomes a reference to the func-
tion object. There’s nothing magic about the name of a function—as you’ll see,
the function object can be assigned to other names, stored in a list, and so on.
Function objects may also have arbitrary user-defined attributes attached to them
to record data.
lambda creates an object but returns it as a result. Functions may also be created
with the lambda expression, a feature that allows us to in-line function definitions
in places where a def statement won’t work syntactically
[/quote]
еще чуток про лямбду:
[quote=Лутц]
Besides the def statement, Python also provides an expression form that generates
function objects. Because of its similarity to a tool in the Lisp language, it’s called
lambda.* Like def, this expression creates a function to be called later, but it returns the
function instead of assigning it to a name. This is why lambdas are sometimes known
as anonymous (i.e., unnamed) functions. In practice, they are often used as a way to
inline a function definition, or to defer execution of a piece of code.
[/quote]
lambda.
Ну, не совсем. В Лиспе лямбды не ограничены одним выражением. Ну и в питоне это ограничение по-идее не так страшно: можно заменить все кодоблоки на аналогичные функции: типа func-for(init-expr, continuation-pred, some-lambda) и преобразовать любой код, состоящий из блоков и тп в одно выражение.
На питоно-псевдо-коде что-то типа такого (вызов g):
...
def f (fl) :
return [for i in fl :
g(def i
...)]
Если я правильно понимаю что требуется, то так надо:
...
def f (fl) :
return [for i in fl : g(i)]
и будет новый список вместо fl.
Опять я ничего не понял. Мне бы на рабоче-крестьянском, а не на аспирантском :)
А что в fl содержится? Почему туда не засунуть функции? Вот и будут они передаваться в g.
В Питоне все переменные вроде как указатели без типа, указывают на объекты в памяти. Объектом может быть и функция. Одна и та же переменная вначале может указывать на число, потом на список, потом на функцию. Привязывай к чему хочешь, когда хочешь.
В g имя уже не дойдет - только объект, который будет привязан к локальной переменной в g.
Надобно одновременно определять функцию с именем, заданным переменной i и потом эту же функцию передавать параметром функции g, подобно тому, как если бы она была лямбдой g(lambda ...).
Попахивает черной магией ::)
Имхо на лету (в рантайме) создавать именованную функцию.... как-то, э-э-э, странно, я бы сказал.
Но все-таки нет ничего невозможного: http://snipplr.com/view/17819/python--create-a-function-in-runtime/
Ну если-бы это делалось на си, си++ и тп - тогда действительно было ею, но для динамических языков - это не просто нормально, но даже подход.
Спасибо, это интересно. Но жутко напряжно и как-то некрасиво. Возможно, есть вариант сделать лучше через eval.
На Лиспе, например, я бы так делал:
Функция обьявляющая функцию:
(eval `(defun ,name ,args ,code)))
Функционал, обьявляющий функции, описанные в списке definitions-list и применяющий функцию func-to-apply к результату каждого обьявления:
(loop for f in definitions-list
do (funcall func-to-apply (apply 'define-function f))))
Пример использования для одновременного обьявления и инстанцирования continuation-генератора последовательных натуральных чисел начиная с заданного:
(define-funcs-and-apply '((gen-1 (x) (lambda nil (setq x (+ x 1))))
(gen-2 (x) (lambda nil (setq x (+ x 2)))))
(lambda (f) (push (funcall f 0) generator-registry)))
(defun call-generator (n) (funcall (nth n generator-registry))))
Вышеприведённый код обьявляет две функции-обьявителя генератора (gen-1 и gen-2), которые возвращают функцию-генератор последовательных (с шагом 1 и 2 соответственно) значений начиная с заданного-при-вызове gen-1 или gen-2 аргумента, и одновременно вызывает эти функции с аргументом 0, инстанцируя два генератора, которые потом можно вызывать обьявляемой в этом же куске кода функцией-аксессором call-generator.
(call-generator 1)
>> 1
(call-generator 2)
>> 2
(call-generator 2)
>> 4
(call-generator 1)
>> 2
(setq new-generator (gen-1 66))
(funcall new-generator)
>> 67
Конечно, не самый практичный пример использования, но наглядный.
В том и проблема, что лисповские подходы требуется также ив Питоне найти. На деле там аналогичные по смыслу практические задачи могут решаться по другому. Скажем, генератор может задаться совсем просто:
a = itertools.count(5)
print a.next(), # 5
print a.next(), # 6
print a.next() # 7
или так:
res = first
while True:
yield res
res *= mult
gen1 = MyGen(6, 2)
gen2 = MyGen(8, 3)
print gen1 .next(), # 6
print gen1 .next(), # 12
print gen1 .next() # 24
print gen2.next(), # 8
print gen2.next(), # 24
print gen2.next() # 72
То есть надо решать конкретную задачу, а не искать способы, которые привык использовать в другом языке.
Но, чую, что это беседа нескольких глухих :)