10 分で学ぶ Python のチュートリアル

"Stavros' Stuff" というサイトに掲載されていた "Tutorial - Learn Python in 10 minutes" という記事の妙訳 翻訳です。これから Python をはじめたいという方向けです。ちょっと分かりやすいように ? 補足情報も付加しちゃってます。ついでに私が Python を書くときに意識していることも付加しちゃってます。付加情報が間違ってたらごめんなさい ><

プロパティ

Python は強い型付け (strongly typed language)、動的型付け (dynamically typed)、暗黙的型付け (implicitly typed)、大文字小文字を区別 (case sensitive)、オブジェクト指向 (object-oriented) です。

  • 強い型付け言語の特徴: 処理や演算が間違った型の引数を受けとることが出来ない (C 言語とかは弱い型付け)。安全ですね。
  • 動的型付け言語の特徴: 型の検査を実行時に行うことが多い。簡単に言うと、型は変数ではなく値に付けられます。
  • 暗黙型付け言語の特徴: 明示的に指定しなくてもコンパイラが自動的に型変換を判断してくれる

ヘルプ

Python のヘルプは常にインタプリタから利用する事ができます。もし、オブジェクトの動作について調べたい場合は、help(<object>) を呼び出しましょう。また、dir(<object>) でオブジェクトのメソッドや変数等のメンバ一覧を参照したり、<object>.__doc__ でドキュメントを参照するのも便利ですよ。

>>> help(5)
Help on int object:
class int(object)
...

>>> dir(5)
['__abs__', '__add__', ...]

>>> print abs.__doc__
abs(number) -> number

Return the absolute value of the argument.

蛇足ですが、個人的には IPython 使ってます。<object>? <object>?? でドキュメントを含む様々な情報を参照できちゃいます。

構文 (シンタックス)

Python はステートメントの終端文字がなくブロックをインデントで指定します。ブロックの始まりにインデントし、終わりにインデントを戻します。コロン (:) で終了するステートメント以下をインデントします。コメントは、1 行ならシャープ # の後に続け、複数行にわたる場合は複数行の文字列 """スパム\nエッグ""" にします。値の割り当て (厳密にはオブジェクトへの名前付け) は等記号 "=" を使い、等価比較は 2 つの等記号 "==" を使います。"+=" や "-=" 演算子で、演算子の右に記載した値でインクリメントやデクリメントすることができます。これは文字列を含む多くの型で利用できます。また、複数の変数を 1 行で定義することができます。

>>> spam = 3
>>> spam
3
>>> spam += 2
>>> spam
5
>>> spam -= 1
>>> spam
4
# 一行のコメント
"""This is a multiline comment.
The following lines concatenate the two strings."""
u"""これは複数行コメントです。
日本語でのコメントはユニコードでコメントする事をお勧めします。
あとで __doc__ とかで文字化けせずに表示したいでしょ :D
下の行では、2 つの文字列を連結しています。"""
>>> egg = "Hello"
>>> egg += " world!"
>>> print egg
Hello world!
# ユニコード文字列だって
>>> ja = u"こんにちわ"
>>> ja += u"世界!"
>>> print ja
こんにちわ世界!
# 1 行で変数の交換だってできちゃいます。
# 値が割り当てられているわけではないので、強い型付けによる制限を受けません。
# 新しいオブジェクトが名前に紐付けられます。
>>> spam, egg = egg, spam
>>> print spam
Hello world!
>>> egg
4

データ型

Python で利用できるデータ構造はリスト (list)、タプル (tuple)、辞書 (dict)、セット (set) (Python 2.5 以前は sets モジュールとして提供) です。リストは一次元配列 (もちろんリスト内にリストを含めることができます)、辞書は連想配列 (もしくはハッシュテーブル)、タプルはイミュータブル (状態を変更することができない) 一次元配列です。Python の配列は型による制限がないため、数値や文字列などをリスト/タプル/辞書/セット内に混在させることができます。すべての配列型で要素のインデックスは 0 から始まります。インデックスに負の数のを指定すると配列の終わりから数えるため、最後の要素のインデックスは -1 となります。関数を変数とすることができます。Python はファーストクラスオブジェクトです。これは渋川先生が翻訳されている "The history of Python" のブログを見ると幸せになれます。

