LazyLife@Diary

[NetHack] [EM] [FHS] [Spork] [UNH]
[Xang] [変愚] [Tiny]

Web site: Lazy Life.
antenna side: LazyLife@Antenna
Twitter side: @dplusplus
Tumblr side: LazyLife@Tumblr
 | 

2010-01-26

[]Python基礎文法最速マスター

↓に便乗してPython版も書いてみました。

ほとんど上記の記事と同じような内容で書いたのでPython入門記事としては色々抜けていたりしますがご了承ください。


Pythonは現在3.x系がリリースされていますが本記事では基本的にPython2.6について書きます。

参考文献:


0. 対話環境として使う

対話環境

pythonはそのまま実行すると対話環境として働きます。

% python
(中略)
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'hello'
hello
>>> 1 + 2
3

help()に関数やその他のオブジェクトを渡すことでヘルプが(あれば)見られます。qをタイプするとヘルプを抜けます。

>>> help(1)
Help on int object:

class int(object)
 |  int(x[, base]) -> integer
(以下略)

dir()にオブジェクトを渡すことでオブジェクトの属性名一覧が返されます。

>>> dir(1)
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'conjugate', 'denominator', 'imag', 'numerator', 'real']

どんな関数があるかを調べるのに使ったりしますが、標準のままではだいぶ見辛いので外部モジュールのseeの導入をおすすめします。


type()でオブジェクトの型を調べます。

>>> type('hoge')
<type 'str'>

暗黙の変数 _ に一つ前に入力した式の結果が代入されます。

>>> 1 + 2
3
>>> _ + 10
13
>>> result = _ + 100
>>> _
13 # 代入文では _ の値は更新されない

exit()を呼び出すと終了します。Ctrl-Dでもいいですが端末によるかもしれません。

より高機能なpython対話環境としてIPythonやJupyterがありますがここでは説明を省略します。

0.5. プログラムの文字コード

最近の環境ではUTF-8あたりに統一した方がよさそうです。

ファイルの1行目か2行目に

# -*- coding: UTF-8 -*-

とすることでプログラムの文字コードを指定します。これが無いと日本語のコメント文字列リテラルを使った際にエラーが出ます。

もちろん、必要があればUTF-8以外を指定することもできます。

1. 基礎

ライブラリのインポート
import math

#mathモジュールの要素を使う
print math.pi # 3.141592653589793

import文で標準ライブラリや外部のライブラリを読み込みます。

指定した名前のライブラリが無い場合はImportError例外が発生します。


from形式を用いてローカルスコープにコピーすることもできます。同時に別名を付けることもできます。

from math import e
print e # 2.718281828459045
from math import e as napiers_constant
print napiers_constant # 同様
from math import * # 全部コピー(作法としてはよろしくないかも)
print文

print文です。自動的に末尾に改行が付加されます。

カンマで区切って複数いっぺんに出力もできます。この場合、間に半角空白が挿入されます。

print 'Hello world'
print 'hoge', 'moge', 'fuga'
print >>sys.stderr, 'nurupo' #標準エラー出力

※Python3系では、printは文(statement)ではなく組み込み関数になりました。

# Python3
print('Hello world')
print('hoge', 'moge', 'fuga')
print('nurupo', file=sys.stderr) #標準エラー出力
入力
raw_input()
input()

raw_input()は入力された文字列をそのまま返します。

input()はeval(raw_input())と等価であり、入力文字列をPythonの式として解釈した結果を返すため、入力文字列が信頼できない状況では使ってはいけません。(参考→Wikipedia.ja:eval#セキュリティ上のリスク)

※Python3系ではinput()が2系のraw_input()相当となり、raw_input()は廃止されました。

コメント

一行コメントです。#から行末までがコメントアウトされます。

# コメント

複数行コメントのかわりとして3重クオート文字列を使う場合があります。後述。

    """
    複数行
    コメント
    """
変数の宣言

Pythonには変数の宣言はありません。変数に代入する型も制限されません。

a = 1
a = 'hoge' # aを上書き
スクリプトの実行
% python hoge.py
ワンライナー実行
% python -c "print 'Hello'"
バージョンの確認
% python -V # あるいは --versionオプション

2. 数値

整数小数複素数が使えます。末尾にjを付与すると虚数を表します。

num = 1
num = 3.14
num = 1 + 1j
各種演算
num = 1 + 1    # 2 
num = 1 - 1    # 0
num = 1 * 2    # 2
num = 5 / 2    # 2 (整数どうしの除算は整数に切り捨てられる)
num = 5.0 / 2  # 2.5 (どちらかが小数なら結果も小数)
num = 5 % 2    # 1 (剰余をとる)
num = 2 ** 3   # 8 (累乗)

python3では整数/整数の演算も小数が帰ってくるようになりました。

従来の整数に切り捨てる演算がしたいときは//演算子を使いましょう。(//演算子はpython2.6〜でも使えます)

# python3
5 / 2 # 2.5
5 // 2 # 2
インクリメントとデクリメント

Pythonには++演算子がないので、+=や-=を使います。

i += 1
i -= 1
論理演算

Pythonの論理演算は以下のとおりです。orやandはTrue/Falseを返すわけではないことに注意。

x or y  # x が偽なら y 、そうでなければ x
x and y # x が偽なら x 、そうでなければ y
not x   # x が偽なら True 、そうでなければ False

3. 文字列

文字列の表現

通常の文字列はシングルクォートかダブルクォートで囲みます。

また、'''〜'''、"""〜"""で複数行にわたる文字列を構成できます。クォートに囲まれている範囲では改行がそのまま扱われます。

str1 = 'abc'
str2 = "def"
str3 = '''ghi
jkl
mno'''

3重クォート文字列を変数に代入せずに記述し、複数行コメントのようにして使うこともあります。

    """
    複数行
    コメント
    """

C言語でいうところのsprintf的な操作は%演算子、あるいはformat()関数で行います。

str4 = '%s def' % str1              # 'abc def'
str5 = '%s %s' % (str1, str2)       # 'abc def'
str6 = '{1} {0}'.format(str1, str2) # 'def abc'
文字列操作

各種文字操作です。

# 結合
join1 = 'hoge' + 'moge' # 'hogemoge'
join2 = ','.join(['aaa', 'bbb', 'ccc']) # 'aaa,bbb,ccc'

# 分割
record1 = 'aaa bbb  ccc'.split() # ['aaa', 'bbb', 'ccc'] デフォルトでは空白で分割
record2 = 'aaa,bbb,ccc'.split(',') # ['aaa', 'bbb', 'ccc']

# 長さ(文字数)
length = len('Supercalifragilisticexpialidocious') # 34

# 切り出し
# [start:stop]の形で指定して切り出す
substr1 = '0123456789'[:3]  # '012'  0〜stop-1を切り出す
substr2 = '0123456789'[3:6] # '345'  start〜stop-1を切り出す
substr3 = '0123456789'[6:]  # '6789' start〜末尾を切り出す

# 検索
result = 'abcd'.find('cd') # 見つかった場合はその位置、見つからなかった場合は-1が返る

4. リスト、タプル

リスト
言語でいう配列のような型です。要素としてどんな型のものでも含むことができます。
タプル
「オブジェクトの組」という点ではリストに似ていますが、要素の追加や削除はできません。関数から複数の値を返したいとき等に多用されます。
# 空リストの作成
list1 = []
list2 = list()
# 複数要素からなるリストを作成
list3 = [0, 1, 2]
# 他のリストの(浅い)コピーを作成
list4 = list(list3)
# 連番のリストを作成 
list5 = range(3) # [0, 1, 2] range(stop)は[0, 1, ..., stop-1]を返す
list6 = range(3, 6) # [3, 4, 5] range(start, stop)は[start, start+1, ..., stop-1]を返す
list7 = range(1, 8, 2) # [1, 3, 5, 7] 3番目の引数で値の増減量を指定できる

# 空タプルの作成
tuple1 = ()
tuple2 = tuple()
# 要素が1つのタプルの作成
tuple3 = (1,)
# 複数要素からなるタプルを作成
tuple4 = (0, '1', 2, [3], -4)
要素の参照と代入

リスト、タプルは0から始まる添字で要素を参照できます。また、タプルは要素を新たに代入できません。

# 要素の参照
list2[1] # 1
list2[-1] # 2 インデックスに負数を指定することで後ろから辿れる
tuple4[2] # 2

# 要素の代入
list2[0] = 100
tuple4[0] = 1 # エラー
タプル/リストの要素数
len(list3) # 5
len(tuple4) # 5
リストの操作
array = [1, 2, 3, 4]

# 任意の要素を取り出す
first = array.pop(0) # first == 1, array == [2, 3, 4]
# 任意の要素を追加する
array.insert(0, 5) # array == [5, 2, 3]
# 末尾を取り出す
last = array.pop() # last == 3, array = [5, 2]
# 末尾に追加
array.append(9) # array == [5, 2, 9]
# 末尾にリストを追加
array.extend([0, 1]) # array == [5, 2, 9, 0, 1]

5. ディクショナリ

他の言語でハッシュ連想配列マップ等と呼ばれているものと似たようなものです。

ディクショナリのキーには、数値、文字列、タプルをはじめとした不変オブジェクトが指定できます。

dic = {} # 空ディクショナリ
dic = dict() # 空ディクショナリその2
dic = {'a': 1, 'b': 2} # key:value, ... の形式で初期化
dic = dict(a=1, b=2) # キーワード引数による初期化
ディクショナリの要素の参照と代入
# 要素の参照
dic['a'] # 1

# 要素の代入
dic['a'] = 100
dic['c'] = 42
ディクショナリに関する関数
# キーの取得
dic.keys() # ['a', 'c', 'b'] (辞書式順や追加順に並ぶとは限らない)
# 値の取得
dic.values()
# キーの存在確認
'a' in dic # True
# ハッシュのキーの削除
del dic['a']

6. 制御文

Pythonは一般的なプログラミング言語と異なり、タブやスペースによるインデント(字下げ)が意味を持ちます。

同じ深さのインデントは同じブロックに属するものとみなされます。

if文
if 条件:
    print 'true'
if〜else文
if 条件:
    print 'true'
else:
    print 'false'
if〜elif文

他の言語のようにelse ifではなくelifです。

if 条件1:
    print 'if1'
elif 条件2:
    print 'if2'
while文
i = 0
while i < 5:
    # 処理
    i += 1

いわゆる無限ループには while 1:が主に使われます。

for文

Javaのforeachのような動作です。

for i in [0, 1, 2, 3, 4]:
    # inの右に渡されたリスト等の要素がiに順次代入されて処理される
    print i

今何番目の要素かを取っておきたい場合は、組み込みのenumerate()と合わせて使うとよいでしょう。

for i, j in enumerate(['zero', 'one', 'two', 'three']):
    print i, j
while-else, for-else

whileブロックやforブロックの後にelseブロックを付加できます。このブロック内の演算は、break以外でループを抜けた時に実行されます。

for i in ['hoge', 'moge', 'fuga']:
    print i
else:
    print 'else' # 出力される

i=1
while i <= 0:
    i += 1
else:
    print 'else' # 出力される

i=1
while i:
    i += 1
    if i>10:
        break
else:
    print 'else' # 出力されない
複数回繰り返し
for i in xrange(1000000):
    print 'SPAM ' # 1000000回繰り返し

xrange()はrange()と似ていますが、最初からリスト全体を生成するわけではないのでこういったループ目的に多用されます。(※Python3系ではrangeがxrange相当になっています。配列を最初から生成するrangeはなくなりました)

7. 関数

関数は基本以下のようにして記述します。返り値はreturn文で返します。(return文がない場合はNoneが返ります)

def add1(num1, num2):
    return num1 + num2

add1(1, 2) # 3

引数に*や**を添えることで可変長引数を実現できます。

収まりきらなかった引数はタプルとして*付き引数に、キーワード引数はディクショナリとして**付き引数に格納されます。

*、**付き引数の名前はなんでも使えますが*args, **kwargsが主流のようです。

def f(arg, *args, **kwargs):
    print arg
    print args
    print kwargs

f(1, 2, 3, four=4, five=5,six=6)
1
(2, 3)
{'four': 4, 'six': 6, 'five': 5}

lambda式で無名関数を作成できます。lambda (引数): (python式)の形で表現します。

add2 = lambda x, y: x + y
add2(1, 2) # 3

lambdaによる無名関数は、小規模な関数を作成して使用したり他の関数の引数とするのに向いています。

無理にlambdaで関数を記述しようとすると可読性も落ちるので、ある程度以上規模の大きい関数は通常の形式で記述したほうがよいです。

7.5. 関数の呼び出し方・補足

引数にデフォルト値を指定できます。デフォルト値が指定された引数は省略できます。

ただし、デフォルト値がある引数の後にデフォルト値のない引数を記述すると文法エラーとなります。

def emphasis(text, decoration='*'):
    return decoration + text + decoration

emphasis('hello') # *hello*

def f(a, b=1, c):
    return a + b + c

SyntaxError: non-default argument follows default argument

よくある落とし穴として、デフォルト値は都度初期化されるのではなく1回のみ初期化されて使いまわされるため、デフォルト値に可変オブジェクトを置いてしまうというミスがあります。

def my_append(a, array=[]):
    array.append(a)
    return array

my_append(4, [1, 2, 3]) # [1, 2, 3, 4]
my_append(1) # [1]
my_append(2) # [2] を期待したが [1, 2] が返される

関数を呼び出す際に、仮引数の名前を用いて呼び出す方法があります。

emphasis('hello', decoration='***') # ***hello***

関数に渡す引数にリテラルが多くてわかりにくい時に便利です。また、デフォルト値付き引数が複数ある時に途中の値のみ値を指定したいときにも使えます。

よく使うところではリストのsortメソッドにキー関数を指定する場合など。

help([].sort)
sort(...)
    L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
    cmp(x, y) -> -1, 0, 1

L = ['1', '8', '4', '6', '5', '9', '7', '2', '3', '10']
L.sort() # L == ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
L.sort(key=int) # L == ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

関数にリストやタプル、ディクショナリを用いて引数を渡す方法もあります。引数の形式に合わないとTypeError例外になります。

args = ['hello', '*']
emphasis(*args) # *hello*

kwargs = {'text': 'bye', 'decoration': '!!!'}
emphasis(**kwargs) # !!!bye!!!

8. ファイル入出力

ファイルコピーの(ナイーブな)例を示します。*1

# ファイルを読み込みモードでオープン
orig = open('orig.txt')
# ファイルを書き込みモードでオープン
copy = open('copy.txt', 'w')
for line in orig:
    # lineは改行文字を含む
    copy.write(line)

orig.close()
copy.close()

file()組み込み関数によるファイルのオープンはpython 2.5から非推奨です。3.x系にはもはや存在しません。

9. 雑多なtips

Pythonの真偽値

pythonにおいて、None、False、ゼロとして解釈できる数値(0, 0.0, 0j)、空文字列('')、空リスト、空タプル、空ディクショナリは偽と評価されます。

また、XXX.__len__()が0を返すようなオブジェクト、XXX.__nonzero__()がFalseを返すようなオブジェクトも偽と評価されます。

その他は真と評価されます。

切り捨て
num = int(1.5) # 1
小数点以下n桁目で丸め
num = round(3.14159, 3) # 3.142
num = round(1250, -2)   # 1300.0  桁数に負数も指定できる
文字→数値
# 10進表記で変換
int('100') # 100
# 基数を指定して変換
int('FFFF', 16) # 65535
# 小数
float('1.0') # 1.0
数値→文字
str(1234) # '1234'
文字列→配列
list('hoge') # ['h', 'o', 'g', 'e']
文字列をそのまま出力したい

print文を使うと空白や改行が付加されて出力されますが、それを望まない場合。

sys.stdout.write('hogehoge')

print('hogehoge', end='') #Python3
コマンドライン引数

sys.argvにリスト形式で格納されています。sys.argv[0]はスクリプト自身を指します。

print sys.argv
後置のif〜else

以下のように3項演算子のような書き方ができます。

result = 'true_value' if 条件 else 'false_value'
クラス定義

クラスはclass 名前:で定義します。

class Person():
    def __init__(self, name, age):
        self.name, self.age = name, age
        self.address = None

jhon = Person('Jhon', 15)
print jhon.name
jhon.address = 'USA, Earth'
map

mapを使ってリスト等の各要素を変換できます。リスト内包表記も使えます。

map1 = map(str, range(5)) # ['0', '1', '2', '3', '4']
map2 = [str(x) for x in range(5)] # ['0', '1', '2', '3', '4']
filter

filterを使ってリスト等の各要素から条件に合うものを抽出したリストを生成できます。リスト内包表記も使えます。

filter1 = filter(lambda x: 'cat' in x, ['cat', 'dog', 'catalog']) # ['cat', 'catalog']
filter2 = [x for x in ['cat', 'dog', 'catalog'] if 'cat' in x]
タプル代入、リスト代入

タプル代入、リスト代入と呼ばれる代入方法があります。

(a, b) = (1, 2) # a=1, b=2
[c, d] = [a, b] # c=1, d=2
a, b = b, a # a, bの値を交換

タプルやリストとして評価されるような式を右辺にして用いると便利です。

year, month, day = '2010/01/26'.split('/')
例外処理

raiseで例外を投げ、try〜except(〜finally)文で捕捉します。

try:
    #何かの処理
    if 条件:
        raise Exception();
except Exception, e:
    # 捕捉したException型の例外はeに代入される
    (略)
finally:
    # 例外の有無に関わらず実行されるブロック(必須ではない)
    (略)
else:
    # 例外が発生しなかった場合のみ実行されるブロック(必須ではない)

except節は2.6系から新しい表記ができるようになりました。

except Exception as e:
    # 捕捉したException型の例外はeに代入される

asを用いた方が「この変数に代入する」という意図が明確に表現されているように思えるのでこちらを使うべきでしょう。Python3ではasを用いない形式は文法エラーになります。

*1:実際のファイルコピー用途にはshutil.copyfile関数があります

dplusplusdplusplus 2010/01/29 04:17 入力について少々追加。

aroma_blackaroma_black 2010/01/29 09:47 改行しない出力は
sys.stdout.write('hogehoge')
だと面倒だと思うので、
print 'hogehoge',
とやると簡単にできます。

dplusplusdplusplus 2010/01/29 13:43 タプル/リスト代入について補足。

>aroma_blackさん
コメントありがとうございます。
カンマ付きのprint文は場合によって空白を付与するため書きませんでした。
文が紛らわしかったので直しておきます。

odakinodakin 2010/01/29 17:14 typo発見。
『num = 5 % 2 # 3 (剰余をとる)』

『num = 5 % 2 # 1 (剰余をとる)』

dplusplusdplusplus 2010/01/29 18:53 >odakinさん
指摘ありがとうございます。修正しました。

ekafekaf 2010/01/29 21:25 How To Become A Hackerを読んでいたのですが、、、とってもちょうどいい!ありがとう!

dplusplusdplusplus 2010/02/01 03:26 ブコメつっこみを参考に追加修正
・タプルの説明追加
・lambdaによる無名関数の説明
・サンプルコード増量
・ほか雑多な修正

>ekafさん
お役に立てたならうれしいです。

AtsushiAtsushi 2011/03/02 02:30 すばらしい情報をありがとうございます.
参考にさせてもらいました.

トラックバック - http://d.hatena.ne.jp/dplusplus/20100126/p1
 |