全「???48」を生成してみる

課題1

  • 大文字のアルファベット3文字 + '48' の全パターンのリストを作る

解答 その1

単純にループの入れ子で
# まず大文字のアルファベットのリストを作る
al = [chr(a) for a in range(65, 91)]

# 全パターンのジェネレータ
def akb():
    for a1 in al:
        for a2 in al:
            for a3 in al:
                yield a1 + a2 + a3 + '48'
# リストで取得
allptns = [p for p in akb()]

allptns.index('AKB48') #=> 本家は261番目に出てきた

解答 その2

リスト内包表記の入れ子
# al は大文字アルファベットのリスト
# 全パターンのリスト
allPtns = [a1 + a2 + a3 + '48' for a1 in al for a2 in al for a3 in al]

解答その3

アルファベットの桁数を指定できるようにしてみる

# al は大文字アルファベットのリスト

# 2個のリストを組み合わせる関数
getprd = lambda list1, list2 : [a1 + a2 for a1 in list1 for a2 in list2]

# 全パターンのリストを生成する関数
def akb(num):
    temp = ['']
    def _akb(tl, n):
        if n == 0:
            return getprd(tl, ['48'])
        else:
            return _akb(getprd(tl, al), n - 1)
    return _akb(temp, num)
allPtns = akb(3)

なんかいまいちだなー。もっとかっこよい解答求む。

課題2

課題1に制限を加える

アルファベット3文字は別々のアルファベットを使う(AAAとかAABはダメ)

解答

課題1の解答3のリストを組み合わせる関数(getprd)を以下に修正すれば対応できる。

# 2個のリストを組み合わせる関数(重複省く)
getprd = lambda list1, list2 : [a1 + a2 for a1 in list1for a2 in list2 if a2 not in a1]

課題2の場合は本家は216番目に出てきた。

やってみた感想

ループとか関数とか考えながら書けるので、初めてのプログラミング言語に取り組むときはHello Worldよりこの課題やると楽しそう。

別解

ちなみに標準モジュールのitertoolsを使えば以下のように書ける。
至れり尽くせり!

import itertools
# al は大文字アルファベットのリスト

# 課題1
allptns1 = [''.join(a) + '48' for a in itertools.product(al, al, al)]
# 課題2
allptns2 = [''.join(a) + '48' for a in itertools.permutations(al, 3)]

EXIFタグで写真の情報を見てみる

自分がデジカメで撮った写真のEXIFタグ情報を見てみようかと思い立った。大量に集めれば何か撮影の傾向が見えるかも?
とりあえずPythonEXIF情報を取得してみよう。

1.EXIF情報を取得するモジュール

EXIF.py プロジェクト日本語トップページ - SourceForge.JP
2008年8月のリリース以後、更新されていないので2010年に策定されたExif2.3に対応したデジカメだとうまく情報がとれないかもしれない。

Exif規格に7年ぶりの新バージョンExif 2.3 - PhotoXP


自分のデジカメは2011年1月発売のOLYMPUS PEN Lite E-PL2。まあ試してみてダメだったら考えよう。

2.EXIFを読み込み!

EXIFモジュールのprocess_file関数使用する。

> from EXIF import process_file
> fp = r'd:\sample.jpg' # EXIFタグを読みたい画像ファイルパス
> f = open(fp, 'rb')
> exifDic = process_file(f)

process_fileは以下の名前付き引数が指定できる。

名前 既定値 説明
stop_tag 'UNDEF' 出現した場合に読み込みを切り上げるタグ名を指定する
details True メーカーが独自に使っているMakerNoteタグを読み込むかどうか。
strict False タグ読み込み時にエラーが発生した場合に実行を停止するかどうか。
debug False タグ読み込み時にデバッグレベルの情報を出力するかどうか

戻り値はタグ名がkeyでEXIF.IFD_Tagのインスタンスをvalueとする辞書型となる。

> ifdTag = exifDic['Image Model'] #IFD_Tagのインスタンス
> dir(ifdTag)
['__doc__',
 '__init__',
 '__module__',
 '__repr__',
 '__str__',
 'field_length',
 'field_offset',
 'field_type',
 'printable',
 'tag',
 'values']

E-PL2のタグはdetailsにFalseを指定すると読み込むことができた。

3.サンプル画像を読み込む!

以下の関数で、フォルダ内のjpgファイルのEXIFタグ情報を一度に読めるようにする。

ExifReader.py

#cording:utf-8
import EXIF
import os
import glob

# 読み込みたくないタグは以下に指定する
excludetags = ['JPEGThumbnail','TIFFThumbnail']

