Архив рубрики: Python

Python 101: Перемещение файлов между серверами (Перевод)

Если Вам часто приходится заниматься системным администрированием, тогда Вы знаете, что иногда Вам нужен скрипт, который бы перемещал файлы с одного сервера на другой. Я не системный администратор, но мне часто приходится сталкиваться с такой задачей. У Python есть сторонний пакет для этой цели. Мы посмотрим на paramiko, который зависит от PyCrypto (скачать PyCrypto можно с PyPI).

Пишем код

Предположим, что у Вас уже всё установлено, так что мы можем приступать к работе. Вот код, основанный на том, что я сам использую на работе. Давайте посмотрим на него:
import paramiko
 
########################################################################
class SSHConnection(object):
""""""
 
#----------------------------------------------------------------------
def __init__(self, host, username, password, port=22):
"""Инициализируем и настраиваем соединение"""
self.sftp = None
self.sftp_open = False
 
# открываем поток SSH Transport
self.transport = paramiko.Transport((host, port))
 
self.transport.connect(username=username, password=password)
 
#----------------------------------------------------------------------
def _openSFTPConnection(self):
"""
Открываем SFTP соединение, если этого ещё не сделано
"
""
if not self.sftp_open:
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
self.sftp_open = True
 
#----------------------------------------------------------------------
def get(self, remote_path, local_path=None):
"""
Копируем файл с удалённого хоста к нам
"
""
self._openSFTPConnection()
self.sftp.get(remote_path, local_path)
 
#----------------------------------------------------------------------
def put(self, local_path, remote_path=None):
"""
Копируем файл от нас на удалённый хост
"
""
self._openSFTPConnection()
self.sftp.put(local_path, remote_path)
 
#----------------------------------------------------------------------
def close(self):
"""
Закрываем SFTP и ssh соединения
"
""
if self.sftp_open:
self.sftp.close()
self.sftp_open = False
self.transport.close()
 
if __name__ == "__main__":
host = "myserver"
username = "mike"
pw = "dingbat!"
 
origin = '/home/mld/projects/ssh/random_file.txt'
dst = '/home/mdriscoll/random_file.txt'
 
ssh = SSHConnection(host, username, pw)
ssh.put(origin, dst)
ssh.close()
Достаточно просто, правда? В методе  __init__ нашего класса мы всего лишь задаём параметры соединения. В нашем случае нам надо указать хост, логин и пароль. После чего мы открываем потоковый объект SSH Transport. Затем мы вызываем наш метод put для отправки файла на удалённый сервер. С обратной задачей нам поможет справиться метод get. И, наконец, мы вызываем наш метод close, чтобы закрыть соединение. Можно заметить, что в наших методах put и get мы используем частный метод для проверки наличия соединения, чтобы открыть его в случае, если оно было по какой-то причине закрыто.

Итог

Paramiko реально облегчает нашу работу. Я очень рекомендую прочитать статью Jesse’а на эту тему (ссылка ниже), так как там всё это описывается более подробно. Мы интересно, как ещё можно решить эту задачу при помощи ssh и scp, так что я буду рад вашим комментариям. Сам я слышал хорошие отзывы о Fabric.

Дополнительное чтение

Автор: Ishayahu Lastov

Зачем в python with

Долгое время при работе с файлами из python я писал примерно следующий код:

Без подсветки синтаксиса

def some_func(fname):
    fd = open(fname)
    some_data_processing(fd.read())
    return result

 

def some_func(fname):
    fd = open(fname)
    some_data_processing(fd.read())
    return result

 

Тут предполагается, что в любом случае при выходе из функции переменная fd уничтожится и вместе с ней закроется файл и все будут жить долго и счастливо.

Но что будет если в some_data_processing произойдет исключение?

Например так:

Без подсветки синтаксиса

import sys

class TestClass(object):
def __del__(self):
print «I’m deleted»

def data_process():
obj = TestClass()
raise IndexError()

try:
data_process()
except:
print «In exception handler»

print «after except»

 

import sys

class TestClass(object):
def __del__(self):
print «I’m deleted»

def data_process():
obj = TestClass()
raise IndexError()

try:
data_process()
except:
print «In exception handler»

print «after except»

 

На консоли появляется:

    In exception handler
    after except
    I'm deleted

Почему-то «In exception handler» и «after except» выводятся раньше «I’m deleted».

