Главная страница

Самоучитель PythonВыпуск 2Дмитрий Мусинмая 07, 2017


Скачать 0.74 Mb.
НазваниеСамоучитель PythonВыпуск 2Дмитрий Мусинмая 07, 2017
Дата20.01.2019
Размер0.74 Mb.
Формат файлаpdf
Имя файлаPython3.pdf
ТипПрограмма
#64480
страница11 из 12
1   ...   4   5   6   7   8   9   10   11   12

31.5. Примеры использования декораторов
129

Самоучитель Python, Выпуск 0.2
>>>
print
(reverse_string(
"А роза упала на лапу Азора"
))
reverse_string была вызвана: 1x wrapper ('А роза упала на лапу Азора',) {}
wrapper 0.00011799999999997923
арозА упал ан алапу азор А
>>>
print
(reverse_string(
"A man, a plan, a canoe, pasta, heros, rajahs, a
˓→
coloratura,"
"maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag,"
"a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash,"
"a jar, sore hats, a peon, a canal: Panama!"
))
reverse_string была вызвана: 2x wrapper ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura,maps, snipe, .
˓→
..',) {}
wrapper 0.00017800000000001148
!amanaP :lanac a ,noep a ,stah eros ,raj a,hsac ,oloR a ,tur a ,mapS ,snip ,eperc
˓→
a , ...
31.5. Примеры использования декораторов
130

Глава
32
Устанавливаем python-пакеты с помощью pip
pip - это система управления пакетами, которая используется для установки и управле- ния программными пакетами, написанными на Python.
Установка pip
Прежде чем с помощью pip устанавливать python-пакеты, нужно сначала установить сам pip.
Python 3.4+
Начиная с Python версии
3.4
, pip поставляется вместе с интерпретатором python.
Python <3.4
Официальная инструкция (
https://pip.pypa.io/en/latest/installing.html
):
• Загрузить get-pip.py
(обязательно сохранив с расширением .py).
• Запустить этот файл (могут потребоваться права администратора).
Есть ещё один способ (для Windows). Возможно, он является более предпочтительным:
• Установить setuptools http://www.lfd.uci.edu/

gohlke/pythonlibs/#setuptools
• Установить pip http://www.lfd.uci.edu/gohlke/pythonlibs/#pip
131

Самоучитель Python, Выпуск 0.2
Начало работы
Попробуем с помощью pip установить какой-нибудь пакет, например,
numpy
:
Linux:
sudo pip3 install numpy
На Windows:
pip3 install numpy
Может не сработать, написав: “python” не является внутренней или внешней командой,
исполняемой программой или пакетным файлом (такого, скорее всего, не должно быть при установке pip вторым способом, но проверить не на чем).
Тогда прийдётся обращаться напрямую:
C:\Python34\Tools\Scripts\pip3
exe install numpy
Либо добавлять папку C:\Python34\Tools\Scripts\ в PATH вручную (самому проверить не на чем, можете посмотреть на stackoverflow
. У кого получится - напишите в комментарии).
Что ещё умеет делать pip
Пробежимся по основным командам pip:
pip help - помощь по доступным командам.
pip install package_name - установка пакета(ов).
pip uninstall package_name - удаление пакета(ов).
pip list - список установленных пакетов.
pip show package_name - показывает информацию об установленном пакете.
pip search - поиск пакетов по имени.
pip –proxy user:passwd@proxy.server:port - использование с прокси.
pip install -U - обновление пакета(ов).
pip install –force-reinstall - при обновлении, переустановить пакет, даже если он послед- ней версии.
32.2. Начало работы
132

Глава
33
Часто задаваемые вопросы
Некоторые не совсем очевидные вещи, с которыми сталкиваются начинающие програм- мисты Python.
Почему я получаю исключение UnboundLocalError, хотя пере-
менная имеет значение?
Может показаться неожиданным получить UnboundLocalError в ранее работающем ко- де, в который добавили операцию присваивания где-то внутри функции.
Этот код:
>>>
x
=
10
>>>
def bar
():
print
(x)
>>>
bar()
10
работает, но следующий код:
>>>
x
=
10
>>>
def foo
():
print
(x)
x
+=
1
приводит к UnboundLocalError:
>>>
foo()
Traceback (most recent call last):
133

