Как стать автором
Обновить

Комментарии 18

Только вот x != 0 и bool(x) — по-разному с None взаимодейтсвуют и надо об этом помнить. Поэтому, поскольку «явное лучше неявного», если работаем с числами, то и сравнивать лучше с числами.
Эффективные и не эффективные методы кодинга на Python

Перевод — уровень Бог. Простите, речь шла действительно про эффективные методики кодинга (т.е. как писать больше кода за единицу времени)? Или скорее про вкус? Оригинал не читал, но предполагаю, что имелись в виду "Практики написания хорошего или плохого кода на Python" или "Хорошие или неудачные шаблоны кода на Python" (т.е. речь именно про "хороший качественный" и "дурно пахнущий, не очевидный, тяжелый в поддерживании" код)

А мне больше понравилось:
Если имя участника начинается с двойного подчеркивания (dunder), оно становится измененным. Вот почему вместо ._z элемент ._Cz.

Теперь можно доступ или изменить напрямую .x:
А когда будут примеры хорошего кодинга?
В профиле написано студент. Так что через 2-3 года практики не раньше. =)
x is None сработает не так, если x не унаследован от NoneType. При этом x == None может отрабатывать нормально, через переопределенный __eq__. Сталкивался с таким в SQLAlchemy filter

В примере с параметрами по умолчанию можно ещё короче написать:


def f(value, seq=None):
    seq = seq or []
    ...

Короче, но неверно:


def f(value, seq=None):
    seq = seq or []
    seq.append(value)
    return seq

x = []
f(1, x)
print(x)  # []

Мне казалось, что в примере в статье как раз хотели избавиться от лишнего побочного эффекта. Если использовать возвращаемое значение, то всё Ок.

А если не использовать? В любом случае, эти 2 функции неэквивалентны, а Ваша реализация к тому же имеет очень неочевидный побочный эффект. Не надо так делать, экономия одной строчки этого не стоит.

Предложение от AAngstrom полностью эквивалентно "рекомендованной" авторской версии. В ней тоже будет создаваться новый список, если в seq передать пустой список.
Что интересно, не первый раз вижу такой баг в руководствах для начинающих.

Ох ты ж… я не обратил внимание, что в статье not seq предлагается, я сравнивал с seq is None. Тогда да, просто бить по рукам автора статьи за такие "оптимизации".

Я конечно сам не питонист, но по-моему самое питонное решение:
def f(value, seq=[]):
    return [*seq, value]

Ну или со старым питоном
def f(value, seq=[]):
    return seq+[value]
Изменяемый тип данных в значении аргумента по умолчанию запрещается большинством линтеров
В таком случае меняется поведение функции, в приведенном варианте, если передан список, то он мутируется:
>>> def f(value, seq=None):
...     if not seq:
...         seq = []
...     seq.append(value)
...     return seq
>>> a = [1, 2]
>>> f(3, a)
[1, 2, 3]
>>> a
[1, 2, 3]

В вашем варианте список остается без изменения
>>> def f(value, seq=[]):
...     return [*seq, value]
>>> a = [1, 2]
>>> f(3, a)
[1, 2, 3]
>>> a
[1, 2]


Но «перевернуть» последовательность – более компактный способ:
for item in x[::-1]:

Подскажите, pls, кто знает потроха питона. А что кроется внутри взятия инверсии массива?
Порождается в памяти новый массив который заполняется из x? И ли это как то очень умно понимается интерпретатором и лишней (относительно классического прохода по индексу в массиве) работы не делается?


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

Впрочем сам не поленился проверить…
Вредный совет.
Экономия на написании кода (сомнительная) и бессмысленный для данной задачи расход памяти и ресурсов.
Порождается еще один массив в памяти.


import tracemalloc

def display(info, snapshot, key_type='lineno', limit=3):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)
    total = sum(stat.size for stat in top_stats)
    print(info+": size: %.1f KiB" % (total / 1024))

def test():
    display("1", tracemalloc.take_snapshot())
    x = [1] * (10 ** 6)
    sum = 0
    display("2",tracemalloc.take_snapshot())
    test = True
    for item in x[::-1]:
        if test:
            display("3",tracemalloc.take_snapshot())
            test = False
        sum += item
    display("4",tracemalloc.take_snapshot())
    del x
    display("5",tracemalloc.take_snapshot())

if __name__ == '__main__':
    tracemalloc.start()
    test()

1: size: 0.0 KiB
2: size: 3910.8 KiB
3: size: 7830.2 KiB
4: size: 3926.5 KiB
5: size: 22.6 KiB

Да, конечно, x[::-1] возвращает новый массив, отсортированный в обратном порядке, применять его только для итерации не стоит, для этого есть reversed():


# x[::-1]:
1: size: 0.0 KiB
2: size: 7818.2 KiB
3: size: 15647.6 KiB
4: size: 7842.5 KiB
5: size: 34.3 KiB

# reversed(x):
1: size: 0.0 KiB
2: size: 7818.2 KiB
3: size: 7835.1 KiB
4: size: 7842.5 KiB
5: size: 34.3 KiB
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории