Наткнулся в ленте на такой материал:
4 ошибки в коде на Python, которые выдают в вас новичка
Нет, это не дружеская реклама другого канала. Просто, так как я сам только недавно занялся Питоном, то считаю себя новичком, и пошёл посмотреть, какие ошибки могут меня выдать.
И знаете, увидел странную вещь по одному вопросу. Я не могу оттуда всё копировать, поэтому предлагаю просто ознакомиться с материалом по ссылке, а здесь напишу свои комментарии к нему.
1. Значения по умолчанию
Речь идёт о том, что в классе, например, можно объявить свойство и дать ему значение по умолчанию. Например, так:
В данном случае в классе House создаётся свойство cats, которому присваивается по умолчанию пустой список [].
Далее мы создаём два объекта класса House: my_house и office. Затем в объекте my_house обращаемся к свойству cats (то есть к тому самому пустому списку) и добавляем в него элемент 'Tom'.
После чего выясняется, что элемент 'Tom' теперь есть и в свойстве cats объекта office.
В чём дело? Как пишет Маша, у всех экземпляров класса House будет ссылка на один и тот же список cats. Да, это так.
Чтобы решить эту проблему, предлагается инициализировать свойство cats значением None:
И тогда всё работает.
Но это объяснение в корне неверно (или не так объяснено). После такого примера у новичка в голове отложится, что нужно писать не cats = [], а cats = None. И всё. А ведь кроме этого, в классе появился конструктор __init__(), где мы видим присваивание self.cats = []. Но про это не сказано ни слова.
Точнее говоря, данная проблема вообще никак не связана со значениями по умолчанию.
Что происходит на самом деле:
Свойство cats в классе House – статическое. Это значит, что все экземпляры класса (то есть объекты, созданные конструктором этого класса) видят одно и то же свойство. Так как оно инициализировано как список, то все объекты видят один указатель на список, и при добавлении в список элементов все объекты получают к ним доступ через указатель.
Но решает эту проблему вовсе не присваивание cats = None, а именно инструкция self.cats = [], которая находится в __init__(). В этом месте вместо статического, общего для всего класса свойства cats у объекта (то есть у непосредственно сейчас конструируемого экземпляра) создаётся СОБСТВЕННОЕ свойство self.cats, которое, имея то же самое имя, просто перекрывает статическое свойство. И этому свойству присваивается НОВЫЙ, то есть свой собственный, список. Именно поэтому оно оказывается изолированным от других объектов.
Это значит, что в объявлении статического свойства класса вы можете написать cats = [], или cats = None, или вообще не писать никакого cats. Это не изменит ничего, если в __init__() создаётся собственное свойство self.cats с собственным списком.
В моём примере я присвоил статическому свойству cats непустой список: cats = ['a']:
Как можно видеть, объекты my_house и office получили собственные списки, но я всё ещё могу обратиться к статическому свойству cats через имя класса, т.е. House.cats.
Никакого отношения к значениям по умолчанию это не имеет. На что надо было обратить внимание? На то, что инструкция my_house.cats.append('Tom') обращается не к собственному свойству объекта, а к общему статическому свойству класса. Как только начали создавать собственное свойство в конструкторе, доступ к статическому свойству прекратился. Вот и всё.
По остальным пунктам у меня нет принципиальных возражений и даже рекомендую с ними ознакомиться.
Читайте также:
- ООП в Python: Особенности реализации