入門Python3 を読む~Python3の基礎まとめ~前編

入門 Python 3

入門 Python 3

一旦Pythonの復習をしようと思い、この本を借りてきた。

情報の整理のために、少しまとめておく。一部サンプルコードは本とは異なります。

分かりやすい本だったので、いつか買うかもしれない。

(ネットに書かれているもので)基本的な文法はここが分かりやすかった。

qiita.com

qiita.com

記事を二つに分けます。

基本的なことは前編で。(1章から6章)

テクニック的なものは後編で。(7章から12章)

(追記)

今さらPython3 (1) - 決意表明? - Deutschina's Tech Diary

こちらの記事である程度まとめてあったので、こっちを見るのがいいかもしれません。


2章 数値、文字列、変数

・[start:end:step]によるスライス(オフセットとは、基準からの距離のこと)

[:] 先頭から末尾まで  

[start:] startオフセットから末尾まで  

[:end]  先頭からend-1オフセットまで  

[start:end] startオフセットからend-1オフセットまで  

[start:end:step] stepごとに、startオフセットからend-1オフセットまで

・split()による分割

todos = 'aaa bbb,ccc ddd'
todos.split(',')

['aaa bbb', 'ccc ddd']

todos.split()

['aaa', 'bbb,ccc', 'ddd']

・join()による結合

todos = ['aaa', 'bbb,ccc', 'ddd']
todos_string = ', '.join(todos)
print(todos_string)

aaa, bbb,ccc, ddd

3章 リスト、タプル、辞書、集合

・リスト 要素の変更(追加、削除、書き換え)が可能。

#リストの作成

empty_list = []
empty_list

[]

another_empty_list = list()
another_empty_list

[]

list = ['a', 'b', 'c', 'd']

#指定したオフセットの要素の追加・削除

list.insert(1, 'x')
list

['a', 'x', 'b', 'c', 'd']

del list[1]
list

['a', 'b', 'c', 'd']

#pop()でオフセットを指定して要素を取り出して、削除(キューを作ることが出来る)

list.pop()
'd'
list
['a', 'b', 'c']
list.pop(1)
'b'
list
['a', 'c']

#=による代入とcopy()によるコピー

a = [1, 2, 3]
a
[1, 2, 3]

b = a
b
[1, 2, 3]

a[0] = 'x'
a
['x', 1, 2]
b
['x', 1, 2]

a = [1, 2, 3]
b = a.copy()
c = list(a)
d = a[:]

a[0] = 'x'
a
['x', 1, 2]
b
[1, 2, 3]
c
[1, 2, 3]
d
[1, 2, 3]

・タプル 要素の変更(追加、削除、書き換え)が不可能 リストに比べて消費スペースが小さい 辞書のキーになることができる

#タプルの作成

empty_tuple = ()

one_tuple = 'x',

two_tuple = 'x', 'y'

two_tuple = ('x', 'y')

#タプルのアンパック

a = 'x'

b = 'y'

c, d = a, b

c
'x'

d
'y'

・辞書

#辞書の作成

empty_dict = {}

#リストの辞書への変換

lol = [['a', 'b'], ['c', 'd']]
dict(lol)
{'a':'d', 'c':'d'}

#すべての要素の削除

one_dict = {'a':'b', 'c':'d'}
one_dict.clear()
{}

#キー、要素、ペアの取得

keys()

values()

items()

によって取得できるキー、要素、ペアの戻り値は特別なビューで返される。

戻り値を通常のリスト値にするには、list()関数を用いる

・集合 数学で使うあの集合

#集合の作成

a  = {1, 2, 3, 4, 5}

b  = {2, 3, 6, 7, 8}

a.union(b)                 # a | b 和集合
a.intersection(b)          # a & b 共通集合
a.difference(b)            # a - b 差集合
a.symmetric_difference(b)  # a ^ b 対称的差集合

a.issubset(b)              # a <= b 部分集合
                           # a <  b 真部分集合
a.issuperset(b)            # a >= b 上位集合(bの集合のすべての要素がaの集合の要素になっている。部分集合の逆)
              # a >  b 真上位集合

この章は知識として抜けている箇所が多かった。

4章 コード構造

・行の継続は、行末にバックスラッシュをつける

・elseによるbreakのチェック(例はwhileループだが、forループでも一緒)

numbers = [1, 3, 5]
position = 0
while position < len(numbers):
    number = numbers[position]
    if number % 2 == 0:
        print('Found even number', number)
        break
    position += 1
else: #breakが呼びだされていない
    print('No even number found')


No even number found

この使い方は今まで知らなかった……。

ようは、ループ終了時にbreakが呼び出されていなかった場合の処理が書けるということだろう。

・zip()を使った複数シーケンスの反復処理

