Python

Проблема: стандартный изменяемый объект

Но сначала разберёмся: что такое изменяемый объект в Python? Изменяемые объекты — это такие объекты, которые можно поменять. Список, множество и словарь — всё это изменяемые объекты.

Для примера опишем простенькую функцию:

Skillbox
def add(x, y=[]):
    y.append(x)
    return y

В данной функции add зададим в список (то есть в изменяемый объект) переменную y по умолчанию. Запускаем эту функцию: 

def add(x, y=[]):
    y.append(x)
    return y
print(add('halil'))
print(add('yıldırım'))



Результатом выполнения будет:

['halil']
['halil', 'yıldırım']

Что здесь не так? Здесь идёт переписывание одного и того же списка. При первом вызове add('halil') аргумент по умолчанию превратился в y=['halil'] и стал накладываться на тот же список. Давайте посмотрим, как это происходило:

def add(x, y=[]):
    y.append(x)
    return y
add('halil')
print(add.__defaults__)
add('yıldırım')
print(add.__defaults__)



Результат:

(['halil'],)
(['halil', 'yıldırım'],)

Получается так, что мы перезаписываем список, который был у нас по умолчанию.

Решение: изменяемый объект по умолчанию

В изменяемом объекте, вместо аргумента по умолчанию, используем None. В нашем примере:

def add(x, y=None):
    if y is None:
        y = list()
        y.append(x)
    else:
        y.append(x)
    return y
print(add('halil'))
print(add('yıldırım'))



Результат:

['halil']
['yıldırım']

Проблема: копирование

Создадим словарь в Python.

a = {'a': 5, 'b': 4, 'c': 8}

Допустим, b равно a:

a = {'a': 5, 'b': 4, 'c': 8}
b = a

Удалим первый элемент с ключом a.

del b['a']

Теперь запишем a, b и посмотрим, что произойдёт.

a = {'a': 5, 'b': 4, 'c': 8}
b = a
del b['a']
print(b)
print(a)

Результат:

{'b': 4, 'c': 8}
{'b': 4, 'c': 8}

Но что тут произошло? Мы же хотели удалить первый элемент b, а не a …

Решение

Когда мы говорим, что b = a, на самом деле мы имеем в виду, что b и a указывают на один и тот же объект. А если оба указывают на один объект, то не имеет значение, выполняем мы операции с b или a. Они оба повлияют на этот объект {'a': 5, 'b': 4, 'c': 8}.

Решение:

import copy
a = {'a': 5, 'b': 4, 'c': 8}
b = copy.copy(a)
del b['a']
print(b)
print(a)

Результат:

{'b': 4, 'c': 8}
{'a': 5, 'b': 4, 'c': 8}

Проблема и решение: присвоение имени файлу

Никогда не присваивайте своим файлам на python названия библиотек, которые вы используете.

Например, если вы назовёте свой файл random.py, программа просто не поймёт, что вы пытаетесь сделать.

import random
print(random.random())

Результат:

File "C:\Users\HalilibrahimYıldırım\Desktop\medium\Python\random.py", line 3, in <module>
print(random.random())
TypeError: объект 'module' не вызывается

Читайте также:


Перевод статьи Halil Yıldırım: 3 Common Mistakes You’d Want to Avoid in Python