Самоучитель Python, Выпуск 0.2
UnboundLocalError
: local variable 'x' referenced before assignment
Это происходит потому, что, когда вы делаете присваивание переменной в области види- мости, она становится локальной в этой области и скрывает другие переменные с таким же именем во внешних областях.
Когда последняя инструкция в foo присваивает новое значение переменной x, компи- лятор решает, что это локальная переменная. Следовательно, когда более ранний print пытается напечатать неинициализированную переменную, возникает ошибка.
В примере выше можно получить доступ к переменной, объявив её глобальной:
>>>
x
=
10
>>>
def foobar
():
global x
print
(x)
x
+=
1
>>>
foobar()
10
Это явное объявление требуется для того, чтобы напомнить вам, что (в отличие от внешне аналогичной ситуации с переменными класса и экземпляра), вы на самом деле,
изменяете значение переменной во внешней области видимости:
>>>
print
(x)
11
Вы можете сделать подобную вещь во вложенной области видимости использованием ключевого слова nonlocal:
>>>
def foo
():
x
=
10
def bar
():
nonlocal x
print
(x)
x
+=
1
bar()
print
(x)
>>>
foo()
10 11
Каковы правила для глобальных и локальных переменных в
Python?
В Python, переменные, на которые только ссылаются внутри функции, считаются гло- бальными. Если переменной присваивается новое значение где-либо в теле функции,
33.2. Каковы правила для глобальных и локальных переменных в Python?
134

Самоучитель Python, Выпуск 0.2
считается, что она локальная, и, если вам нужно, то нужно явно указывать её глобаль- ной.
Хотя это немного удивительно на первый взгляд, это легко объяснимо. С одной стороны,
требование global для присваиваемых переменных предотвращает непреднамеренные побочные эффекты в bar. С другой стороны, если global был обязательным для всех гло- бальных ссылок, вы бы использовали global все время. Вы должны были бы объявить как глобальную каждую ссылку на встроенную функцию или компонент импортируемого модуля.
Почему анонимные функции (lambda), определенные в цикле
с разными значениями, возвращают один и тот же ре-
зультат?
Например, вы написали следующий код:
>>>
squares
=
[]
>>>
for x
in range
(
5
):
squares append(
lambda
: x
**
2
)
Это даёт вам список из 5 функций, считающих x**2. Можно ожидать, что, будучи вы- званными, они вернут, соответственно, 0, 1, 4, 9, и 16. Однако, вы увидите, что все они возвращают 16:
>>>
squares[
2
]()
16
>>>
squares[
4
]()
16
Это случается, поскольку x не является локальной для lambda, а определена во внешней области видимости, и получается тогда, когда она вызывается - а не когда определяется.
В конце цикла, x=4, поэтому все функции возвращают 4**2, то есть 16. Это можно также проверить, изменив значение x и посмотрев на результат:
>>>
x
=
8
>>>
squares[
2
]()
64
Чтобы избежать подобного, необходимо сохранять значения переменных локально:
>>>
squares
=
[]
>>>
for x
in range
(
5
):
squares append(
lambda n
=
x: n
**
2
)
Здесь, n=x создаёт локальную для функции переменную n и вычисляется в момент опре- деления функции:
33.3. Почему анонимные функции (lambda), определенные в цикле с разными
значениями, возвращают один и тот же результат?
135

Самоучитель Python, Выпуск 0.2
>>>
squares[
2
]()
4
>>>
squares[
4
]()
16
Это применимо не только к анонимным, а также и к обычным функциям.
Как организовать совместный доступ к глобальным перемен-
ным для нескольких модулей?
Канонический способ организовать подобный доступ - это создать отдельный модуль (ча- сто называемый config или cfg). Просто добавьте import config в каждый модуль при- ложения. При этом модуль становится доступен через глобальное имя. Поскольку суще- ствует только один экземпляр модуля, любые изменения, произведённые в модуле отра- жаются везде. Например:
config.py:
x
=
0
mod.py:
import config config x
=
1
main.py:
import config import mod print
(config x)
По тем же соображениям, модули можно использовать как основу для имплементации синглтона.
Как правильнее использовать импортирование?
В общих случаях не используйте from modulename import *. Это засоряет пространство имён того, кто импортирует. Некоторые люди избегают этой идиомы даже для тех немно- гих модулей, которые были спроектированны, чтобы так импортироваться. Это такие мо- дули как Tkinter и threading.
Импортируйте модули в начале файла. Это отвечает на вопрос, какие модули требует
Ваш код и находится ли имя модуля в области видимости. Запись по одному импорту на строку упрощает добавление и удаление операторов импорта, но множественный им- порт будет занимать меньше места на экране.
Хорошая практика, если Вы импортируете модули в следующем порядке:
33.4. Как организовать совместный доступ к глобальным переменным для нескольких
модулей?
136

Самоучитель Python, Выпуск 0.2
• стандартные библиотечные модули (например, sys, os, getopt, re)
• модули сторонних разработчиков (всё, что установлено в директории site-packages)
– например, PIL, NumPy и т.д.
• локально созданные модули
Иногда бывает необходимо поместить импорт в функцию или класс, чтобы избежать про- блем с циклическим импортом. Gordon McMillan советует:
Циклический импорт отлично работает, если оба модуля используют форму import
. Но они терпят неудачу, когда второй модуль хочет извлечь имя из первого
(from module import name) и импорт находится на внешнем уровне. Это происходит из- за того, что имена первого модуля ещё недоступны, так как первый модуль занят импор- том второго.
В этом случае, если второй модуль используется только в одной функции, то импорт мож- но легко поместить в эту функцию. К тому времени, как он будет вызван, первый модуль уже закончит инициализацию и второй модуль осуществит свой импорт.
Может оказаться необходимым переместить импорт из начала файла, если один из моду- лей платформно-зависимый. В этом случае импорт всех модулей в начале файла окажет- ся невозможным. В этой ситуации хорошим решением будет импорт нужных модулей в соответствующем платформно-зависимом коде.
Переносите импорт во вложенные области видимости, такие как определения функций,
только если Вы столкнулись с проблемой, например циклического импорта, или если Вы пытаетесь сократить время инициализации модуля.
Эта техника полезна, если многие из импортов не являются необходимыми, и зависят от того, как программа будет исполняться. Вы также можете поместить импорт в функцию,
если конкретные модули используются только в этой функции. Обратите внимание, что загрузить модуль в первый раз может оказаться дорого из-за задержки на инициализа- цию модуля, однако повторные загрузки “бесплатны”, они стоят только пары поисков в словарях. Даже если имя модуля исчезло из области видимости, модуль скорее всего до сих пор находится в sys.modules.
Почему значения по умолчанию разделяются между объекта-
ми?
Этот тип ошибки часто встречается среди начинающих. Предположим, функция:
def foo
(mydict
=
{}):
# Опасность: разделяемая ссылка между вызовами compute something mydict[key]
=
value return mydict
В первый раз, когда вы вызываете функцию, mydict содержит одно значение. Второй раз,
mydict содержит 2 элемента, поскольку, когда foo() начинает выполняться, mydict уже содержит элемент.
33.6. Почему значения по умолчанию разделяются между объектами?
137

Самоучитель Python, Выпуск 0.2
Часто ожидается, что вызов функции создаёт новые объекты для значений по умолча- нию. Но это не так. Значения по умолчанию создаются лишь однажды, когда функция определяется. Если этот объект изменяется, как словарь в нашем примере, последующие вызовы функции будут использовать изменённый объект.
По определению, неизменяемые объекты (числа, строки, кортежи и None), безопасны при изменении. Изменение изменяемых объектов, таких как словари, списки, и экземпляры пользовательских классов может привести к неожиданным последствиям.
Поэтому, хорошей практикой является не использовать изменяемые объекты в качестве значений по умолчанию. Вместо этого, используйте None и внутри функции, проверяйте аргумент на None и создавайте новый список/словарь. Например, не пишите:
def foo
(mydict
=
{}):
Но пишите так:
def foo
(mydict
=
None
):
if mydict is None
:
mydict
=
{}
# create a new dict for local namespace
Однако, эта особенность может быть полезна. Когда у вас есть функция, которая долго вы- полняется, часто применяемая техника - кэширование параметров и результата каждого вызова функции:
def expensive
(arg1, arg2, _cache
=
{}):
if
(arg1, arg2)
in
_cache:
return
_cache[(arg1, arg2)]
# Расчёт значения result
= ...
expensive computation
_cache[(arg1, arg2)]
=
result
# Кладём результат в кэш return result
Как передать опциональные или именованные параметры из
одной функции в другую?
Получить такие параметры можно с помощью спецификаторов * и ** в списке аргумен- тов функции; они возвращают кортеж позиционных аргументов и словарь именованых параметров. После этого Вы можете передать их в другую функцию, используя в её вызо- ве * и **:
def f
(x,
*
args,
**
kwargs):
kwargs[
'width'
]
=
'14.3c'
g(x,
*
args,
**
kwargs)
33.7. Как передать опциональные или именованные параметры из одной функции в
другую?
138

