Python

(作成:2013/12)

これまでそれなりに色々なプログラミング言語やスクリプトを使ってきたけれど、個人用途〜仕事効率化として、此頃はshとPythonに落ち着いた感じ。
というわけでPython。良いねこれ……実に良い。

紹介とかハウツーは別に良質なサイトが幾らでもあるのでそちらにお任せするとして、ここではウチの備忘録的に適当な事を書いていくので悪しからず。

pydoc – ドキュメント生成式コメント表記

Pythonではコメントの書き方でドキュメントまで出来ちゃう。仕様書≒ソース、みたいな作り方は日曜大工的なウチにもぴったりで素晴しい。

主なところではこんな書き方をすれば良い。上がソースコード、下がpydocによるドキュメント。良い感じ。

#! /usr/bin/env python
# -*- coding:utf-8 -*-

""" [NAME] に続くScriptの簡易説明文

[DESCRIPTION] Scriptの詳細説明文
"""
__author__ = 'Riyo'
__version__ = '0.1'

import sys

foo = 'bar: '

class MyClass:
    """
    [CLASSES] Class説明文
    """

    def __init__(self, hoge=''):
        """ [CLASSES] 関数説明文

        Keyword arguments:
        hoge -- 引数説明
        """
        self.hoge = hoge

    def fuga(self):
        """ [CLASSES] 関数説明文

        Return value:
        戻り値説明
        """
        global foo

        return foo + self.hoge

def main():
    """ [FUNCTIONS] 関数説明文
    """
    c = MyClass('piyo')
    print c.fuga()

    sys.exit(0)

if __name__ == '__main__':
    main()
# pydoc ./test.py

 Help on module test:

NAME
    test - [NAME] に続くScriptの簡易説明文

FILE
    /home/riyo/bin/test.py

DESCRIPTION
    [DESCRIPTION] Scriptの詳細説明文

CLASSES
    MyClass

    class MyClass
     |  [CLASSES] Class説明文
     |  
     |  Methods defined here:
     |  
     |  __init__(self, hoge='')
     |      [CLASSES] 関数説明文
     |      
     |      Keyword arguments:
     |      hoge -- 引数説明
     |  
     |  fuga(self)
     |      [CLASSES] 関数説明文
     |      
     |      Return value:
     |      戻り値説明

FUNCTIONS
    main()
        [FUNCTIONS] 関数説明文

DATA
    __author__ = 'Riyo'
    __version__ = '0.1'
    foo = 'bar: '

VERSION
    0.1

AUTHOR
    Riyo

optparse – コマンドラインオプション実装

スクリプトでコマンドラインを実装するには optparse を使うと楽で良い。何が素敵って、 [-h|--help]--version も簡単に実装できて、例外処理もよろしくやってくれるって事。
惜しむらくは複数行にわたるhelpメッセージを付けられない事か……まあ詳細なんかは man とか作るだろうし、これで十分だけれど。

なおこれを利用するにあたっては、コマンドラインオプションのBackgroundを理解しておくと後々役立つ。

#! /usr/bin/env python
# -*- coding:utf-8 -*-

import sys
from optparse import OptionParser
from optparse import OptionGroup

def main():
    psr = OptionParser(version='0.1')
    psr.add_option('-a', '--apple', dest='apple',
                   help = u'りんご')
    psr.add_option('-b', '--banana', action='store_true', dest = 'banana',
                   help = u'ばなな')
    psr.add_option('-c', '--cherry', action='count', dest = 'cherry',
                   help = u'さくらんぼ')
    grp = OptionGroup(psr, 'Note',
                      u'くだものぱくぱく。')
    psr.add_option_group(grp)

    (opts, args) = psr.parse_args()
    if opts.apple != None:
        print u'りんごの感想: %s' % opts.apple
    if opts.banana:
        print u'そんなばななー'
    if opts.cherry != None:
        print 'いやしんぼめ、もう%d粒も食べおって' % opts.cherry

    sys.exit(0)

if __name__ == '__main__':
    main()
$ ./test.py -a delicious!
りんごの感想: delicious!
$ ./test.py --banana
そんなばななー
$ ./test.py -ccccc
いやしんぼめ、もう5粒も食べおって
$ ./test.py -a
Usage: test.py [options]

test.py: error: -a option requires an argument
$ ./test.py --help
Usage: test.py [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -a APPLE, --apple=APPLE
                        りんご
  -b, --banana          ばなな
  -c, --cherry          さくらんぼ

  Note:
    くだものぱくぱく。
$ ./test.py --version
0.1

telnetlib – Python ScriptでTelnet操作

pexpect モジュールのTelnet拡張? なんだろうなぁ。便利なのは良い事だ。コードはこんな感じ。

#! /usr/bin/env python
# -*- coding:utf-8 -*-

import sys
import telnetlib

def main():
    HOST = 'hostname'
    LOGIN_USER = 'account'
    LOGIN_PASS = 'password'
    ENABLE_PASS = 'admin_password'

    try:
        tn = telnetlib.Telnet(HOST)
        tn.set_debuglevel(0)

        # login
        tn.read_until('Username:')
        tn.write(LOGIN_USER + '\n')
        tn.read_until('Password:')
        tn.write(LOGIN_PASS + '\n')

        # enable
        tn.write('en' + '\n')
        tn.read_until('Password:')
        tn.write(ENABLE_PASS + '\n')
        tn.read_until('#')

        # show running-config
        tn.write('terminal length 0' + '\n')
        tn.write('show running-config' + '\n')
        cfg = tn.read_until('end\r\n').splitlines()
        tn.write('exit' + '\n')
        tn.read_until('#')
    except EOFError:
        print 'connection closed.'

    for line in cfg:
        print line
    sys.exit(0)

if __name__ == '__main__':
    main()

上述の例は、Ciscoネットワーク機器にTelnetでアクセスして、現在動作中の configure を出力するというもの。単なるサンプルスクリプトなのでアカウント情報をコード中に記述しているけれど、平文なので注意。まあコマンドラインオプションで取るのが妥当だろうねえ。

基本は read_until() でコマンドラインに出力される可能性のある文字列を待ち、 write() で入力したい文字列を与える。これの繰り返し。
set_debuglevel() は、引数に0以上の数値を仕込めば stdouttelnetlib の実行結果を出力してくれる。物凄く確認し辛いけれど、テスト実行なんかでまあ便利。

Telnetで管理する同一機材が沢山あったりすると、一括パスワード変換や同一設定の一括登録なんか手作業でやるの莫迦らしくてねえ。こんなん使って適当にスクリプトを組んで、for でホスト名羅列したタプルぶん回せば、仕事がすこぶる捗る。お勧め。

Python Tips

グローバル変数の使い方

Pythonでグローバル定義をClass内や関数内で正しく使う方法。

>>> hoge = ['a', 'b', 'c']
>>>
>>> def test():
...     hoge = 'a'
...     print hoge
... 
>>> test()
a
>>> print hoge
['a', 'b', 'c']
>>>
>>> def test():
...     global hoge
...     hoge = 'a'
...     print hoge
... 
>>> test()
a
>>> print hoge
a

ちゃんと区別されてるねって話。

文字列操作 – 特定複数の「文字」を消す

関数単体であるかなと思ったら無かったのでこんな感じで。以外とトリッキー。

>>> import string
>>>
>>> hoge = '01-23-45-67-89-AB, 01:23:45:67:89:AB, 0123.4567.89AB'
>>>
>>> hoge = hoge.translate(string.maketrans('', ''), '.:-')
>>> print hoge
0123456789AB, 0123456789AB, 0123456789AB