Подстановочные знаки в Python? - PullRequest
5 голосов
/ 01 ноября 2011

За прошедшие годы я заметил переменную 'wildcard' в разных частях Python, с которыми я сталкивался. Я предположил, что это работает как Haskell: позволяет вам поместить переменную туда, где она требуется в формальных параметрах, но не связывать ее.

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

Например:

_, extension = os.path.splitext(filename)

Итак, когда я написал что-то похожее на это сегодня:

(lambda (x,_,_): x)((1,2,3))

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

(lambda (x,_,z): _)((1,2,3))
> 2

Похоже, _ это просто имя переменной, как и любое другое.

Существует ли истинная подстановочная переменная, которую я могу использовать по своему усмотрению (т.е. использовать более одного в назначении для распаковки кортежей), как в первом примере?

Ответы [ 5 ]

4 голосов
/ 01 ноября 2011

В Python нет подстановочной переменной.

Я пытаюсь отговорить людей от использования _ в качестве имени переменной в течение достаточно долгого времени. Вы не первый, кто ошибочно принимает _ как какой-то особый синтаксис, поэтому лучше вообще не использовать _ в качестве имени переменной, чтобы избежать такого рода путаницы. Если когда-либо существовало «соглашение» об использовании _ в качестве имени одноразовой переменной, это соглашение было ошибочным.

Есть больше проблем, чем просто путаница, которую это вызывает. Например, _ конфликтует с _ в интерактивном интерпретаторе и общим псевдонимом gettext.

Что касается выражения lambda, я бы просто использовал lambda x, *args: ..., чтобы игнорировать все аргументы, кроме первого. В других случаях я бы использовал имена, явно заявляющие, что я не хочу их использовать, например dummy. В случае циклов range() с я обычно использую for i in range(n) и просто не использую i.

Редактировать : Я только что заметил (просматривая другие ответы), что вы используете распаковку кортежей в списке аргументов, поэтому lambda x, *args: ... не решит вашу проблему. Распаковка кортежей в списках параметров была удалена в Python 3.x, потому что это считалось слишком скрытой функцией. Лучше пойти с ответом Мипади вместо.

3 голосов
/ 01 ноября 2011

Не совсем. Питон не Хаскель. Карта, применять, уменьшать и лямбда - это люди второго сорта, хотя в itertools есть кое-что интересное.

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

def f(x, *args, **kwargs):
    return x

Аргумент *args позволяет использовать любое количество безымянных аргументов (которые будут доступны в виде кортежа с именем args). Дополнительные именованные аргументы будут в словаре с именем kwargs.

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

def make_func(s):
    def f(*trash, **more_trash):
        print s
    return f

f1 = make_func('hello')
f2 = make_func('world')
f1(1,2,'ham','spam')
f2(1,2,a=1,b=2)

выведет:

>>> hello
>>> world

Как указывал @rplnt, для циклов это будет не так:

funcs = []
for s in ('hello','world'):
    def f():
        print s
    funcs.append(f)

for f in funcs:
    f()

выведет:

>>> world
>>> world

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

3 голосов
/ 01 ноября 2011

Нет, Python не имеет эквивалента _ на Haskell.В Python принято использовать _ для «одноразовых» переменных, но это фактическое имя переменной, и, как вы обнаружили, вы не можете использовать его дважды в одном и том же контексте (например, в виде списка лямбда-параметров).

В приведенных вами примерах я бы просто использовал индексирование:

lambda tup: tup[0]

или

lambda tup: tup[1]

Не такой красивый, но один из лучших способов сделать это.

2 голосов
/ 15 января 2013

Возможно, с небольшим фокусом:

class _: 
    def __eq__(x,y): return true
_=_() #always create a new _ instance if used, the class name itself is not needed anymore

[(a,b) for (a,_,_,b) in [(1,2,3,4),(5,6,7,8)]]

дает

[(1, 4), (5, 8)] 

Я часто его использую, потому что это делает код более элегантным, часть красоты Haskells в Python.

1 голос
/ 01 ноября 2011

Короткий ответ - нет.Может просто следовать вашей существующей конвенции.То есть

(lambda (x, _1, _2): x)((1,2,3))
...