>>> sample = [1, [u"日本語", "list"], ("a", "tuple")]
>>> mylist = ["List item 1", 2, 3.14]
>>> mylist[0] = "List item 1 again"
>>> mylist[-1] = 3.14
>>> mydict = {"Key 1": "Value 1", 2: 3, "pi": 3.14}
>>> mydict["pi"] = 3.15
>>> mytuple = (1, 2, 3)
>>> myfunction = len
>>> print myfunction(mylist)
3

コロン (:) を使って配列内の指定した範囲にアクセスすることができます。インデックスの開始を省略すると最初の要素から、インデックスの終了を省略すると最後の要素までとなります。負のインデックスを指定すると、最後のアイテム (-1 が最後のアイテムのインデックス) から数えます。

どこでどういうデータ型を使うかというのは非常に重要です。各データ型の特徴をしっかり把握しておくと幸せになれます。配列内でユニークにデータを持たせたい場合はセット、順番を保証したいのであればリスト!などなど

>>>  mylist = ["List item 1", 2, 3.14]
>>>  print mylist[:]
['List item 1', 2, 3.1400000000000001]
>>>  print mylist[0:2]
['List item 1', 2]
>>>  print mylist[-3:-1]
['List item 1', 2]
>>>  print mylist[1:]
[2, 3.14]

ちなみに array[:] で配列の シャローコピー ディープコピー ができます。元の配列を保持したまま、配列を操作する時に使います。

文字列

文字列はシングルクォーテーションかダブルクォーテーションの何れかで定義でき、"He said 'Hello'" のようにクォーテーション内で異なるクォーテーションを使用することができます。複数行にまたがる文字列は 3 つのダブルクォーテーション (もしくはシングルクォーテーション) で囲みます。Python はユニコードをサポートしており、u"これはユニコード文字" と定義できます。文字列フォーマット操作は % (モジュロ) 演算子とタプルを使います。各 %s や %d 等が、左から右へタプル内の各アイテムに置き換えられます。タプルの変わりに辞書を使うことも出来ます。

>>> print u"名前: %s\n数字: %d\n少数: %f\n文字列: %s" % (myclass.name, 3, 3.14, 3 * "-")
名前: Poromenos
数字: 3
少数: 3.140000
文字列: ---

multiline = """This is
a multiline
string."""

# WARNING: Watch out for the trailing s in "%(key)s".
>>> print "This %(verb)s a %(noun)s." % {"noun": "test", "verb": "is"}
This is a test.

美しいコードを書くために、複数行にまたがる文字列の 3 つの引用符はダブルクォーテーションを、ログやメッセージなどユーザに表示や通知する文字列もダブルクォーテーションを、その他コード内で利用する設定情報 (URL や DB接続情報等) や定数はシングルクォーテーションを使いましょう。っていうかそう決めておくと、後でコードが追いやすいです。運用する人がログやメッセージを追加、変更したいのであればダブルクォートを追いかける、ロジックや環境が変更した場合はシングルクォートを追いかける、とかできます。また、美しくコードを書くために複数行文字列は非明示的文字列連結を使うというテクニックもありますよ。

フロー制御構文

フロー制御構文は ifforwhile です。switchselect はありませんが、ifelif で代用します。

rangelist = range(10)
>>> print rangelist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

for number in range(10):
    # number がタプル内に含まれているかをチェック
    if number in (3, 4, 7, 9):
        # "break" は "else" に行かずに for を終了します
        break
    else:
        # "continue" は次のループを続けます
        continue
else:
    # "else" は "break" 以外の場合に実行されます
    pass # 何もしない場合は "pass" と記載

if rangelist[1] == 2:
    print "The second item (lists are 0-based) is 2"
elif rangelist[1] == 3:
    print "The second item (lists are 0-based) is 3"
else:
    print "Dunno"

while rangelist[1] == 1:
    pass

関数

