2013-08-04 2 views
4
>>> list=[None] 
>>> def list[0](x,y): 
    File "<stdin>", line 1 
    def list[0](x,y): 
      ^
SyntaxError: invalid syntax 

Как определить функцию как элемент списка?Определить функцию как элемент списка

Синтаксис определения
+1

Что вы пытаетесь сделать? Я думаю, что вы хотите не то, что вы не должны делать, но даже тогда я не уверен, что вы спрашиваете. – TerryA

+4

Я очень впечатлен, почему так много пользователей используют этот законный вопрос. – Hyperboreus

+1

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

ответ

11

Python's def не является достаточно гибким, чтобы обрабатывать общий lvalues, такой как list[0]. Язык только позволяет вам использовать идентификатор в качестве имени функции. Вот соответствующие части grammar rule for the def-statement:

funcdef  ::= "def" funcname "(" [parameter_list] ")" ":" suite 
funcname  ::= identifier 

Вместо этого, вы можете использовать ряд операторов присваивания и определения:

s = [None] 

def f(x, y): 
    return x + y 

s[0] = f 

В качестве альтернативы можно также хранить lambda expression непосредственно в списке :

s = [lambda x,y : x+y] 
9
def f(whatever): 
    do_stuff() 

l[0] = f 

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

+0

Или 'l = []; l.append (f) ' – SethMMorton

+2

@SethMMorton: Или просто' l = [f] ', если вы контролируете создание' l' вместо того, чтобы пытаться назначить функцию в существующее место, но я решил, что это будет более ясным , – user2357112

4
def someFunctionA(x, y): 
    return x+y 

def someFunctionB(x, y): 
    return x*y 

someList = [someFunctionA, someFunctionB] 

print someList[0](2, 3) 
print someList[1](5, 5) 
+2

Почему бы не 'l = [someFunctionA, someFunctionB]'? (Кроме того, лучше не использовать 'list' в качестве идентификатора.) – glglgl

+0

Я сделал это первым, но получил ошибку и подумал, что необходима лямбда. Сейчас это работает, но очевидно, что лямбда была излишней. +1! – Akinakes

+3

Я думаю, что жалоба на использование 'list' в качестве идентификатора стоит. Тень «список» не очень хорош. – tacaswell

2

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

...(x, y, z=3) 

может быть либо декларация параметра (где 3 по умолчанию для параметра ключевого слова г) или вызова (который проходит значение параметра z ключевого слова в качестве 3).

Если вы хотите разрешить общий назначаемой выражение в def вы также должны позволить

def foo(x, y, z=3)[3](x, y, z=3): 
    ... 

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

Написание парсера для этого является раздражающим (в основном потому, что вам нужно обработать произвольное неограниченное количество исходного кода, не понимая его), и это то, что, например, приводит к худшему правилу синтаксического анализа во всей вселенной, которую я знаю (это страшный most vexing parse C++), которые в основном просто отказались от попыток получить достойный язык, отказавшись от двусмысленности.

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

Python правильно оценивает читаемость как очень важную.

Функция в Python, однако первые объекты класса, так что вы можете решить вашу проблему достаточно легко:

def foo(...): 
    ... 

mylist[index] = foo 

или, только если функция является одиночным выражением

mylist[index] = lambda ... : ... 

(но lambda очень ограничен, потому что это своего рода «ненавистный» в сообществе Python, а также потому, что он создаст некоторое раздражение на уровне синтаксиса из-за необходимости обработки отступов внутри скобок).

Обратите также внимание на то, что некоторые новички Python не знают, что вы можете использовать def даже внутри функции; например:

def register_http(): 
    def handle_http(connection): 
     ... 
    global_register['http'] = handle_http 

, который будет назначить функцию в качестве элемента глобальной карты без загрязнения глобальных (модуль) имен с его именем. Локальный def также может создавать замыкание путем захвата локальных переменных состояния (только для чтения в 2.x или даже чтения/записи в 3.x).

Обратите также внимание, что если вам нужна некоторая обработка функции, может быть decorators может быть полезна. Например, путем определения

def register(name): 
    def do_registering(f): 
     global_register[name] = f 
     return f 
    return do_registering 

вы можете просто использовать

@register('http') 
def handle_http(connection): 
    ... 
+0

Вы совершенно правы, но, увы, я должен рассказать о том, что такая сложная вещь нужна. Существует очень хороший синтаксический элемент: декораторы. Они могли легко использовать для этого. То, что я иногда делаю, это вернуть или дать функцию, но декораторы не работают для операторов. Однако '@ return' или' @ yield' было бы неплохо. В этом случае мы могли бы иметь «@ = target» (было бы уродливо из-за назначения назначения справа) или, возможно, '@@ target', например' @@ global_register ['http'] 'перед функция, устраняя необходимость в уродливой строке назначения/выхода/возврата после функции. – glglgl

+0

@glglgl: вы можете сделать что-то более простое, чем при использовании параметрических декораторов типа '@register ('http')'. Они вроде странны для реализации (параметрический декоратор должен вернуть непараметрическую функцию декоратора), но они приятны в использовании. См. Править. – 6502

+0

Правильно, это хорошая альтернатива в этом случае; Я забыл об этом. Но, увы, нельзя использовать для упрощения таких вещей, как 'yield' или' return'. – glglgl

Смежные вопросы