Для сортировки этого списка у нас есть два пути:
🔸 функция sorted()
>>> a = [3, 1, 2]Думаю, всем очевидно что теперь
>>> b = sorted(a)
>>> print(a, b)
[3, 1, 2] [1, 2, 3]
a и b это разные объекты. Так работает sorted(), то есть получает один список, и возвращает другой список с изменениями. Исходный список не изменяется.🔸 метод list.sort()
>>> a = [3, 1, 2]Метод list.sort() не возвращает новый список. Он вообще ничего не возвращает. Он просто сортирует исходный список.
>>> b = a.sort()
>>> print(a, b)
[1, 2, 3], None
Надеюсь, уловили разницу? Но это было лишь вступление чтобы был ясна следующая тема.
На самом деле я хотел рассказать про операторы "=" и "+=" по отношению к спискам.
Все мы привыкли что запись
x += 3Это просто более короткая версия записи
x = x + 3Но это не всегда так.
Дело в том, что со списками оператор "+" работает аналогично функции sorted(), то есть возвращает новый объект, после чего оператор "=" записывает значение в переменную. В то время как "+=" работает аналогично методу list.sort() — изменяет исходный список.
Вот небольшой пример для проверки:
>>> a = [1, 2]Во второй строке
>>> b = a
>>> a = a + [3, 4]
>>> print(a, b)
[1, 2, 3, 4] [1, 2]
a и b ссылаются на один и тот же обеъект. Но после присвоения результата оператора сложения в переменную a мы создали новый объект и переписали ссылку a.>>> a = [1, 2]А в этом примере переменная
>>> b = a
>>> a += [3, 4]
>>> print(a, b)
[1, 2, 3, 4] [1, 2, 3, 4]
a не перезаписалась, оператор отработал с исходным объектом. Поэтому мы изменили и b тоже.Можете пройтись функцией id() чтобы точно всё проверить.
Данная фишка не сработает с кортежами, так как они неизменяемые. Оба варианта создают новый объект.
Пример, где это может вызвать неоднозначность. Класс, в атрибутах которого указывается список каких-то дефолтных полей. Во время создания инстанса мы можем их расширять через аргументы.
class MyClass:Класс имеет два статических атрибута.
L1 = [0]
L2 = [0]
def __init__(self, fields):
self.L1 = self.L1 + fields
self.L2 += fields
В конструкторе класса в первом случае мы создаём новый атрибут инстанса
L1 который своим именем перекрывает атрибут класса. Такое значение L1 будет только у этого инстанса.Во втором случае мы меняем именно атрибут класса
L2, то есть это будет видно во всех инстансах данного класса.>>> obj1 = MyClass(fields=[1])
>>> print(obj1.L1, obj1.L2)
[0, 1] [0, 1]
>>> obj2 = MyClass(fields=[2])
>>> print(obj2.L1, obj2.L2)
[0, 2] [0, 1, 2]
>>> obj3 = MyClass(fields=[3])
>>> print(obj3.L1, obj3.L2)
[1, 3] [0, 1, 2, 3]
В атрибут класса L2 добавляется элемент при каждом создании инстанса.#tricks