Python/メモ

文字列reverse

文字列をreverseしてみます。

# coding: sjis

for s in [u"こんにちは世界", u"Hello世界", u"こんにちはworld"]:
  print "".join(reversed(s))

実行結果です。

> python a.py
界世はちにんこ
界世olleH
dlrowはちにんこ

ジェネレータは使い捨て

>>> g = (x for x in range(5))      # ジェネレータ作成
>>> list(g)                        # リストを作る
[0, 1, 2, 3, 4]
>>> sum(g)                         # sumを得る
0                                  # 10じゃないの?
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration                      # おっと、いけない。既にお尻にきてたのだった
>>> sum(x for x in range(5))
10

自己言及的スクリプト

結城さんの『結城 浩のPerlクイズ』のp.25に「自己言及的スクリプト」というのがあります。実行するとスクリプトの内容と同じ文字列が表示されるスクリプトです。それをPythonで書いてみました。

x = ';print "x = %s%s" % (foo(x), x)';print "x = %s%s" % (foo(x), x)

うまくかけなかったので、fooという関数を使ってしまいました。

def foo(a):
  return "'%s'" % a

追記:reprが使えました。

x = ';print "x = %s%s" % (repr(x), x)';print "x = %s%s" % (repr(x), x)

さらに追記:バッククオートも使えました。

x = ';print "x = %s%s" % (`x`, x)';print "x = %s%s" % (`x`, x)

バッククオート内に書かれた式(のリスト)は、そのオブジェクトに対応する文字列に変換されます。

lambdaでタプルを返す

lambda でタプルを返そうと思い、次のように書きましたがエラーになります。

>>> a = (lambda x: x, x)(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'x' is not defined

これは、

a = ((lambda x: x), x)(10)

という風に解釈されます。エラーメッセージが分かりにくいので、x のところを例えば 1 にしてみると、

>>> a = (lambda x: x, 1)(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'tuple' object is not callable

タプルが生成されて、それに対して () で呼び出しをしようとしているのが分かります。

返したいタプルをちゃんと括弧で囲めば問題ありません。

>>> a = (lambda x: (x, x))(10)
>>> a
(10, 10)

iter

>>> it = iter([1, 2, 3])
>>> it.next()
1
>>> it.next()
2
>>> it.next()
3
>>> it.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration
>>> it = iter({ 1: 2, 3: 4 })
>>> it.next()
1
>>> it.next()
3
>>> it.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration

__call__

"インスタンス()" とすると、__call__ メソッドが呼び出されます。

>>> class Counter:
...   def __init__(self, n=0):
...     self.n = n
...   def __call__(self):
...     self.n += 1
...     return self.n
...
>>> counter = Counter()
>>> counter()
1
>>> counter()
2
>>> counter()
3
>>> counter2 = Counter(10)
>>> counter2()
11
>>> counter2()
12

文字列フォーマットにディクショナリを使う

% 演算子の右側にディクショナリを指定して、変換指定子の % の後に '(hoge)' のように括弧でディクショナリのキー(文字列)を指定できます。

>>> d = { "foo": "Hello", "bar": "World" }
>>> "%(foo)s %(bar)s" % d
'Hello World'

lst.reverse() の意味

dis モジュールを使うと Python バイトコードを逆アセンブル出来ます。

>>> def foo():
...   lst.reverse()
...
>>> import dis
>>> dis.dis(foo)
  2           0 LOAD_GLOBAL              0 (lst)
              3 LOAD_ATTR                1 (reverse)
              6 CALL_FUNCTION            0
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

これを見ると 'lst.reverse()' とは lst の reverse 属性を取り出し、それを呼び出しているのが分かります。なので次のような書き方も出来ます。

>>> lst = []
>>> append = lst.append
>>> lst
[]
>>> append(12)
>>> lst
[12]

ジェネレータ

ジェネレータは名前のとおり値を生み出します。yieldに渡される値が、生み出される値になります。

>>> def foo(): # 10を生み出すジェネレータ
...   yield 10
...
>>> g = foo()
>>> g.next()
10
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration

generatorに対しnextメソッドで生み出された値を取得できます。nextメソッドを呼び出したときに、もう値がないならStopIteration例外が生成されます。

>>> def bar(n): # n,n+1,n+2を生み出すジェネレータ
...   yield n
...   yield n+1
...   yield n+2
...
>>> g = bar(10)
>>> g.next()
10
>>> g.next()
11
>>> g.next()
12
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration
>>> list(bar(5))
[5, 6, 7]

範囲テスト

「1 < x and x < 4」は「1 < x < 4」と書けます。

>>> 1 < 2 < 3
True
>>> 1 < 5 < 3
False
>>> x = 10
>>> 1 < x < 10
False
>>> 1 < x < 90
True

foo がクラス Foo のインスタンスかを調べるには isinstance を使う

class Foo: 
  pass

class Bar:
  pass

>>> isinstance(Foo(), Foo)
True
>>> isinstance(Bar(), Foo)
False

また、オブジェクトの同一性を調べるには is を使います。type を使うと、それがインスタンスなのか、クラスオブジェクトなのか等を調べる事が出来ます。

>>> type(Foo())
<type 'instance'>
>>> type(Foo)
<type 'classobj'>
>>> foo, bar = Foo(), Foo()
>>> foo is bar
False
>>> type(foo) is type(bar)
True

キーワード引数

引数名によって値を対応付けてくれます。

def foo(a, b):
  print a, b
 >>> foo(1, 2)
 1 2
 >>> foo(a=10, b=3)
 10 3
 >>> foo(b=2, a=8)
 8 2
 >>> foo(a=1, 4)
 SyntaxError: non-keyword arg after keyword arg
 >>> foo(2, b=1)
 2 1
 >>> foo(3, c=9)
 TypeError: foo() got an unexpected keyword argument 'c'

値を返す時は必ず return を使う

returnがなければ、関数からNone返されます。

>>> def bad():
...   10
...
>>> r = bad()
>>> type(r)
<type 'NoneType'>

デフォルト引数は一度しか評価されない

リファレンスマニュアルによると:

デフォルトパラメタ値は関数定義を実行する際に値評価されます。 これは、デフォルトパラメタの式は関数を定義するときにただ一度だけ評価され、同じ ``計算済みの'' 値が全ての呼び出しで使われることを意味します。
>>> def foo(a=[]):
...   print len(a)
...   a.append(1)
...
>>> foo()
0
>>> foo()
1
>>> foo()
2

lambda に文は書けない

lambda は式のみ。

>>> lambda x: if x > 0: return 5
  File "<stdin>", line 1
    lambda x: if x > 0: return 5
              ^
SyntaxError: invalid syntax

Python ページ