Change in Python3

Y901x を Python3 化してみた。
Python3 って pyc キャッシュは __pycache__ ディレクトリに入るのね。

言語としての一貫性を重視したPython 3の進化 ? @IT

Y901x は gir 以外は sys, os, time の標準モジュールしか使っていない。
多分文字列と割り算さえ気を付ければそれほど変更点は無いだろう。

Python3 はデフォルトが UTF-8 なので coding 指定が不要に。
これで海外の Python 製アプリの動作が変という場合は減ると思う。

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

to

#!/usr/bin/env python3

例外はカンマから as に変わり raise も関数(?)になった。

#except Exception, e:
except Exception as e:

#raise ValueError, "hoge"
raise ValueError("hoge")

忘れちゃいけない unicode 関数を使っていた部分は str にして。

#s = unicode(entry.get_text()) # Python2
s = entry.get_text()
i = s.rindex(".")

割り算で整数にならないと困る部分は / を // に書き換えて。
/= も //= にしないといけないのか。
逆に float にキャストしていた部分はキャストを外して。

Python 歴があるなら誰でも知っていることはこれくらいで。

他 Fedora 19 の gir を色々試してみると
GLib.filename_from_uri 関数の動作が Ubuntu 13.04 と同じになった。
Gio.ApplicationFlags.HANDLES_OPEN も使えるようになった。

しかし Gio.ActionEntry が作れず ApplicationMenu は使えないまま。
使えるなら多重起動防止の設定を追加しようと思ったけどまだムリっぽい。
pygobject のバージョンに今後も振り回されるんだろうな。

今頃気が付いたけど inifile8.py に古いものを使っていた。
Python3 互換の文字列フォーマッタ版を随分前に作ったのにアホだ。

思ったより簡単だと変更していたけど問題は文字列や割り算ではなかった。
自然順ソートを行う numsort.py だった。

Python3 には cmp 関数が無い、いやコレの自作だけなら簡単だけど。
sort(), sorted() の引数が違う、てか比較関数が使えない。

ソート HOW TO ? Python 3.3 documentation

自力でクイックソートを作るか cmp_to_key をコピペするかだね。
cmp_to_key 関数を使うとなるとこんな感じでいいようです。

#! /usr/bin/env python3

from gi.repository import GLib, Gio

def sort_func(str1, str2):
    """
        str1.encode("utf8") is not required.
        Not 'cmp' function in Python3
    """
    cmpstr1 = GLib.utf8_collate_key_for_filename(str1, -1)
    cmpstr2 = GLib.utf8_collate_key_for_filename(str2, -1)
    # cmp function
    if cmpstr1 < cmpstr2:
        return -1
    elif cmpstr1 > cmpstr2:
        return 1
    return 0

def cmp_to_key(mycmp):
    """
        http://docs.python.org/3.3/howto/sorting.html # en
        http://docs.python.jp/3.3/howto/sorting.html # Japanese
        Convert a cmp= function into a key= function
    """
    class K(object):
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

def get_file_numsort_list(dirname):
    """
        param dirname: Directory Full Path Name
        return: List in Numeric Order
    """
    files = []
    d = Gio.file_new_for_path(dirname)
    enum = d.enumerate_children(
            Gio.FILE_ATTRIBUTE_STANDARD_TYPE,
            Gio.FileQueryInfoFlags.NONE,
            None )
    for info in enum:
        if info.get_file_type() == Gio.FileType.REGULAR:
            s = info.get_name()
            if not s.startswith("."):
                if not s.endswith("~"):
                    files.append(s)
    # Python2
    #files.sort(lambda x, y : cmp(GLib.utf8_collate_key_for_filename(x, -1), 
    #            GLib.utf8_collate_key_for_filename(y, -1)))
    #
    # Python3
    files.sort(key=cmp_to_key(sort_func))
    return files

これじゃラムダ式にできない、別にいいけど。
随分コードが長くなってしまったけどアプリケーションは動けばいいのさ。
アーカイブサイズが減った理由がワカラナイ…

GLib.utf8_collate_key_for_filename は str のままイケた。
GLib で文字列として扱う場合は UTF-8 で得られるということみたい。
でも Python 文字列として扱う場合は UCS-4 であるのを意識する必用あり。
でいいのだろうか、いつか落とし穴にはまりそうな気もする。

ついでに PyGI で今更気が付いたこと。

class CToolBox(Gtk.Box):
    def __init__(self):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

GtkBox は GtkOrientable をインプリメントしているから orientation property がある。
なのでこの指定で GtkBox のサブクラスを作れば GtkVBox と同様になる。
いやプロパティは全部 __init__ の引数にできるのを知ったのは最近だし。

y901x101

とりあえず Python3 化した Y901x 1.0.1 公開。
memopoli の更新をやるべきなんだろうけど、実はもう使っていないのだがどうしよう。

1.0.1 Download (34.0kb)

blog にもリンクを今回から貼ることにする。
需要は無いだろうけど何かの参考になればいいや。