Первая проблема в том, что вместе с исключением питон хранит и трейс стека, содержащий все фреймы вплоть до породившего исключение. А внутри фрейма живет f_locals — словарь локальных переменных, и именно он имеет ссылку на экземпляр класса TestClass. Таким образом до окончания обработки исключения obj будет жить точно. Почему же «after except» появляется раньше чем «I’m deleted»? Было бы логично чистить трейс после успешного выхода из блока try. Дело в том что 2.X питон не всегда чистит внутренние структуры после обработки исключения и в общем случае вы должны явно вызывать функцию sys.exc_clear чтобы очистить их. Когда я подошел с этим вопросом к Larry Hastings (одному из основных разработчиков ядра питона) ему потребовалось около 20ти минут, что-бы понять что происходит и найти в документации sys.exc_clear. (Правда стоит отметить, что он давно использует 3.X, где это поведение стало адекватнее.) В 3.X это поведение улучшили, и теперь sys.exc_clear автоматически вызывается окончанию обработки исключения.

Кстати, если вы напишете примерно такой код:

Без подсветки синтаксиса

try:
    data_process()
except:
    fr = sys.exc_info()[2]
    del fr

 

try:
    data_process()
except:
    fr = sys.exc_info()[2]
    del fr

 

то не забудьте удалить fr используя del, как в последней строке — иначе он образует циклическую ссылку с текущим фреймом и тогда все станет совсем плохо.

Стоит отметить, что подобное поведение проявляется не всегда. Например сл

Метаклассы в python 2.X с примерами и полным разоблачением

Теория, часть 1. Метаклассы

Все начинается с объявления класса:

Hightlited/Raw

class A(object):
field = 12
def method(self, param):
return param + self.field

class A(object):
field = 12
def method(self, param):
return param + self.field

Имеющие опыт программирования на компилируемых языках могут увидеть здесь декларативную конструкцию, но это только обман зрения. В python всего две декларативные конструкции — объявление кодировки файла и импорт синтаксических конструкций «из будущего». Все остальное — исполняемое. Написанное объявление это синтаксический сахар для следующего:

Hightlited/Raw

txt_code = """
field = 12
def method(self, param):
return param + self.field
"""

class_body = {}
compiled_code = compile(txt_code, __file__, "exec")
eval(compiled_code, globals(), class_body)
A = type("A", (object,), class_body)

txt_code = """
field = 12
def method(self, param):
return param + self.field
"""

class_body = {}
compiled_code = compile(txt_code, __file__, "exec")
eval(compiled_code, globals(), class_body)
A = type("A", (object,), class_body)

Оба этих способа создать класс A совершенно эквивалентны. Окончательно убедиться в том, что объявление класса исполнимо можно посмотрев вот на это:

Hightlited/Raw

def this_is_not_cplusplus(some_base_class, num_methods):
class Result(some_base_class):
x = some_base_class()
for pos in range(num_methods):
# добавим функцию в locals - она попадает в тело
# класса Result и станет его методом
locals()['method_' + str(pos)] =
lambda self, m : m + num_methods
return Result

class_with_10_methods = this_is_not_cplusplus(object, 10)
class_with_20_methods = this_is_not_cplusplus(
class_with_10_methods, 20)
print class_with_10_methods().method_3(2) # напечатает 12
print class_with_20_methods().method_13(2) # напечатает 22

def this_is_not_cplusplus(some_base_class, num_methods):
class Result(some_base_class):
x = some_base_class()
for pos in range(num_methods):
# добавим функцию в locals - она попадает в тело
# класса Result и станет его методом
locals()['method_' + str(pos)] =
lambda self, m : m + num_methods
return Result

class_with_10_methods = this_is_not_cplusplus(object, 10)
class_with_20_methods = this_is_not_cplusplus(
class_with_10_methods, 20)
print class_with_10_methods().method_3(2) # напечатает 12
print class_with_20_methods().method_13(2) # напечатает 22

Функция this_is_not_cplusplus создает новый класс каждый раз, когда мы ее вызываем, используя переданный тип в качестве базового и создавая в н

Установка питона и пакетов

В этой статье я попытаюсь описать процесс создания готового python окружения и работу с пакетами на пользовательском уровне. Статья расcчитана на новичков (в основном для студентов, слушающих мои курсы).

Задачи обычно возникающие при установки питона и его пакетов:

  • Выбор дистрибутив питона и его установка
  • Выбор IDE
  • Поиск и установка пакетов

Кроме этого я пробегусь по этим полезным вещам:

 

Выбор дистрибутив питона и его установка

Если вы используете linux, то лучше использовать python идущий в пакетах — как правило это немного измененный cpython. Для windows можно выбирать между стандартным питоном и дистрибутивом от Active State. Последний содержит расширенную документацию и некоторые дополнительные библиотеки. Мы не будем рассматривать PyPy/Stackless/etc — ограничимся только CPython. Дальше нужно сделать выбор между двумя ветками — 3.2/3.3 и 2.7. Пока что с 2.7 у вас будет меньше проблем, но третья версия по поддержке уже подбирается достаточно близко. x86 и amd64 версии выбираем по вкусу. Установка и под windows и совершенно стандартна и не должна вызывать проблем. В linux питон уже почти 100% установлен.

 

Выбор IDE

Динамический характер языка делает написание функциональных IDE достаточно сложным, а высокая компактность кода и pythonic подход заметно уменьшает в них необходимость. Так что не сложные проекты можно делать в продвинутых текстовых редакторах — [notepad++], sublime text (или vim/emacs). Хотя новичкам IDE будут оказывать заметную помошь встроенной подсказкой и каким ни каким статическим анализом. Из IDE я бы выделил eclipse + pydev и платные PyCharm и KomodoIDE. Также есть Python tools for VS, которые добавляет поддержку cpython и ironpython в VS2010/VS2012.

Я бы советовал выбирать между sublime text и eclipse + pydev.

 

Поиск и установка пакетов

Пакеты/модули в python это файлы с расширениями py/pyc/pyo/(pyd или so), или директории с такими файлами. Также весь пакет может быть в одном архиве (только если пакет не содержит pyd/so файлы). По умолчанию пакеты устанавливаются в системную папку — PYTHON_ROOTlibsite-packages для windows и /usr/local/lib/pythonXX/dist-packages для ubuntu (XX — версия питона, PYTHON_ROOT — корневая папка установки python, как правило С:PythonXX)

Если вы используете linux, то можно использовать пакеты из дистрибутива — в Ubuntu/Fedora есть практически все. Иначе искать пакеты в основном стоит на pypi или с помощью google. Пакеты могут быть в трех основных форматах: архив, exe/msi, egg.

Архив нужно распаковать, в корневой папке должен быть файл setup.py. Если его там нет, то можно просто скопировать содержимое архива в директорию с пакетами. Если setup.py есть, то нужно выполнить python setup.py install. При этом следует использовать тот интерпретатор питона, в который вы хотите установить пакет. Если пакет не предоставляет модулей написанных на С/С++, то установка должна пройти без особенных проблем. Иначе python будет пытаться собрать компилируемые расширения. В linux такой процесс проходит чаще всего безболезненно (максимум требуется установка пакетов с заголовочными файлами для для используемых C библиотек), а вот в windows путь компиляции может быть достаточно трудным.

При установке в windows проще использовать уже собранный exe/msi файл. Для большинства пакетов они доступны на pypi или на сайте библиотеки, также много бинарных пакетов можно найти на pythonlibs. При загрузке обратите внимание на архитектуру и версию python. Для установки такие пакеты нужно запустить. Библиотеки не содержащие компилируемого кода уставливаются без проблем на обеих системах.

egg это формат пакетов одного из пакетные менеджеров питона — setuptools. Грубо говоря это zip архив с дополнительной информацией о пакете и его зависимостях. Более новой и активно развиваемой альтернативой setuptools является pip. pip использует код setuptools(или distribute) и не поддерживает egg. Оба этих менеджера умеют находить пакеты по имени на pypi, по URL и локально. Поддерживаются разнообразные форматы архивов и автоматическая установка зависимостей. pip умеет деинсталлировать пакеты и поддерживает установку из svn/git/mercurial.

Установка pip — www.pip-installer.org/en/latest/installing.html

Установка setuptools

Оба этих менеджера предоставляют команду easy_install, pip кроме этого предоставляет команду pip.

Использование (примеры команд без их вывода):

Без подсветки синтаксиса

# pip install pylint # установим pylint
# easy_install install -U pylint # обновить пакет
# pip install --upgrade simplejson
# pip uninstall simplejson # удалить
# pip install http://my.package.repo/SomePackage-1.0.4.zip
# pip install git+https://github.com/simplejson/simplejson.git
# pip install svn+svn://svn.zope.org/repos/main/zope.interface/trunk/

 

# pip install pylint # установим pylint
# easy_install install -U pylint # обновить пакет
# pip install --upgrade simplejson
# pip uninstall simplejson # удалить
# pip install http://my.package.repo/SomePackage-1.0.4.zip
# pip install git+https://github.com/simplejson/simplejson.git
# pip install svn+svn://svn.zope.org/repos/main/zope.interface/trunk/

 

virtualenv

virtualenv позволяет делать на одной машине несколько независимых инсталляций python, каждая из которых имеет свой интерпретатор, набор настроек и библиотек. Некоторые из таких окружений могут использовать системную папку с дополнительными пакетами. Кроме этого virtualenv позволяет устанавливать питон и пакеты пользователям без прав root.

Без подсветки синтаксиса

$ sudo pip install virtualenv # или sudo apt-get install python-virtualenv
$ virtualenv --distribute ENV_NAME # или python virtualenv.py --distribute ENV_NAME

—distribute заставить virtualenv установить distribute вместо setuptools.

 

$ sudo pip install virtualenv # или sudo apt-get install python-virtualenv
$ virtualenv --distribute ENV_NAME # или python virtualenv.py --distribute ENV_NAME

—distribute заставить virtualenv установить distribute вместо setuptools.

 

Эта команда создаст папку ENV_NAME внутри которой будет интерпретатор python ENV_NAME/bin/python и каталог для пакетов ENV_NAME/lib/pythonX.X/site-packages. ENV_NAME/bin/python будет настроен на поиск пакетов в ENV_NAME/lib/pythonX.X/site-packages. Также virtualenv устанавливает в новое окружение pip. Что-бы активировать это окружений нужно исполнить скрипт activate.

Без подсветки синтаксиса

$ source ENV_NAME/bin/activate
> ENV_NAMEScriptsactivate # для windows

 

$ source ENV_NAME/bin/activate
> ENV_NAMEScriptsactivate # для windows

 

Теперь команда python будет приводить к запуску питона из ENV_NAME/bin/python, то же относится и к pip. После окончания работы нужно выполнить deactivate. virtualenv включили в стандартную библиотеку начиная с python3.3

 

lint’ы

Линтами называют средства статического анализа по имени первой такой утилиты, которая находила странно написанные участки C кода, потенциально содержащие ошибки. Из-за динамического характера python сделать для него очень хороший линт невозможно, а даже просто хороший очень сложно. Ошибки при которых С программа даже не скомпилируется могут легко загнать в угол python линты. Но тем не менее значительную часть (а у начинающих — практически все) ошибок/опечаток они найдут.

Три основных lint’а для python это pylint, pychecker и pyflakes. Из них pylint, наверное, наиболее сообразительный. Кроме этого он имеет большое количество настроек, которые позволяют изменить особенности проверок. Также pylint проверяет стиль кода, используя шаблоны из конфигурационного файла и собирает полезную статистику. Плюс большая часть IDE и даже sublime имеют интеграцию с pylint.

По умолчанию pylint слишком требовательный так что начинать его использование стоит с подстройки конфига под себя, кроме этого иногда он дает ложные срабатывания.

Как более легкую альтернативу можно использовать pep8, проверяющий код на соответствие основному python стандарту кодирования.

 

ipython

Чуть подробнее о установке ipython. Под linux с правами root все просто (ubuntu):

Без подсветки синтаксиса

$ sudo apt-get install ipython ipython-doc ipython-notebook ipython-qtconsole python-zmq

 

$ sudo apt-get install ipython ipython-doc ipython-notebook ipython-qtconsole python-zmq

 

или

Без подсветки синтаксиса

$ sudo apt-get install --install-suggests ipython

 

$ sudo apt-get install --install-suggests ipython

 

ipython готов к запуску —

Без подсветки синтаксиса

$ ipython qtconsole # GUI консоль
$ ipython notebook  # Web интерфейс
$ ipython # консольный интерфейс

 

$ ipython qtconsole # GUI консоль
$ ipython notebook  # Web интерфейс
$ ipython # консольный интерфейс

 

Под windows все не так просто — нужно загрузить все пакеты и зависимости вручную и установить их. pip поможет не сильно, поскольку большая часть пакетов С расширения с внешними зависимости и собирать их будет лишней сложностью. Зависимости ipython (поскольку мы не будем использовать pip то их придется выяснять и устанавливать самостоятельно) можно определить двумя способами — найти в документации по установке или пытаться запускать ipython и смотреть на ошибки импорта. Из документации находим зависимости:

  • pyqt или pyside
  • pyzmq
  • tornado
  • pygments
  • pyreadline
  • distribute или setuptools

Бинарные версии всех этих пакетов есть в pythonlibs. Загружаем и ставим в любом порядке. После чего выбираем из:

Без подсветки синтаксиса

> С:Python2.7Scriptsipython.bat qtconsole # GUI консоль
> С:Python2.7Scriptsipython.bat notebook # Web интерфейс
> С:Python2.7Scriptsipython.bat # консольный интерфейс

 

> С:Python2.7Scriptsipython.bat qtconsole # GUI консоль
> С:Python2.7Scriptsipython.bat notebook # Web интерфейс
> С:Python2.7Scriptsipython.bat # консольный интерфейс

 

pythonanywhere.com

Если поставить питон совсем никак нельзя, то можно воспользоваться web консолью на указанном сайте. После регистрации можно бесплатно запустить 2 python/ipython консоли в браузере и пробовать python без установки.

Ссылки:
pypi.python.org/pypi/virtualenv
www.python.org/download
www.activestate.com/activepython/downloads
pypi.python.org/pypi
www.lfd.uci.edu/~gohlke/pythonlibs
www.pip-installer.org/en/latest/index.html
ipython.org/ipython-doc/stable/install/install.html
pychecker.sourceforge.net
pytools.codeplex.com
launchpad.net/pyflakes
www.python.org/dev/peps/pep-0008
pypi.python.org/pypi/pylint
pypi.python.org/pypi/pep8
www.jetbrains.com/pycharm
pydev.org
pypi.python.org/pypi/setuptools
www.sublimetext.com
www.activestate.com/komodo-ide
pythonanywhere.com

Исходники этого и других постов со скриптами лежат тут — github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.

Автор: konstantin danilov

Модули и импорты

Для разбития программы на модули удобно использовать импорты.

Для импорта какого-либо модуля нужно написать:

import имя_модуля
Например, чтобы использовать математические функции:
import math
Доступ к какой-то функции:
модуль.имя_функции
Например:
math.sqrt(9) # вернёт 3.0
Для того, чтобы узнать, что есть в модуле, гуглите «python имя_модуля». Либо можем сделать так:
>>> dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
Функция dir покажет список доступных имён в модуле.

Обычно модули находятся в папке место_установки_питонаLib. Можете зайти и посмотреть. Только вряд ли вы найдёте там математический модуль, поскольку он написан на C (банально из-за скорости).

Можно импортировать отдельные вещи из модуля, например:
from math import sqrt, pi
Тогда уже можно обращаться с ним просто, как к sqrt и pi:
>>> sqrt(9)
3.0
>>> pi
3.141592653589793

Можно импортировать и всё:
from math import *
Но это считают плохим стилем, могут быть конфликты имён. И при чтении чужого кода с такими импортами может быть непонятно, откуда взята та или иная функция.

Как же использовать импорты для разбития программы на модули?
В одной папке создадим следующие файлы:
> module.py
# coding: utf-8

def func():
    print «Successfully imported.»


> main.py
# coding: utf-8
import module
def main():
    module.func()
if __name__ == '__main__':
    main()
Итак, что же на самом деле делает импорт? Импорт выполняет файл, все функции, классы, переменные и т.д. теперь доступны там, где выполнялся импорт.

Здесь используется такая конструкция:
if __name__ == '__main__':
    main()
Это нужно для того, чтобы главная функция программы (main()) выполнялась только тогда, когда мы запускаем саму программу, а не, например, импортируем её.


Если из меня хуёвый писатель или вы что-то не поняли, пишите в комментарии или заходите в нашу jabber-конференцию: python-b@conference.jabber.ru

Автор: Бихтсэ
Дата публикации: 2012-09-16T08:14:00.003-07:00