Сопоставление с образцом списков в Python

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

38
задан abatishchev 3 November 2015 в 21:39
поделиться

8 ответов

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

split_list = lambda lst: (lst[0], lst[1:])
head, rest = split_list(my_func())

Однако в Python 3.0 специализированный синтаксис, используемый для variadic подписей аргумента и аргумента, распаковывающего, станет доступным для этого типа общей последовательности, распаковывающей также, таким образом, в 3,0 Вы будете в состоянии записать:

head, *rest = my_func()

См. PEP 3132 для деталей.

60
ответ дан Cristian Ciupitu 27 November 2019 в 03:10
поделиться

В первую очередь, обратите внимание на то, что "сопоставление с образцом" функциональных языков и присвоения на кортежи, которые Вы упоминаете, не действительно настолько подобно. На функциональных языках шаблоны используются для предоставления частичных определений функции. Так f (x : s) = e не означает, берут голову и хвост аргумента f и возврат e использование их, но это означает, что , если аргумент f имеет форму x : s (для [приблизительно 117] и s), тогда f (x : s), равно [1 110].

присвоение Python больше похоже на несколько присвоение (я подозреваю, что это было его исходным намерением). Таким образом, Вы пишете, например, x, y = y, x для свопинга значений в [1 112] и y, не нуждаясь во временной переменной (как Вы были бы с простым оператором назначения). Это имеет мало общего с сопоставлением с образцом, поскольку это - в основном стенография для "одновременного" выполнения [1 114] и y = x. Хотя Python позволяет произвольные последовательности вместо разделенных запятыми списков, я не предложил бы назвать это сопоставление с образцом. С сопоставлением с образцом Вы проверяете, соответствует ли что-то шаблону; в присвоении Python необходимо удостовериться, что последовательности с обеих сторон являются тем же.

, Чтобы сделать то, что Вы, кажется, хотите Вас, обычно было бы (также на функциональных языках), используют любого вспомогательная функция (как упомянуто другими) или что-то подобное [1 116] или where конструкции (который можно рассматривать как использующий анонимные функции). Например:

(head, tail) = (x[0], x[1:]) where x = my_func()

Или, в фактическом Python:

(head, tail) = (lambda x: (x[0], x[1:]))(my_func())

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

(Извините, если мой ответ немного чрезмерен. Я просто думаю, что важно ясно дать понять различие.)

32
ответ дан mweerden 27 November 2019 в 03:10
поделиться

Это - в значительной степени 'чистый функциональный' подход, и как таковой разумная идиома в Haskell, но это, вероятно, не так соответствует Python. Python только имеет очень ограниченное понятие шаблоны таким образом - и я подозреваю, что Вам, возможно, понадобилась бы несколько более твердая система типов для реализации такой конструкции ( любители erlang, приглашенные не соглашаться здесь).

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

, Как был , указал в нескольких случаях , прежде чем , Python не будет на самом деле функциональным языком. Это просто одалживает идеи у мира FP. Это не по сути Хвост, Рекурсивный в способе, которым Вы ожидали бы видеть встроенный в архитектуру функционального языка, таким образом, Вы испытаете некоторые затруднения при выполнении этого вида рекурсивной операции на большом наборе данных, не используя большое стековое пространство.

4
ответ дан ConcernedOfTunbridgeWells 27 November 2019 в 03:10
поделиться

расширенная распаковка была представлена в 3,0 http://www.python.org/dev/peps/pep-3132/

3
ответ дан 27 November 2019 в 03:10
поделиться

В отличие от Haskell или ML, Python не имеет встроенного сопоставления с образцом структур. Большая часть Pythonic способ сделать сопоставление с образцом с попыткой - кроме блока:

def recursive_sum(x):
    try:
        head, tail = x[0], x[1:]
        return head + recursive-sum(tail)
    except IndexError:  # empty list: [][0] raises IndexError
        return 0

Примечание, что это только работает с объектами с индексацией части. Кроме того, если функция является сложной, что-то в теле после head, tail, строка могла бы повысить IndexError, который приведет к тонким ошибкам. Однако это действительно позволяет Вам делать вещи как:

for frob in eggs.frob_list:
    try:
        frob.spam += 1
    except AttributeError:
        eggs.no_spam_count += 1

В Python, хвостовая рекурсия обычно лучше реализуется как цикл с аккумулятором, т.е.:

def iterative_sum(x):
    ret_val = 0
    for i in x:
        ret_val += i
    return ret_val

Это - один очевидный, правильный способ сделать это 99% времени. Мало того, что это более ясно читать, это быстрее, и это будет работать над вещами кроме списков (наборы, например). Если будет исключение, неизбежное там, функция счастливо приведет к сбою и поставит ему цепочку.

3
ответ дан giltay 27 November 2019 в 03:10
поделиться

Ну, почему Вы хотите его в 1 строке во-первых?

, Если Вы действительно хотите, можно всегда делать прием как это:

def x(func):
  y = func()
  return y[0], y[1:]

# then, instead of calling my_func() call x(my_func)
(head, rest) = x(my_func) # that's one line :)
2
ответ дан kender 27 November 2019 в 03:10
поделиться

В дополнение к другим ответам обратите внимание, что эквивалентная голова / операция хвоста в Python, включая расширение python3 * синтаксис обычно будет менее эффективным, чем сопоставление с образцом Haskell.

списки Python реализованы как векторы, так получение хвоста должно будет сделать копию списка. Это - O (n) wrt размер списка, тогда как implementaion, использующий связанные списки как Haskell, может просто использовать указатель хвоста, O (1) операция.

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

, Например, Шифр подход, если изменено для возврата итератора вместо того, чтобы преобразовать его в кортеж будет иметь это поведение. Кроме того, более простой с 2 объектами только метод, не полагающийся на байт-код, был бы:

def head_tail(lst):
    it = iter(list)
    yield it.next()
    yield it

>>> a, tail = head_tail([1,2,3,4,5])
>>> b, tail = head_tail(tail)
>>> a,b,tail
(1, 2, <listiterator object at 0x2b1c810>)
>>> list(tail)
[3, 4]

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

2
ответ дан Community 27 November 2019 в 03:10
поделиться

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


def peel(iterable,result=tuple):
    '''Removes the requested items from the iterable and stores the remaining in a tuple
    >>> x,y,z=peel('test')
    >>> print repr(x),repr(y),z
    't' 'e' ('s', 't')
    '''
    def how_many_unpacked():
        import inspect,opcode
        f = inspect.currentframe().f_back.f_back
        if ord(f.f_code.co_code[f.f_lasti])==opcode.opmap['UNPACK_SEQUENCE']:
            return ord(f.f_code.co_code[f.f_lasti+1])
        raise ValueError("Must be a generator on RHS of a multiple assignment!!")
    iterator=iter(iterable)
    hasItems=True
    amountToUnpack=how_many_unpacked()-1
    next=None
    for num in xrange(amountToUnpack):
        if hasItems:        
            try:
                next = iterator.next()
            except StopIteration:
                next = None
                hasItems = False
        yield next
    if hasItems:
        yield result(iterator)
    else:
        yield None

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

1
ответ дан Jake 27 November 2019 в 03:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: