Как устроен Python. Как устроен Python. Харрисон. Харрисон Мэтт
Скачать 5.41 Mb.
|
6.6. Дополнительные рекомендации по назначению имен Кроме уже упоминавшегося правила о том, что имена переменных не могут совпадать с ключевыми словами, существует ряд рекомендаций, поддерживаемых сообществом Python. Эти рекомендации просты: имена переменных должны состоять их символов нижнего реги- стра; слова должны разделяться символом подчеркивания; имена переменных не могут начинаться с цифр; имена переменных не могут переопределять встроенные функции. 6.6. Дополнительные рекомендации по назначению имен 47 Несколько примеров имен переменных — как хороших, так и плохих: >>> good = 4 >>> bAd = 5 # плохо - верхний регистр >>> a_longer_variable = 6 # Не рекомендуется >>> badLongerVariable = 7 # Плохо - начинается с цифры >>> 3rd_bad_variable = 8 File " ^ SyntaxError: invalid syntax # Плохо - ключевое слово >>> for = 4 File " for = 4 ^ SyntaxError: invalid syntax # Плохо - встроенная функция >>> compile = 5 СОВЕТ Правила и соглашения назначения имен в Python перечислены в документе «PEP 8 — Style Guide for Python Code» 1 . Сокращение PEP означает «Python Enhancement Proposal», то есть «Предложение по улучшению Python» — так называется процесс документирования функции, усовершенствования или передовой практики для Python. Документы PEP доступны на сайте Python. ПРИМЕЧАНИЕ Хотя Python не разрешает использовать ключевые слова в качестве имен переменных, встроенные имена могут использоваться как переменные. 1 https://www.python.org/dev/peps/pep-0008/ 48 Глава 6. Переменные Встроенные имена (built-ins) — имена функций, классов или переменных, которые Python загружает автоматически, чтобы вам было проще обра- щаться к ним. В отличие от ключевых слов, Python позволяет использовать встроенное имя в качестве названия переменной без малейших возражений. Тем не менее поступать так не рекомендуется — это считается признаком плохого стиля. Использование встроенного имени в качестве названия переменной приво- дит к замещению встроенного имени. Новое имя переменной не позволит получить доступ к исходному встроенному имени. Фактически вы берете встроенную переменную и заимствуете ее для собственного использова- ния. В результате доступ к исходному встроенному имени будет возможен только через модуль __builtins__ . Гораздо лучше с самого начала избегать замещения. Ниже перечислены встроенные имена Python, которые не следует исполь- зовать в качестве имен переменных: >>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 6.7. Итоги 49 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'] СОВЕТ Несколько встроенных имен, которые выглядят особенно соблазнительно в качестве имен переменных: dict , id , list , min , max , open , range , str , sum и type 6.7. Итоги В Python все сущности являются объектами. Объекты обладают состо- янием, которое также называется значением. Для работы с объектами используются переменные. Переменные Python напоминают бирки: они связываются с объектом и обладают именем. Однако объект содержит важные данные: значение и тип данных. В этой главе также рассматривается повторное связывание переменных с объектами. Python допускает такую возможность, но вы должны быть 50 Глава 6. Переменные внимательны и не должны изменять тип переменной, потому что это усложнит понимание кода для тех, кто будет его читать. Наконец, в этой главе рассматриваются соглашения об именах переменных Python. 6.8. Упражнения 1. Создайте переменную pi , которая указывает на приближенное зна- чение числа π. Создайте переменную r для представления радиуса круга; эта переменная должна быть равна 10. Вычислите площадь круга ( π × квадрат радиуса). Умножение выполняется операто- ром * , а возведение числа в квадрат — оператором ** . Например, результат 3**2 равен 9 2. Создайте переменную b , которая указывает на ширину прямоу- гольника со значением 10. Создайте переменную h , которая указы- вает на высоту прямоугольника со значением 2. Вычислите длину периметра прямоугольника. Измените ширину, присвоив ей значе- ние 6, и снова вычислите периметр. 7 Подробнее об объектах В этой главе объекты будут рассмотрены более подробно. Речь пойдет о трех важных свойствах объектов: идентификатор; тип; значение. 7.1. Идентификатор На самом низком уровне идентификатор определяет местонахождение объекта в памяти компьютера. В Python существует встроенная функ- ция id , которая возвращает идентификатор объекта: >>> name = "Matt" >>> id(name) 140310794682416 При выполнении этого кода идентификатор строки "Matt" выводится в форме 140310794682416 (это число определяет адрес оперативной памяти вашего компьютера). Обычно идентификатор изменяется в за- висимости от компьютера и сеанса командного интерпретатора, однако на протяжении жизненного цикла программы идентификатор объекта остается неизменным. Одну корову можно пометить двумя бирками; точно так же две пере- менные могут указывать на один объект. Если вы хотите, чтобы другая 52 Глава 7. Подробнее об объектах переменная (скажем, с именем first ) тоже указывала на объект, на ко- торый указывает name , выполните следующую команду: >>> first = name Команда приказывает Python назначить переменной first такой же идентификатор, как у name . При выполнении функции id для двух пере- менных будут получены одинаковые значения: >>> id(first) 140310794682416 >>> id(name) 140310794682416 Две переменные, один объект name = "Matt" Код "Matt" Id:140... Type:String Что делает компьютер Переменные Объекты name first = name first Рис. 7.1. На диаграмме показано, что происходит при связывании переменной с существующей переменной. Обе переменные указывают на один объект. Обратите внимание: переменная при этом не копируется! Также обратите внимание на то, что объект обладает значением “Matt”, типом и идентификатором Какая польза от идентификатора, спросите вы? Вообще-то пользы не- много. При программировании на Python вас обычно не интересуют такие низкоуровневые подробности, как адрес объекта в памяти. Однако при помощи идентификатора можно показать время создания объектов и возможно ли их изменение. Кроме того, идентификаторы косвенно используются для проверки тождественности оператором is 7.2. Тип 53 Оператор is проверяет тождественность, то есть он проверяет, указывают ли две переменные на один и тот же объект: >>> first is name True Если вывести в REPL first и name , будут выведены одинаковые значения, потому что оба имени указывают на один объект: >>> print(first) Matt >>> print(name) Matt Бирку можно снять с одной коровы и повесить на другую. Точно так же и переменную можно перевести с одного объекта на другой. Например, мы можем заставить переменную name указывать на новый объект. Вы увидите, что идентификатор name изменился, тогда как идентификатор first остался прежним: >>> name = 'Fred' >>> id(name) 140310794682434 >>> id(first) 140310794682416 7.2. Тип Еще одно свойство объекта — его тип. В программах чаще всего исполь- зуются такие типы, как строки, целые числа, числа с плавающей точкой и логические значения. Существует много других типов, вдобавок вы можете создавать собственные. Под «типом объекта» обычно подразуме- вается класс объекта. Класс определяет состояние данных, хранящихся в объекте, а также методы (или действия), которые может выполнять объект. В языке Python тип объекта легко проверяется встроенной функцией type : >>> type(name) 54 Глава 7. Подробнее об объектах В данном случае функция type сообщает, что переменная name указывает на строку ( str ). В следующей таблице перечислены типы различных объектов Python. Объект Тип Строка str Целое число int Число с плавающей точкой float Список list Словарь dict Кортеж tuple Функция function Класс, определяемый пользователем type Экземпляр класса class Встроенная функция builtin_function _or_method type type Из-за применения утиной типизации функция type используется не так часто. Вместо того чтобы проверять, относится ли объект к типу, поддерживающему некоторую операцию, обычно вы просто пытаетесь выполнить эту операцию. Однако иногда в программе имеются данные, которые нужно преоб- разовать к другому типу. Такая ситуация типична для чтения данных из стандартного ввода: данные обычно поступают в виде строки, и эту строку нужно преобразовать в число. Python предоставляет встроенные классы str , int , float , list , dict и tuple , которые при необходимости выполняют преобразование к соответствующему типу: >>> str(0) '0' >>> tuple([1,2]) (1, 2) >>> list('abc') ['a', 'b', 'c'] 7.3. Изменяемость 55 ПРИМЕЧАНИЕ Термин «утиная типизация» происходит от поговорки XVIII века, в которой говорилось о механической утке: «Если оно выглядит как утка, ходит как утка и крякает как утка, то это утка». Впрочем, лично я предпочитаю сцену из фильма «Монти Пайтон и Священ- ный Грааль», где в одной женщине распознают ведьму, потому что она весит столько же, сколько весит утка. (Если вам это кажется странным, посмотрите фильм — мне он нравится.) Идея в том, что женщина обладает такими же характеристиками (вес), как и утка, поэтому ее следует считать ведьмой. Python действует аналогично. Если вы хотите использовать объект для пере- бора элементов, вы помещаете его в цикл for . Вы не проверяете, является ли он списком или субклассом списка, а просто выполняете перебор. Если вы хотите выполнить операцию сложения, вы не проверяете, является ли объект числом или строкой (или другим типом, поддерживающим сложение). Если операция завершится неудачей — нормально, это всего лишь говорит о том, что вы предоставили неправильный тип. Если вы знакомы с объектно-ориентированным программированием, «утиная типизация» ослабляет жесткие требования субклассирования. Вместо того чтобы наследовать от нескольких классов, чтобы воспользоваться предостав- ляемым ими поведением, вы должны реализовать протоколы (обычно для этого нужно определить один-два метода). Например, чтобы создать класс, который может использоваться для сложения, необходимо реализовать ме- тод .__add__ . Любой класс может определить этот метод и реагировать на операцию сложения. 7.3. Изменяемость Другое интересное свойство объекта — его изменяемость. Многие объ- екты являются изменяемыми, другие неизменяемы. Изменяемые объекты допускают изменение своего значения «на месте» — иначе говоря, их со- стояние можно изменить, но их идентификатор останется неизменным. Неизменяемые объекты не позволяют изменить свое значение. Вместо этого их переменная связывается с новым объектом, но это также при- водит к изменению идентификатора переменной. В языке Python словари и списки являются изменяемыми типами. Строки, кортежи, целые числа и числа с плавающей точкой относятся 56 Глава 7. Подробнее об объектах к неизменяемым типам. Следующий пример демонстрирует, что иденти- фикатор переменной, содержащей целое число, изменится при изменении значения. Сначала программа присваивает целое число переменной age и проверяет идентификатор: >>> age = 1000 >>> id(age) 140310794682416 Обратите внимание: если теперь изменить значение целого числа, то у него появится новый идентификатор: >>> age = age + 1 >>> id(age) 140310793921824 А теперь рассмотрим пример изменения списка. Начнем с пустого списка и проверим его идентификатор. Обратите внимание: даже после добав- ления элемента в список идентификатор списка остается неизменным, поскольку список является изменяемым типом. Сначала мы создаем список и проверяем идентификатор: >>> names = [] >>> id(name) 140310794682432 Теперь добавим в список строку. Здесь есть ряд моментов, заслужива- ющих внимания. Возвращаемое значение метода .append не выводится (то есть метод не возвращает новый список). Но если просмотреть переменную names , выясняется, что новое имя успешно занесено в спи- сок. Также идентификатор списка остался неизменным — список был успешно изменен: >>> names.append("Fred") >>> names ['Fred'] >>> id(name) 140310794682432 Изменяемые объекты не должны использоваться в качестве ключей в словарях. Кроме того, они могут создать проблемы при использовании в качестве параметров по умолчанию в функциях. 7.4. Использование IDLE 57 7.4. Использование IDLE Приведенный пример было бы неплохо опробовать в IDLE (или в ва- шем любимом редакторе с интегрированным интерпретатором REPL). Так как IDLE включает REPL, вы можете ввести приведенный код и проанализировать его прямо в REPL. Однако вы также можете напи- сать код, запустить его и проанализировать из REPL. Чтобы опробовать эту возможность, откройте новый файл и включите в него следующий код: name = "Matt" first = name age = 1000 print(id(age)) age = age + 1 print(id(age)) names = [] print(id(names)) names.append("Fred") print(id(names)) Сохраните код в файле с именем iden.py . Запустите файл. В IDLE для этого следует нажать клавишу F5 . В REPL будут выведены четыре числа. Первые два будут разными; это говорит о том, что целое число является неизменяемым. Последние два числа совпадают. Это объясняется тем, что несмотря на изменение списка names идентификатор остался прежним. В общем-то в этом факте нет ничего принципиально нового. Теперь самое интересное: если ввести в REPL команду dir() , она выведет список переменных. Вы увидите, что глобальные переменные из iden.py теперь стали доступны. REPL в IDLE открывает доступ ко всем глобальным переменным. Вы можете просмотреть name и names и даже вызывать функции или мето- ды — например, names.append("George") Имея возможность изучить результаты только что выполненного кода, вы можете быстро проанализировать код и поэкспериментировать с ним. Опытные разработчики Python нередко пишут код в REPL, вставляют его в файл, снова запускают файл, пишут новый код в REPL и продолжают писать код таким способом. 58 Глава 7. Подробнее об объектах Неизменяемые целые числа a = 1000 Команда 1000 Id:2f3b Type:Integer Что делает компьютер Переменные Объекты Переменные Объекты Переменные Объекты a a = a + 1 1: Python создает целое число 1000 Id:2f3b Type:Integer a 2: Python увеличивает a на 1 и создает целое число 1001 Id:2f3f Type:Integer a = a + 1 1000 Id:2f3b Type:Integer a 3: Python связывает a с новым объектом и уничтожает старый объект 1001 Id:2f3f Type:Integer Рис. 7.2. Попытка изменить целое число неизбежно приводит к созданию нового целого числа. Целые числа неизменяемы, и их значение должно создаваться заново 7.4. Использование IDLE 59 Изменяемый список names = [] [] Id:4f3b Type:List names Этап 1: Python создает пустой список names.append("Fred") [] Id:4f3b Type:List names Этап 2: Python создает объект со строкой "Fred" Id:4f3f Type:String names.append("Fred") [ ] Id:4f3b Type:List names Этап 3: Python вставляет строку в существующий список "Fred" Id:4f3f Type:String Команда Что делает компьютер Переменные Объекты Переменные Объекты Переменные Объекты Рис. 7.3. При присоединении объекта к списку изменяется значение списка. При добавлении и удалении элементов идентификатор списка не изменяется |