def getTagValueDict(filePath):
    f = open(filePath, 'rb')
    exifTags = EXIF.process_file(f, details=False, strict=False)
    f.close()
    exifKeys = [key for key in exifTags.keys() if key not in excludetags]

    exifDict = {}
    for exifKey in exifKeys:
        exifDict[exifKey] = exifTags[exifKey].printable
    return exifDict

def getTagValueDicts(root, pattern='*.jpg'):
    files = glob.glob(os.path.join(root, pattern))
    exifDicts = {}
    for file in files:
        tags = getTagValueDict(file)
        exifDicts[os.path.basename(file)] = tags
    return exifDicts

EXIF.py プロジェクト日本語トップページ - SourceForge.JPではサンプル画像もダウンロードできるので読み込ませてみる。
デジカメで撮った画像である以下を対象とする。

Canon_40D.jpg
Canon_DIGITAL_IXUS_400.jpg
Fujifilm_FinePix6900ZOOM.jpg
Fujifilm_FinePix_E500.jpg
Kodak_CX7530.jpg
Konica_Minolta_DiMAGE_Z3.jpg
Nikon_COOLPIX_P1.jpg
Nikon_D70.jpg
Olympus_C8080WZ.jpg
Panasonic_DMC-FZ30.jpg
PC040163.JPG
Pentax_K10D.jpg
Ricoh_Caplio_RR330.jpg
Samsung_Digimax_i50_MP3.jpg
Sony_HDR-HC3.jpg
WWL_(Polaroid)_ION230.jpg

さらにE-PL2で撮った画像を一枚対象に含める。

全機種で使われているタグを調べてみる

> from ExifReader import getTagValueDicts,getTagValueDict
> rootPath = r'D:\Exif_test_images' # サンプル画像のフォルダ
> exifTagsDict = getTagValueDicts(rootPath)
> tagSets = [tagnames for dic in exifTagsDict.values() for tagnames in dic.keys()]
> distinctTags = reduce(lambda x,y: x.intersection(y) ,tagSets)
> distinctTags
set(['EXIF Flash', 'Image ExifOffset', 'Image Model', 'EXIF ColorSpace', 'EXIF DateTimeOriginal', 'Image XResolution', 'Image Make', 'Image DateTime', 'Image YResolution', 'EXIF FNumber', 'EXIF ExifImageLength', 'Image ResolutionUnit', 'EXIF ExifImageWidth'])

サンプル画像のExifバージョンを調べる

> versions = [str(v) for tags in exifTagsDict.values() for t,v in tags.iteritems() if t=="EXIF ExifVersion"]
> set(['0220', '0221', '0210'])

ちなみにE-PL2で撮った画像の結果は以下

> d = getTagValueDict(epl2FilePath)
> tagNames = sorted(d.keys())
>  for t in tagNames:
    v = d[t]
    print t,':'v

EXIF ColorSpace : sRGB
EXIF ComponentsConfiguration : YCbCr
EXIF Contrast : Normal
EXIF CustomRendered : Normal
EXIF DateTimeDigitized : 2011:12:04 12:18:44
EXIF DateTimeOriginal : 2011:12:04 12:18:44
EXIF DigitalZoomRatio : 1
EXIF ExifImageLength : 4032
EXIF ExifImageWidth : 3024
EXIF ExifVersion : 0221
EXIF ExposureBiasValue : 0
EXIF ExposureMode : Auto Exposure
EXIF ExposureProgram : Program Normal
EXIF ExposureTime : 1/500
EXIF FNumber : 71/10
EXIF FileSource : Digital Camera
EXIF Flash : Auto Off
EXIF FlashPixVersion : 0100
EXIF FocalLength : 17
EXIF GainControl : None
EXIF ISOSpeedRatings : 200
EXIF InteroperabilityOffset : 17202
EXIF LightSource : Unknown
EXIF MaxApertureValue : 761/256
EXIF MeteringMode : Pattern
EXIF Padding : []
EXIF Saturation : Normal
EXIF SceneCaptureType : Standard
EXIF Sharpness : Normal
EXIF Tag 0xEA1D : 1872
EXIF WhiteBalance : Auto
Image Artist : 
Image Copyright : 
Image DateTime : 2011:12:31 21:47:17
Image ExifOffset : 2538
Image ImageDescription : OLYMPUS DIGITAL CAMERA         
Image Make : OLYMPUS IMAGING CORP.  
Image Model : E-PL2           
Image Orientation : Horizontal (normal)
Image Padding : []
Image PrintIM : [80, 114, 105, 110, 116, 73, 77, 0, 48, 51, 48, 48, 0, 0, 37, 0, 1, 0, 20, 0, ... ]
Image ResolutionUnit : Pixels/Inch
Image Software : Microsoft Windows Photo Viewer 6.1.7600.16385
Image XResolution : 314
Image YCbCrPositioning : Co-sited
Image YResolution : 314
Thumbnail Compression : JPEG (old-style)
Thumbnail JPEGInterchangeFormat : 17864
Thumbnail JPEGInterchangeFormatLength : 5873
Thumbnail ResolutionUnit : Pixels/Inch
Thumbnail XResolution : 72
Thumbnail YResolution : 72

