Programming」カテゴリーアーカイブ

Python IniFile Read and Write

前々回 Python の True, False は整数と書いたけど
そういえば isinstance() は?

bool is instance of int in Python – Peterbe.com (Peter Bengtsson on Python, Zope, Kung Fu, London and photos)

やっぱりそうなるか。
他にオブジェクトのタイプを正確に調べるには…

How to compare type of an object in Python? – Stack Overflow

こんなに色々タイプ比較方法があったんだ、めもめも。
でも速度はどうなるんだろう?

import time

t = 100000

s0 = time.time()
for i in range(t):
    isinstance(i, int)
print time.time() - s0

s1 = time.time()
for i in range(t):
    type(i) is int
print time.time() - s1

s2 = time.time()
for i in range(t):
    "%d" % i
print time.time() - s2

結果

0.0666399002075
0.0661001205444
0.157742977142

変わらないや、一応試した文字列変換可能かどうかでは遅すぎるかやはり。

設定読み書きクラスを自作する

私が以前自分で書いたコレもサル丸出しだなと。
とにかく type() がいいみたいなので現行版をベースに作りかえてみる。

とはいえもはや SeeMe で使っているのは原型を留めていないのであるが…
ついでにアトリビュートには直接アクセスできないようにとか % 演算子に変更とか…

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

ERROR_READ = 'Configuration file READ ERROR\n[%s]\n%s=\nvalue is not %s'
ERROR_WRITE = 'Configuration file WRITE ERROR\n(%s, %s) value is not %s'
ERROR_HEADER = 'Configuration file header value is not str'

import os

class InifileBase():
    """
        This class is Inheritance Base
    """
    def __init__(self, filename):
        """
            Attribute is the file name only
        """
        self._filename = filename

    def _get_value(self, section, key):
        """
            This Methods is Inheritance Base
        """
        return None

    def read_int(self, section, key, default):
        """
            @param default: int.
        """
        result = self._get_value(section, key)
        if result == None:
            return default
        try:
            return int(result)
        except:
            raise ValueError, ERROR_READ % (section, key, "int")
    
    def read_float(self, section, key, default):
        """
            @param default: float.
        """
        result = self._get_value(section, key)
        if result == None:
            return default
        try:
            return float(result)
        except:
            raise ValueError, ERROR_READ % (section, key, "float")
    
    def read_bool(self, section, key, default):
        """
            @param default: bool.
        """
        result = self._get_value(section, key)
        if result == None:
            return default
        if result == "1" or result == "-1":
            return True
        elif result == "0":
            return False
        else:
            raise ValueError, ERROR_READ % (section, key, "bool")
    
    def read_str(self, section, key, default):
        """
            @param default: str.
        """
        result = self._get_value(section, key)
        if result == None:
            return default
        return result


class InifileReader(InifileBase):
    """
        This class is read-only
        ini files to load faster
    """
    def __init__(self, filename):
        """
            @param filename: the full path name.
        """
        InifileBase.__init__(self, filename)

    def _get_value(self, section, key):
        """
            Read using the file stream
        """
        if os.path.exists(self._filename):
            section_in = False
            f = open(self._filename)
            try:
                for linenn in f:
                    line = linenn.strip()
                    if line == "":
                        continue
                    if section_in:
                        if "=" in line:
                            pos = line.index("=")
                            if key == line[:pos]:
                                return line[pos+1:]
                        if len(line) > 2 and line[0] =="[" and line[-1] == "]":
                            return None
                    if len(line) > 2 and line[0] =="[" and line[-1] == "]":
                        if section == line[1:-1]:
                            section_in = True
            finally:
                f.close()
        return None


class Inifile(InifileBase):
    """
        ini file to read and write class.
    """
    def __init__(self, filename):
        """
            Loading degradation inifile
            @param filename: the full path name.
        """
        InifileBase.__init__(self, filename)
        self._header = ""
        self._ini = []
        if os.path.exists(filename):
            f = open(filename)
            x = f.read()
            f.close()
            lines = x.split("\n")
            section = ""
            for line in lines:
                if line == "":
                    continue
                if len(line) > 2 and line[0] =="[" and line[-1] == "]":
                    section = line[1:-1]
                elif section == "":
                    pass # Nothing
                elif "=" in line:
                    pos = line.index("=")
                    self._add(section, line[:pos], line[pos+1:])
    
    def _add(self, section, key, value):
        """
            Add to contents.
        """
        for dic1 in self._ini:
            if section in dic1.keys():
                for dic2 in dic1[section]:
                    if key in dic2.keys():
                        dic2[key] = value
                        return
                dic1[section].append({key: value})
                return
        self._ini.append({section: [{key: value}]})
    
    def _get_value(self, section, key):
        """
            Get to contents.
        """
        for dic1 in self._ini:
            if section in dic1.keys():
                for dic2 in dic1[section]:
                    if key in dic2.keys():
                        return dic2[key]
        return None
    
    def save(self):
        """
            Save the contents.
        """
        s = ""
        if self._header:
            s += self._header
        for dic1 in self._ini:
            for section in dic1.keys():
                s += "[%s]\n" % section
                for dic2 in dic1[section]:
                    for key in dic2.keys():
                        s += "%s=%s\n" % (key, dic2[key])
                s += "\n"
        if s != "":
            f = open(self._filename, "w")
            f.write(s)
            f.close()

    def add_header(self, header):
        """
            @param headre: str.
        """
        if type(header) is str:
            self._header = header
        else:
            raise ValueError, ERROR_HEADER

    def section_exists(self, section):
        """
            Check existence of section.
        """
        for dic1 in self._ini:
            if section in dic1.keys():
                return True
        return False
    
    def erase_section(self, section):
        """
            Remove the specified section.
        """
        for dic1 in self._ini:
            if section in dic1.keys():
                dic1.pop(section)
                return True
        return False

    def erase_key(self, section, key):
        """
            Erase Key
        """
        for dic1 in self._ini:
            if section in dic1.keys():
                for dic2 in dic1[section]:
                    if key in dic2.keys():
                        dic2.pop(key)
                        return True
        return False

    def write_int(self, section, key, value):
        """
            @param value: int.
        """
        if type(value) is int:
            self._add(section, key, str(value))
        else:
            raise ValueError, ERROR_WRITE % (section, key, "int")
    
    def write_float(self, section, key, value):
        """
            @param value: float.
        """
        if type(value) is float:
            self._add(section, key, str(value))
        else:
            raise ValueError, ERROR_WRITE % (section, key, "float")
    
    def write_bool(self, section, key, value):
        """
            @param value: bool.
        """
        if type(value) is bool:
            if value:
                self._add(section, key, "1")
            else:
                self._add(section, key, "0")
        else:
            raise ValueError, ERROR_WRITE % (section, key, "bool")
    
    def write_str(self, section, key, value):
        """
            @param value: str.
        """
        if type(value) is str:
            self._add(section, key, value)
        else:
            raise ValueError, ERROR_WRITE % (section, key, "str")

継承使っているし、こうなると初心者は見ても意味解らないかも。
Y901x と SeeMe に使うのはこれでいいとして、覚書ページはどうするか…
てかあそこに書いた方法では今では動画再生できなくなったと解っているんだが。

IronPython True False

Python の True, False は変数みたいなものであるのは有名。
True が 1、False が 0 な整数という解釈でいいのかな。

>>>True + True
2
>>>True + False
1

まてよ、IronPython ではどうなのかな?
CTS により .NET の型にマッピングされなければいけないはずなんだが。

と思ったので少し試したけど整数等と同じ、つまり普段は Python の型である。
clr か System を import すると「どっちでもいい」オブジェクトに変身する。

>>>import System
>>>System.Boolean.Parse("true") == True
True
>>>True + True + True
3

又、変数?なので

>>> True = "abcde"
>>> True
'abcde'
>>> True + True
'abcdeabcde'
>>> System.Boolean.Parse("true") == True
False
>>> 2 == 2
True

真ならやはり True が戻ってくるけど中身は文字列というワケワカなことにも。
ま、普通は True や False に代入するはずがないから気にしなくてもいいんだが。

ついでに、どこかで null は IntPtr.Zero だとか見かけたけど

全然違う、None で大抵イケるはずだが None のマッピングは何だろう?

C 言語で文字列メンドクサイ

最近の Linux なら locale は ja_JP.UTF-8 でイケるようだ。

scanf – Wikipedia
scanf ってこんなに面倒だったかなぁ…
gets だと思いっきり警告だし。

wchar_t って Linux では 4 バイトなんだね。
Windows つか Visual Studio では 2 バイトなのですけど。