関数は "def" で宣言します。必須の引数の後に、デフォルトの値を指定したオプション引数を宣言することができます。名前付け引数は値を渡す引数の名前を指定する事が出来ます。関数が返したい結果が複数ある場合、タプルを返すと、効率的に 複数の結果をアンパックすることができます。ラムダ関数は 1 行の構文を含むアドホック関数を定義します。パラメータは参照渡しですが、イミュータブル型 (タプル、数値、文字列等) は変更できません。これは引数としてそのオブジェクトのメモリ上の位置を渡しているためであり、それを他のオブジェクトへ結びつけると今までのオブジェクトは破棄され、イミュータブル型のオブジェクトは新しく結びつけられたオブジェクトになってしまいます。イミュータブル型のオブジェクトのうち配列に関しては、上述したシャローコピー (array[:]) で渡してあげると、新たなオブジェクトを作成するので、元の配列 (シャローコピーなので値は参照です) を保持することができます。

# def f(x): return x + 1 と同じこと
functionvar = lambda x: x + 1
>>> print functionvar(1)
2

# an_int と a_string は初期値を持つオプション引数です
# 最初の引数は省略することができません
def passing_example(a_list, an_int=2, a_string="A default string"):
    a_list.append("A new item")
    an_int = 4
    return a_list, an_int, a_string

>>> my_list = [1, 2, 3]
>>> my_int = 10
>>> print passing_example(my_list, my_int)
([1, 2, 3, 'A new item'], 4, "A default string")
>>> my_list
[1, 2, 3, 'A new item']
>>> my_int
10

ちなみにオプション引数と、名前付け引数を混同している?と見受けられる文献をたまに見かけますが、両者はまったく違います。オプション引数は前述の通り、デフォルト値が指定されたオプショナルの引数。名前付け引数というのは、引数の名前を指定して値を渡すことができる機能のことです。

def spam(foo, bar="optional"):
    # foo は必須の引数 
    # bar はオプション引数
    print foo, bar

# オプション引数を指定しない、非名前付け引数呼び出し
spam("mandatory")
# オプション引数を指定した、非名前付け引数呼び出し
spam("mandatory", "optional")
# オプション引数を指定した、名前付け引数呼び出し 1
spam(foo="mandatory", bar="optional")
# オプション引数を指定した、名前付け引数呼び出し 2
# 名前付け引数を使っても、引数の順番は守ろうね!読みにくくなる。
spam(bar="optional", foo="mandatory")

# すべて "mandatory optional" と出力されます

クラス

Python のクラスは、制限付き多重継承をサポートしています。プライベート (厳密にはプライベートではない) 変数やメソッドは、 __spam のように最初に 2 つ以上のアンダーラインがある名前で宣言します。クラスのインスタンスには任意の名前を付けることができます。

class MyClass:
    common = 10
    def __init__(self):
        self.myvariable = 3
    def myfunction(self, arg1, arg2):
        return self.myvariable

>>> classinstance = MyClass()
>>> classinstance.myfunction(1, 2)
3
# 変数 "common" はすべてのクラスに共通するクラス変数
>>> classinstance2 = MyClass()
>>> classinstance.common
10
>>> classinstance2.common
10
# クラス変数の更新は、インスタンスではなくクラス名による操作
>>> MyClass.common = 30
>>> classinstance.common
30
>>> classinstance2.common
30
# クラス変数を更新せずにインスタンス変数のみを更新
>>> classinstance.common = 10
# クラス変数からインスタンス変数へ
>>> classinstance.common
10
>>> classinstance2.common
30
>>> MyClass.common = 50
# "common" はインスタンス変数になっているため変更されない
>>> classinstance.common
10
# "common" はクラス変数のままなので変更される
>>> classinstance2.common
50

# MyClass を継承したクラス
# クラスを多重継承したい場合は以下のように定義する:
# class OtherClass(MyClass1, MyClass2, MyClassN)
class OtherClass(MyClass):
    # 変数 "self" はクラスインスタンスへの参照が自動的に代入される
    def __init__(self, arg1):
        self.myvariable = 3
        print arg1

>>> classinstance = OtherClass("hello")
hello
>>> classinstance.myfunction(1, 2)
3
# このクラスには "test" というメンバ変数を持っていませんが、
# そのインスタンスに対していつでも追加することができます。
>>> classinstance.test = 10
>>> classinstance.test
10

例外

Python の例外は try-except ブロックでハンドリングします。また finally 句で、事後処理をする事ができます。

def spam():
    try:
        # 0 による乗算で例外をスロー
        10 / 0
    except ZeroDivisionError:
        # 例外発生時の処理
        print "Oops, invalid."
    else:
        # 例外が発生しなかった場合の処理
        pass
    finally:
        # 例外発生の有無にかかわらず処理
        print "We're done with that."

