Hatena::ブログ(Diary)

(void*)Pないと このページをアンテナに追加 RSSフィード

2017-03-26 逃げ腰のラーメン

Pythonでの書式指定出力(新しいスタイル)

入門Python3 7.1.2.2


Python3からは古いスタイルよりもこの新しいスタイルの書式指定を使った方がよいとのこと。

print("hello {}! {}".format("world",10))
$ py main.py
hello world! 10

「%s」などの書き方だったのが「{}」に変わり、文字列に対して%演算子で繋げていたのがformatメソッド呼び出しに変わるといったかんじですね。


さてこの新しいスタイルでいいなと思ったのは展開対象の引数を指定できるようになったところです。

print("hello {1}! {0}".format("world",10))
$ py main.py
hello 10! world

「{0}」でformatの一つ目、「{1}」で二つ目の引数を指定できます。


formatにキーワード引数を渡した場合はそのキー名でも指定できます。

print("hello {foo}! {bar}".format(foo="FOO", bar="BAR"))
$ py main.py
hello FOO! BAR

辞書を渡して指定することもできます。

d = {"foo":"FOO", "bar":"BAR"}
print("hello {0[foo]}! {0[bar]}".format(d))
$ py main.py
hello FOO! BAR

古いスタイルのようなフォーマット指定をしたい場合はコロンで区切って指定します。

# print("hello %s! %d" % ("world",10))と同じ意味
print("hello {:s}! {:d}".format("world",10))
$ py main.py
hello world! 10

新しいスタイルの方が柔軟で便利ですね。

2017-03-25 ぜつぼきぼき

Pythonでの書式指定出力(古いスタイル)

入門Python3 7.1.2.2


Python2でも3でも使える文字列の古いスタイルの書式指定方法。C言語でいうところのprintfみたいなものですね。

print("hello %d" % 10)
$ py main.py
hello 10

文字列に%演算子で繋げると書式が展開された文字列に変換されます。

%演算子を使うのはC++のboost::formatにも似てますね。


複数の値を展開したい場合はタプルを使います

print("hello %s! %d" % ("world",10))
$ py main.py
hello world! 10

他にどういった書式が指定できるかはリファレンスで確認しておきましょう。

2017-03-24 海ぶどうを流し込みたい

引数リストのアンパック

例えば、リストやタプルの要素を個別に関数引数を渡す処理を実装したいとします。

愚直に書くと以下のようになります。

def foo(a,b,c,d):
    print(a + b + c + d)

ary = [2,4,6,8]

foo(ary[0],ary[1],ary[2],ary[3])
$ py main.py
20

いちいちary[0]とかを並べて書くのが面倒ですね、そんな時は*演算子を使って引数リストのアンパックをすることができます

def foo(a,b,c,d):
    print(a + b + c + d)

ary = [2,4,6,8]

foo(*ary) # foo(ary[0],ary[1],ary[2],ary[3])と同じ意味
$ py main.py
20

とっても便利ですね。


辞書でも同じようなことができます。辞書の場合は**演算子を使います

def foo(a,b,c,d):
    print(a + b + c + d)

h = {"a":2,"b":4,"c":6,"d":8}

foo(**h) # foo(h["a"],h["b"],h["c"],h["d"])と同じ意味
$ py main.py
20

2017-03-23 カマンベール焼き

namedtupleによる名前付きタプル

入門Python3 6.14.1


namedtupleを使うことで名前付きのタプルを作ることができます。

from collections import namedtuple

Foo = namedtuple('Foo', ('bar', 'baz'))

まずはこのコードでbarとbazのプロパティを持つFooクラスが生成されます。


次にFooオブジェクトを生成。namedtupleの第二引数に指定した順に引数を渡します。

foo = Foo(1,2)

もしくは

foo = Foo(bar=1,baz=2)

といった感じで初期化します。

これで通常のタプルのように[]演算子によるアクセスも可能だし、オブジェクトプロパティの用にアクセスも可能となります。

from collections import namedtuple

Foo = namedtuple('Foo', ('bar', 'baz'))

foo = Foo(bar=1,baz=2)

# タプルのようにアクセス
print(foo[0])
print(foo[1])

# プロパティのようにアクセス
print(foo.bar)
print(foo.baz)

# イテレータでアクセス
for item in foo:
    print(item)
$ py main.py
1
2
1
2
1
2

またタプルと同じくイミュータブルなので変更は不可です

from collections import namedtuple

Foo = namedtuple('Foo', ('bar', 'baz'))

foo = Foo(bar=1,baz=2)

foo.bar = "aaa"
$ py main.py
Traceback (most recent call last):
  File "main.py", line 8, in <module>
    foo.bar = "aaa"
AttributeError: can't set attribute

便利ですね。


もしこのFooクラスをnamedtupleを使わずに実装した場合どうなるか、試しに実装してみました。

class Foo():
    def __init__(self,bar,baz):
        self.__list = (bar,baz)
        self.__counter = 0
    
    def __getitem__(self,key):
        return self.__list[key]
    
    @property
    def bar(self):
        return self.__list[0]
    
    @property
    def baz(self):
        return self.__list[1]
    
    def __iter__(self):
        self.__counter = 0
        return self
    
    def __next__(self):
        self.__counter += 1
        
        if ( self.__counter > len(self.__list) ):
            raise StopIteration
        
        return self.__list[self.__counter - 1]

こんな感じになりました。

実際にはnamedtupleはもっと多機能なので、こんなコード毎回書いてられないですね。活用しましょう。

2017-03-22 モダン焼きくらいモダン

Pythonで独自クラスで配列をエミュレートしてみる

今回は[]演算子によるアクセスと、forループのみを実装してみます。

配列のエミュレートをするには特殊メソッドを使います。

まずは[]演算子の実装

__getitem__で[]演算子で値を取り出す時の処理をエミュレートできます

class Foo():
    def __getitem__(self,key):
        return key * 2

foo = Foo()
print(foo[0])
print(foo[1])
print(foo[2])
$ py main.py
0
2
4

__setitem__で[]演算子で値を設定する時の処理をエミュレートできます

class Foo():
    def __setitem__(self,key,value):
        print(key,value)

foo = Foo()
foo[2] = 10
$ py main.py
2 10

forループのエミュレートは__iter__を用意し、そこでイテレータオブジェクトを返す必要があります。

そしてイテレータオブジェクトには__next__を実装しておく必要があります。

例として指定した数までカウントするイテレータを実装してみます。

class Foo():
    def __init__(self,max_counter):
        self.__max_counter = max_counter
        self.__counter = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        self.__counter += 1
        if self.__counter > self.__max_counter:
            self.__counter = 0
            raise StopIteration
        return self.__counter

foo = Foo(10)

for item in foo:
    print(item)
$ py main.py
1
2
3
4
5
6
7
8
9
10

ループを終了させるにはStopIterationという例外を発生させる必要があります。


配列のエミュレートには他にもたくさんの特殊メソッドを実装する必要があります。

独自クラスで真面目にやるとかなり大変ですね。