a = [1, 2, 3]
b = ['a', 'b', 'c']

for i, j in zip(a, b):
    print(i, j)

1 a
2 b
3 c

・リスト内包表記

[expression for item in iterable]

number_list = [number for number in range(1,6)]
number_list
[1, 2, 3, 4, 5]

[expression for item in iterable if condition]

number_list = [number for number in range(1,6) if number % 2 == 1]
number_list
[1, 3, 5]

・辞書包括表記

{key_item: value_item for item in iterable}

word = 'letters'
letter_counts = {letter: word.count(letter) for letter in word}
letter_counts
{'e': 2, 'l': 1, 'r': 1, 's': 1, 't': 2}

#上記では、tとeを2回計算しているので

word = 'letters'
letter_counts = {letter: word.count(letter) for letter in set(word)}
letter_counts

・集合内包表記

[item for item in iterable]

a_set = {number for number in range(1,6) if number % 3 == 1}
a_set
{1, 4}

・ジェネレータ内包表記

タプルは内包表記をもたない。()を用いた内包表記は、ジェネレータ内包表記と呼ばれる。ジェネレータは、イテレータに値を渡す役割がある。

ジェネレータは一度しか実行することしかできない。

number_thing = (number for number in range(1,6))
for number in number_thing :
    print(number)

1
2
3
4
5

#リスト関数で呼び出せばリスト内包表記のように使えるが、ジェネレータは一度しか実行できないので

number_thing = (number for number in range(1,6))
for number in number_thing :
    print(number)
number_list = list(number_thing)
number_list

1
2
3
4
5
[]

・関数

デフォルト引数値の指定

def buggy(arg, result=[]):
    result.append(arg)
    print(result)
buggy('a')
buggy('b')

['a']
['a', 'b']

def works(arg):
    result = []
    result.append(arg)
    return result

works('a')
works('b')

['a']
['b']

*による位置引数のタプル化

def print_args(*args):
    print('Positional argument tuple:', args)
print_args(3, 2, 1, 'wait', 'uh...')

Positional argument tuple: (3, 2, 1, 'wait', 'uh...')

**によるキーワード引数の辞書化

def print_kwargs(**kwargs):
    print('Keyword argument:', kwargs)
print_kwargs(wine='merlot', entree='mutton', dessert='macaroon')

Keyword argument: {'dessert': 'macaroon', 'wine': 'merlot', 'entree': 'mutton'}

docstring 関数のドキュメントの作成

def echo(anything):
    '''
    test
    test
    test
    test
    '''
    pass
help(echo)

Help on function echo in module __main__:

echo(anything)
    test
    test
    test
    test

オブジェクトとしての関数 *argsと**kwargsの利用

def sum_args(*args):
    return sum(args)
def run_with_positinal_args(func, *args):
    return func(*args)
run_with_positinal_args(sum_args, 1, 2, 3, 4)

10

関数内関数

def outer(a, b):
    def inner(c, d):
        return c + d
    return inner(a, b)
outer(4, 7)

11

クロージャ 

def outer(a, b):
    def inner(c):
        return a + b + c
    return inner
c = outer(1,2)
c(3)

6

cが定義された時のa. bの値をouterは保持していて、さらにinnerはa, bにアクセスすることができる。

クロージャは、今まで意識使えてなかったですね。

クロージャの使い方はここに詳しく載っていた。

www.lifewithpython.com

qiita.com

理解が不完全なので個別に記事を作るかも。

ジェネレータ関数

def my_range(first=0, last=10, step=1):
    number = first
    while number < last:
        yield number
        number += step
        
ranger = my_range(1, 5)
for x in ranger:
    print(x)

1
2
3
4

yieldはイテレータに渡す戻り値?を指定しているイメージなのかな。

デコレータ

入力として関数を1つ関数を1つ取って、別の関数を返す関数。

def test(func):
    def new_function(*args, **kwargs):
        print("test")
        result = func(*args, **kwargs)
        return result
    return new_function

@test
def add_number(a, b):
    return a + b

add_number(1, 2)

test
3

ここが分かりやすかった。

qiita.com

名前空間とスコープ

locals()

ローカル名前空間の内容を示す辞書を返す

globals()

グローバル名前空間の内容を示す辞書を返す

・エラー処理

class TestClass(Exception):
    pass

try:
    raise TestClass('error')
except TestClass as e:
    print(e)

error

エラー処理も独自に記事を書くかもです。

5章 モジュール、パッケージ、プログラム

・パッケージ

--main.py
--packege_sources--module1.py
         --modele2.py
         __init__.py

main.pyの中身

from packege_sources import module1, module2

...

・標準ライブラリ

ここにまとまっている。