最近の Windows SDK のようにセキュリティ関数が存在してくれないと怖いなぁ…
文字列処理って簡単にバッファオーバーランが起こせるからね。
malloc で動的処理すればなんとかなりそうだけど std::string のほうが(略

日本語の文字数カウントとかをするには UNICODE にするのが一番なわけで。
とりあえずバッファオーバーラン等を考慮しないでうまくいったコード。

#include <stdio.h>
#include <stddef.h>
#include <locale.h>
#include <string.h>

int 
main (int argc, char *argv[])
{
    /* set locale */
    setlocale( LC_CTYPE, "ja_JP.UTF-8" );

    /* おまけ、変数バイト数チェック */
    printf("int     サイズ = %d\n", sizeof(int));
    printf("char    サイズ = %d\n", sizeof(char));
    printf("wchar_t サイズ = %d\n", sizeof(wchar_t));

    /* バッファ */
    char cin[256];
    wchar_t s[256 * 4];
    char c[4] = {0};

    /* 何か入力させる */
    printf("何か文字列を入力して Enter\n");
    scanf("%s", cin);

    /* UNICODE に変換 */
    const char *cc = cin;
    size_t t = mbsrtowcs(s, &cc, strlen(cc), NULL);
    printf("文字数は %d です\n", t);

    /* 一文字ずつ書き出ししてみる */
    int i=0;
    for (i; i<t; i++)
    {
        wctomb(c, s[i]);
        printf("%s\n", c);
    }
    return 0;
}

あーくそ!Python ならたったコレだけ、import も無しで同じことができるんだが。

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

s = raw_input("何か文字列を入力して Enter\n")
u = unicode(s, "utf8")
print "文字数は %d です" % len(u)
for c in u:
    print c.encode("utf8")

しかもバッファオーバーランの心配は無いと思うし。

※追記、GLib を使えば簡単だった
gunichar | PaePoi

クライアント領域のサイズ

GetWindowRect とか自分で書いて思い出したので書いておこう。
Windows の SDK を含む GUI ツールキットと Linux での GTK+ のサイズについて。
とりあえず全部 300×300 サイズなウインドウを作ってみる

SDK

hWnd = CreateWindow(
    szWindowClass,
    szTitle,
    WS_OVERLAPPEDWINDOW, 
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    300, // Width
    300, // Height
    NULL,
    NULL,
    hInstance,
    NULL);

WindowsForm

WPF

<Window x:Class="_wpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        
    </Grid>
</Window>

PyGtk (Linux)

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

import gtk

class Template(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        self.connect("delete-event", gtk.main_quit)
        self.resize(300, 300)
        self.show_all()

if __name__ == "__main__":
    w = Template()
    gtk.main()

MFC や Qt は知らない、MFC は SDK と結果は同じになるはずだが。
とにかく結果、Windows の画像は VirtualBox ose 上である。

GTK+ はクライアント領域のサイズ、Windows は全部が全体サイズです。
いやいや、Windows は WPF になってもまだデフォルトは外枠を含んだサイズなんですね。
よく見るとメニューさえクライアント領域に食い込んで含まれてしまうのが解る。

Windows でクライアント領域のサイズを指定するには

SDK の場合
AdjustWindowRectEx 関数を使うか GetClientRect との差を自力計算する。

WindowsForm の場合

this.ClientSize = new Size(300, 300);

WPF の場合
SizeToContent を WidthAndHeight に指定し 300×300 のコンテンツを入れる。

何故クライアント領域のサイズがどうだというと。
メニューやツールバー、ステータスバーなんかも当然クライアント領域内に食い込む。
画像ビューアや動画プレイヤーを作る場合は当然実寸で表示したくなるよね。
そうするとメニューやステータスバーのサイズまで計算し加算しなくてはいけないハメに…
ちなみに私の作った Cinema はそうやっている、ステータスバーは面倒で付けなかった。

コンテンツのサイズでクライアント領域サイズを決めたほうがイイに決まっている。
本当に GTK+ や WPF のレイアウタって神ですよ。

SDK はしかたがないとして WindowsForm はどうなんだ?ですよね。
WPF は古い考え方をブチ壊したのだから最初からクライアントサイズにすればいいのに。

structure

ネタを何にしようか困っていたけどドコかの誰かにヒントをもらったので構造体を。

構造体は何気に便利です。
単純に「入れ物」として使うだけでもありがたい言語仕様である。

たとえば WindowsSDK には RECT 構造体が define されている。
RECT 構造体

コレを Linux で利用するには自身で定義するだけ。
LONG なんて Linux では当然定義されていないので int か long で全置換。

#include <stdio.h>
#include <string.h>

typedef struct tagRECT { 
    int left;
    int top;
    int right;
    int bottom;
} RECT;

int main(int argc, char *argv[])
{
    RECT rc = {10, 10, 320, 240};
    
    printf("x=%d, y=%d, width=%d, height=%d\n", rc.left, rc.top,
        rc.right - rc.left, rc.bottom - rc.top);
    return 0;
}

後はこの rc という変数の要素がウインドウのサイズ情報なのだと理解しやすい。
他のデータは他の構造体でまとめる、内部で利用する情報はまとめたほうが整理しやすい。
ソレのドコが便利なのかはメモリ内に保存するデータが多くなると実感するよ。
実際にアプリを作っているといつのまにかトンデモネェ数になってしまうから。

たとえば私の作った Y901x でのアトリビュートや Cinema の public 変数中身の数を見て呆れてくれ。
実際にアプリを作ったことが無い人には解らないかもだけどコレでも少ないほうだ。

それだけならたいして便利では無いのですけど。
Windows で GUI アプリを本当に作っている人なら GetWindowRect 関数を使ったことが無い人はいない。
と思うけどどうなのだろう。
GetWindowRect 関数

そう、この関数に RECT 構造体のポインタを渡せばウインドウ外観のサイズ情報は一度で取得できる。

void hoge(HWND hWnd)
{
    RECT rc;
	GetWindowRect(hWnd, &rc);
	/* サイズに関する何かの処理 */

つまり構造体のポインタを渡すだけで多数の情報を一度でゲットできる関数を作れば後々で楽。
C# 言語なんて仕様でソレを駆使している感じ、GC なので戻り値で済ませるように作っているけど。
おかげで型がアホみたく多い言語になってしまったのは何ともいえん、バランスって難しい。

とにかく、後々サイズ大きくなりそうなアプリを作るなら構造体の利用方法を覚えたほうがいい。
というか class の利用方法を覚えるのに必須の知識ですので。