Qt Console でラグジュアリーな IPython

気付いてはいたんですよ、PythonのScriptsフォルダにipython-qtconsole.exeがいるのを。
ダブルクリックしても起動しないんで無視してました。

ところが、↓の記事を見て、使ってみたらとてもいいものだった!!
かっこ良くなったipython 0.11のqtconsoleを試す。: YATSTUKE BLOG

というわけでQt Console版のIPythonを使ってみる。(ほぼ元記事と内容がかぶっちゃいましたが……)

1.インストール

以下の環境を想定

OS Windows7 (x86)
Python 2.7.2
IPython 0.12
(1) PyQt4 のインストール

↓からPyQt-Py2.7-x86-gpl-4.9-1.exeを入手してインストール。
Riverbank | Software | PyQt | PyQt4 Download
とりあえずインストールタイプを"MINIMAL"にしてQt Runtimeのみ入れれば良い。

(2) pyzmq のインストール

pip install pyzmq でうまく入らなかったので早々にあきらめて↓からpyzmq-2.1.11.win32-py2.7.msiを入手して実行。
Downloads · zeromq/pyzmq · GitHub

Windows はインストーラが用意されている場合が多いのがいいね。

(3) pygments のインストール

pip install pygments でインストール。バージョン1.4が入った。

これでリッチなQt Console 生活を始める準備が整った。

2.使い方

Python インストールフォルダ配下のScriptsフォルダにあるipython-qtconsole.exeを起動。

とりあえず色々入力してみよう。

  • 入力するとimportやdefなどの予約後やモジュール名・メソッド名などが自動的にシンタックスハイライトされる!
  • 括弧にカーソルを合わせると対応する括弧が強調表示される!
  • コマンドライン引数で --pylab=inline を指定するとMatplotlibのプロットがコンソールないに表示される!
  • コピー・カット・貼り付けがCtrl + c、Ctrl + x、 Ctrl + v !
  • 画面の入力・出力した内容をhtmlファイルとして保存できる!
  • Tabキーでの候補表示でプロンプトが改行しない!
  • Ctrl + Enter で複数行の入力が可能!(履歴も複数行で出てくる)
  • タブでコンソールを複数開ける!
    • 同じセッションで開くことも、新しいセッションで開くこともできる!
  • 入力・出力内容をhtml/xhtml形式でエクスポートできる!(グラフも!)
  • 全てのマジック関数がメニュー上から実行できる!
  • なにげにチートシートを表示できるのがいいかも!

リッチすぎて目眩がする。こんなに便利でいいのか!
f:id:meganehouser:20120106005230p:image

3.フォントの変え方

デフォルトの文字がちょっと小さいと感じるなど、フォントの設定を変更したい場合は以下の通り。

(1) IPython の profile の作成

コマンドプロンプトから以下を実行する。

ipython profile create <プロフィール名>
※<プロフィール名>は任意の文字列
(2) profile の修正

(1)により以下にprofileフォルダが作成される。

C:\Users\<現在のユーザ名>\.ipython\profile_<プロフィール名>
※ XPだとDocument and Settings配下だったと思われ。

ipython_qtconsole_config.py を開いて以下の修正を行う。

213行目
# c.IPythonWidget.font_size = 0
↓コメントアウトを外して任意のサイズ値を指定
c.IPythonWidget.font_size = 12

273行目
# c.IPythonWidget.font_family = u''
↓コメントアウトを外して任意のフォント名を指定
c.IPythonWidget.font_family = u'MS Gothic'
(3) オプション引数指定

ipython-qtconsole.exe にオプション引数"--profile=<プロフィール名>"を指定して起動する。

4.まとめ

Windowsでの対話シェルはIPythonのQtConsoleが最もリッチでよさそう。
でも私の環境だと、import行でTab補完するとIPythonのカーネルから応答がなくなるけど。何でですかね。誰か助けて。