Самоучитель Python, Выпуск 0.2
Почему изменение списка ‘y’ изменяет также список ‘x’?
Если вы написали код:
>>>
x
=
[]
>>>
y
=
x
>>>
y append(
10
)
>>>
y
[10]
>>>
x
[10]
вы, возможно, будете удивлены тому, что добавление в y изменяет также и x.
Два факта приводят к такому результату:
• Переменные - это просто ссылки на объекты. y = x не создаёт копию списка - это просто создаёт переменную y, которая ссылается на тот же объект, что и x.
• Списки изменяемы.
После вызова append, содержимое объекта было изменено с [] на [10]. Поскольку x и y ссылаются на один и тот же объект, использование любого из них даёт нам [10].
Если мы используем неизменяемые объекты:
>>>
x
=
5
# числа неизменяемы
>>>
y
=
x
>>>
x
=
x
+
1
# 5 нельзя изменить. Мы создаём НОВЫЙ объект
>>>
x
6
>>>
y
5
мы можем видеть, что x и y больше не равны, поскольку числа неизменяемы, и x = x
+ 1 не изменяет число 5 путем увеличения. Вместо этого, создаётся новый объект 6 и присваивается переменной x (то есть, изменяется то, на какой объект ссылается x). После этого у нас 2 объекта (6 и 5) и 2 переменные, которые на них ссылаются.
Некоторые операции (например y.append(10) и y.sort()) изменяют объект, в то время,
как внешне похожие операции (например y = y + [10] и sorted(y)) создают новый объект. Вообще в Python (и во всех случаях в стандартной библиотеке), метод, который изменяет объект, возвращает None, чтобы помочь избежать ошибок. Поэтому, если вы написали y
=
y sort()
думая, что это даст вам отсортированную копию y, вы вместо этого получите None, что скорее всего приведёт к легко диагностируемой ошибке.
Однако, существует один класс операций, где одна и та же операция ведёт себя по- разному с различными типами: расширенные операторы присваивания. Например, +=
33.8. Почему изменение списка ‘y’ изменяет также список ‘x’?
139

Самоучитель Python, Выпуск 0.2
изменяет списки, но не кортежи или числа (a_list += [1, 2, 3] эквивалентно a_list.
extend([1, 2, 3])) и изменяет список, в то время, как some_tuple += (1, 2, 3) и some_int += 1 создают новый объект.
Если вы хотите знать, ссылаются ли 2 переменные на один объект или нет, вы можете использовать оператор is, или встроенную функцию id.
Как создавать функции более высокого порядка?
Есть два пути: использовать вложенные функции или вызываемые объекты. Например,
с использованием вложенных функций:
def linear
(a, b):
def result
(x):
return a
*
x
+
b return result
Использование вызываемого объекта:
class linear
:
def
__init__
(
self
, a, b):
self a,
self b
=
a, b def
__call__
(
self
, x):
return self a
*
x
+
self b
В обоих случаях,
taxes
=
linear(
0.3
,
2
)
даёт функцию, что (к примеру) taxes(10e6) == 0.3 * 10e6 + 2.
Использование вызываемого объекта - немного медленнее, и в результате получается больше кода. Однако, заметьте, что несколько функций могут разделять свою сигнату- ру с помощью наследования
:
class exponential
(linear):
# __init__ наследуется def
__call__
(
self
, x):
return self a
*
(x
**
self b)
Объект может сохранять свое состояние для нескольких вызовов:
class counter
:
value
=
0
def set
(
self
, x):
self value
=
x
33.9. Как создавать функции более высокого порядка?
140

Самоучитель Python, Выпуск 0.2
def up
(
self
):
self value
=
self value
+
1
def down
(
self
):
self value
=
self value
-
1
count
=
counter()
inc, dec, reset
=
count up, count down, count set
Здесь inc, dec, reset выступают в роли функций, которые разделяют одну и ту же пере- менную.
Как скопировать объект в Python?
В общем случае, с помощью модуля copy
Некоторые объекты можно скопировать более просто. Словари имеют метод copy:
newdict
=
olddict copy()
Последовательности могут быть скопированы путём срезов
:
new_l
=
l[:]
1   ...   4   5   6   7   8   9   10   11   12


написать администратору сайта