Введение
В этом разделе представляется концепция модулей и работа с функциями, которые охватывают несколько файлов.
This tutorial is from open-source community. Access the source code
В этом разделе представляется концепция модулей и работа с функциями, которые охватывают несколько файлов.
Любой исходный файл на Python является модулем.
## foo.py
def grok(a):
...
def spam(b):
...
Инструкция import загружает и исполняет модуль.
## program.py
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
Модуль - это коллекция именованных значений и иногда называется пространством имен. Имена представляют собой все глобальные переменные и функции, определенные в исходном файле. После импорта имя модуля используется в качестве префикса. Отсюда и пространство имен.
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
Имя модуля напрямую связано с именем файла (foo -> foo.py).
Все, определенное в глобальном пространстве имен, заполняет пространство имен модуля. Рассмотрим два модуля, которые определяют одну и ту же переменную x.
## foo.py
x = 42
def grok(a):
...
## bar.py
x = 37
def spam(a):
...
В этом случае определения x ссылаются на разные переменные. Одна из них - foo.x, а другая - bar.x. Разные модули могут использовать одинаковые имена, и эти имена не будут конфликтовать между собой.
Модули изолированы.
Модули образуют окружающее окружение для всего кода, определенного внутри них.
## foo.py
x = 42
def grok(a):
print(x)
Глобальные переменные всегда связываются с окружающим модулем (одним и тем же файлом). Каждый исходный файл представляет собой свою маленькую вселенную.
Когда модуль импортируется, все инструкции в модуле выполняются последовательно, пока не достигнут конец файла. Содержимое пространства имен модуля - это все глобальные имена, которые по-прежнему определены в конце процесса выполнения. Если в модуле есть инструкции сценария, которые выполняют задачи в глобальном пространстве имен (печать, создание файлов и т.д.), вы увидите их выполнение при импорте.
import asВы можете изменить имя модуля при импорте:
import math as m
def rectangular(r, theta):
x = r * m.cos(theta)
y = r * m.sin(theta)
return x, y
Это работает так же, как обычный импорт. Просто переименовывает модуль в этом файле.
fromЭто позволяет выбрать определенные символы из модуля и сделать их доступными локально.
from math import sin, cos
def rectangular(r, theta):
x = r * cos(theta)
y = r * sin(theta)
return x, y
Это позволяет использовать части модуля без необходимости указывать префикс модуля. Это полезно для часто используемых имен.
Различные способы импорта не изменяют то, как работают модули.
import math
## vs
import math as m
## vs
from math import cos, sin
...
В частности, import всегда выполняет целый файл, и модули по-прежнему являются изолированными окружениями.
Инструкция import module as только изменяет имя локально. Инструкция from math import cos, sin по-прежнему загружает весь модуль math "под капотом". Просто копирует имена cos и sin из модуля в локальное пространство после того, как это сделано.
Каждый модуль загружается и выполняется только один раз. Примечание: Повторный импорт просто возвращает ссылку на ранее загруженный модуль.
sys.modules - это словарь всех загруженных модулей.
>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath',...]
>>>
Внимание: Часто возникает путаница, если вы повторяете инструкцию import после изменения исходного кода модуля. В силу кеша модулей sys.modules, повторный импорт всегда возвращает ранее загруженный модуль - даже если были внесены изменения. Самый безопасный способ загрузить измененный код в Python - выйти и перезапустить интерпретатор.
Python обращается к списку путей (sys.path), когда ищет модули.
>>> import sys
>>> sys.path
[
'',
'/usr/local/lib/python36/python36.zip',
'/usr/local/lib/python36',
...
]
Обычно первым в списке является текущая рабочая директория.
Как уже упоминалось, sys.path содержит пути поиска. Вы можете вручную настроить его, если это необходимо.
import sys
sys.path.append('/project/foo/pyfiles')
Пути можно также добавлять с помощью переменных окружения.
% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles',...]
В общем случае, обычно не нужно вручную настраивать путь поиска модулей. Однако иногда возникает ситуация, когда вы пытаетесь импортировать Python-код, расположенный в необычном месте или недоступном из текущей рабочего директории.
Для этого упражнения, связанного с модулями, крайне важно убедиться, что вы запускаете Python в правильной среде. Модули часто создают проблемы для начинающих программистов, связанные с текущей рабочим директорией или настройками пути Python. Для этого курса предполагается, что вы пишете весь свой код в директории ~/project. Для наилучших результатов вы должны убедиться, что также находитесь в этой директории, когда запускаете интерпретатор. Если нет, вам нужно убедиться, что ~/project добавлено в sys.path.
В разделе 3 мы создали универсальную функцию parse_csv() для разбора содержимого CSV-файлов с данными.
Теперь мы посмотрим, как использовать эту функцию в других программах. Сначала откройте новое окно консоли. Перейдите в папку, где находятся все ваши файлы. Мы собираемся их импортировать.
Запустите интерактивный режим Python.
$ python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
После этого попробуйте импортировать некоторые из ранее написанных вами программ. Вы должны увидеть их вывод точно так же, как и раньше. Чтобы подчеркнуть, импорт модуля запускает его код.
>>> import bounce
... посмотрите на вывод...
>>> import mortgage
... посмотрите на вывод...
>>> import report
... посмотрите на вывод...
>>>
Если ничего не работает, вы, вероятно, запускаете Python в неправильной директории. Теперь попробуйте импортировать ваш модуль fileparse и получить помощь по нему.
>>> import fileparse
>>> help(fileparse)
... посмотрите на вывод...
>>> dir(fileparse)
... посмотрите на вывод...
>>>
Попробуйте использовать модуль для чтения некоторых данных:
>>> portfolio = fileparse.parse_csv('/home/labex/project/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... посмотрите на вывод...
>>> pricelist = fileparse.parse_csv('/home/labex/project/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... посмотрите на вывод...
>>> prices = dict(pricelist)
>>> prices
... посмотрите на вывод...
>>> prices['IBM']
106.28
>>>
Попробуйте импортировать функцию, чтобы не нужно было указывать имя модуля:
>>> from fileparse import parse_csv
>>> portfolio = parse_csv('/home/labex/project/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... посмотрите на вывод...
>>>
В разделе 2 вы написали программу report.py, которая генерировала отчет по активам, похожий на этот:
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
Взять эту программу и изменить ее так, чтобы все обработка входных файлов выполнялась с использованием функций из вашего модуля fileparse. Для этого импортировать fileparse в качестве модуля и изменить функции read_portfolio() и read_prices(), чтобы они использовали функцию parse_csv().
Используйте интерактивный пример в начале этого упражнения в качестве руководства. После этого вы должны получить точно такой же вывод, как и раньше.
В разделе 1 вы написали программу pcost.py, которая читала портфель и вычисляла его стоимость.
>>> import pcost
>>> pcost.portfolio_cost('/home/labex/project/portfolio.csv')
44671.15
>>>
Измените файл pcost.py так, чтобы он использовал функцию report.read_portfolio().
После завершения этого упражнения у вас должны быть три программы. fileparse.py, в котором содержится универсальная функция parse_csv(). report.py, которая генерирует красивый отчет, но также содержит функции read_portfolio() и read_prices(). И, наконец, pcost.py, которая вычисляет стоимость портфеля, но использует функцию read_portfolio(), написанную для программы report.py.
Поздравляем! Вы завершили лабораторную работу по модулям. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.