>>> spam()
Oops, invalid.
We're done with that.

インポート

外部のライブラリは import <libname> でインポートします。また、from <libname> import <funcname> を使って、ライブラリ内の関数をインポートすることもできます。

import random
from time import clock

randomint = random.randint(1, 100)
>>> print randomint
64

美しいコードを書くために from <libname> import * を多用するのは避けましょう。名前空間が心配になります。あと、なるべく関数ではなくモジュールレベルでインポートしましょう。read とかいう関数とかかぶりそうですよね。それに spam.readegg.read と書いてあったほうが脳に優しいです。

ファイル入出力

Python には多くの標準ライブラリーが備わっています。例えば、ファイル入出力を使ったシリアライズ (pickle を使ってデータ構造を文字列に変換する) は以下のように書くことができます。

import pickle
mylist = ["This", "is", 4, 13327]
# "C:\binary.dat" を書込権限で開く
# ファイル名の前の "r" は文字列をエスケープしないっていう意味
# "raw string" の "r"
myfile = file(r"C:\binary.dat", "w")
pickle.dump(mylist, myfile)
myfile.close()

myfile = file(r"C:\text.txt", "w")
myfile.write("This is a sample string")
myfile.close()

myfile = file(r"C:\text.txt")
>>> print myfile.read()
'This is a sample string'
myfile.close()

# ファイルを読取権限で開く
myfile = file(r"C:\binary.dat")
loadedlist = pickle.load(myfile)
myfile.close()
>>> print loadedlist
['This', 'is', 4, 13327]

その他

  • 同時に複数のコンディションをチェックできます。1 < n < 3 では n が 1 より大きく、 3 より小さいかどうかをチェックします。
  • 配列からアイテムを削除したい場合は del を使います。
  • リスト内包表記はリストを生成するための強力な方法を提供します。それは複数の for-in と、if で条件を含める事ができます。
    >>> spam = [1, 2, 3]
    >>> egg = [3, 4, 5]
    >>> print [x * y for x in spam for y in egg]
    [3, 4, 5, 6, 8, 10, 9, 12, 15]
    >>> print [x for x in spam if 4 > x > 1]
    [2, 3]
    # "any" でアイテム内に値が真値であるかチェックできます
    >>> any([i % 3 for i in [3, 3, 4, 4, 3]])
    True
    # 4 % 3 が 1 になり、1 は真値であるため、True を返します
    
    # 条件に該当する値の個数を調べたい場合は以下のように書けます
    >>> sum(1 for i in [3, 3, 4, 4, 3] if i == 4)
    2
    
    # 値の削除
    >>> del spam[0]
    >>> print spam
    [2, 3]
    >>> del spam
    
  • グローバル変数は関数外に宣言し、特別な宣言をしなくても関数内で参照できます。しかし値を変更したい場合は、関数の最初に "global" の後に変更する変数を記述する必要があります。"global" 宣言しない場合、Python はそれを新しい新しいローカル変数とみなします。
    number = 5
    
    def spam():
        # 5 と出力します
        print number
    
    def egg():
        # 新しい変数を作る前にその変数を参照しているとみなされ、
        # 例外がスローされます。
        print number
        number = 3
    
    def yetanother():
        global number
        # グローバル変数を書き換える
        number = 3
    

コメント

  1. 冒頭、確かに「妙訳」ではあるんでしょうが、「抄訳」の誤字?
    しかし元記事から省略されているところも見当たらず、むしろ付加されている部分もあったりするので、この場合は単なる「翻訳」「日本語訳」でいいのではないかと。

    返信削除
  2. なんと・・・。よく見かけから使っとこうと意味もわからず使ってましたw
    これ "抄訳" っていうんですね!
    ご指摘ありがとうございます。勉強になりました!

    返信削除
  3. 「 array[:] で配列のディープコピーができます。」
    とありますが、
    [:] はシャローコピーですよ。

    返信削除
  4.  ご指摘ありがとうございます。修正いたしました m(_ _)m

    返信削除

コメントを投稿

このブログの人気の投稿

Python から Win32 API 経由で印刷する

Disqus のスケール - Django 編

Disqus のスケール - Django で月間80億PVを処理する