Python 標準ライブラリ — Python 3.5.2 ドキュメント

6章 オブジェクトとクラス

・クラスの定義

class TestClass():
    def __init__(self, name):
        self.name = name
a = TestClass('test')
a.name

'test'

a = TestClass('test')

1.TestClassクラスの定義を探しだす

2.メモリ内に新しいオブジェクトのインスタンスを作成する

3.新しくつくったオブジェクトをself、引数の'test'をnameとして渡して、オブジェクトのinitメソッドを呼び出す(initインスタンス作成後に呼び出される)

4.nameの値をオブジェクトに格納する

5.あの新たしいオブジェクトを返し、aという名前を付ける

a.name

オブジェクトのname属性を呼び出す

・super

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

class MailPerson(Person):
    def __init__(self, name, email):
        super().__init__(name)
        self.email = email
        
unknown = MailPerson('unknown', 'unknown')

unknown = MailPerson('unknown', 'unknown')

1.上記1~3を行う

2.super()が親クラスのPersonの定義を取り出す

3.super().init = Person.init()

・プロパティによる属性値の取得・設定

オブジェクトの非公開属性の値を読み書きできるようにセッターとゲッターメソッドを書くことが、オブジェクト指向言語の中にはある。

pythonはすべての属性とメソッドが公開されているので、セッターとゲッターを書く必要はないが、プロパティを用いて、セッターとゲッターを書くことが出来る。

ちなみに、非公開属性は先頭に__をつける。

class Test():
    def __init__(self, input_name):
        self.__name = input_name
    def get_name(self):
        print('inside the getter')
        return self.__name
    def set_name(self, input_name):
        print('inside the setter')
        self.__name = input_name
    name = property(get_name, set_name)
a = Test('test')
print(a.name)
a.name = 'Test'
print(a.name)

inside the getter
test
inside the setter
inside the getter
Test

デコレータで定義することも出来る

class Test():
    def __init__(self, input_name):
        self.__name = input_name
    #ゲッターメソッド前に付ける
    @property
    def name(self):
        print('inside the getter')
        return self.__name
    #セッターメソッド前に付ける
    @name.setter
    def name(self, input_name):
        print('inside the setter')
        self.__name = input_name
    

・クラスメソッド

クラス単位でのセット、ゲットが可能になる。

class Test():
    count = 0
    def __init__(self):
        Test.count += 1
    def exclaim(self):
        print("I'm an A")
    @classmethod
    def kids(cls):
        print('A has', cls.count, "object")
        
a = Test()
b = Test()
c = Test()
Test.kids()

A has 3 object

Test.count += 1

クラスとしてのcountを参照している

cls.count

この時の引数はクラス自体。

・静的メソッド

クラスにもオブジェクトにも影響を与えないメソッド。

class Test():
    @staticmethod
    def a():
        print('test')
        
Test.a()

test

引数は取らない。オブジェクトを作らずに実行することだできる。

・ダックタイピング

同じ振る舞いをするものは、継承関係以外のオブジェクト同士でも同じようにみなして書くことが出来る

class Test():
    def __init__(self, one, two):
        self.one = one
        self.two = two
    def a(self):
        return self.one
    def b(self):
        return self.two + '_'
class Test1(Test):
    def b(self):
        return self.two + '?'
class Test2(Test):
    def b(self):
        return self.two + '!'

class Tests():
    def a(self):
        return 'd'
    def b(self):
        return 'D_?!'

a = Test('a', 'A')
b = Test1('b', 'B')
c = Test2('c', 'C')
d = Tests()

def a_b(obj):
    print(obj.a(), obj.b())

a_b(a)
a_b(b)
a_b(c)
a_b(d)

a A_
b B?
c C!
d D_?!

・特殊メソッド

ここに載ってる。

3. データモデル — Python 3.3.6 ドキュメント

特殊メソッド名 - Dive Into Python 3 日本語版

コンポジション

クラスをどんどん継承していくのではなく、has-aの関係をつくる。

class Test():
    def __init__(self, one):
        self.one = one
class Test1():
    def __init__(self, two):
        self.two = two
class Tests():
    def __init__(self, test, test1):
        self.test = test
        self.test1 = test1
    def show(self):
        print(self.test.one, self.test1.two)

a = Test('a')
b = Test1('b')
c = Tests(a, b)

c.show()

a b

継承とどう使い分ければ良いのかイマイチ分からない。

・名前付きタプル

イミュータブルなオブジェクトとして振る舞える。

from collections import namedtuple
Test = namedtuple('Test', 'a b')
test1 = Test('A', 'B')
test1

Test(a='A', b='B')

test1.a

'A'

test1.b

'B'

詳しくはここが分かりやすかった。

http://docs.python.jp/3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields