Pythonを使ってみよう

  • 概要
    • シンプルで習得がしやすいオブジェクト指向言語
    • データ解析、機械学習
  • 環境
    • Vagrant ローカル開発環境 (CentOS 6.7)

Python 3 インストール

  • CentOS 6 標準では Python 2 がインストールされているため pyenv を利用して Python 3 をインストール
  • epel リポジトリをダウンロード
$ wget https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
  • epel リポジトリをインストール
$ sudo rpm -Uvh epel-release-6-8.noarch.rpm
  • Ansible インストール
$ sudo yum -y install ansible
$ ansible --version
ansible 2.3.0.0
  • git, patch をインストール
$ sudo yum -y install git
$ sudo yum install patch
  • Playbook 作成
$ vi playbook.yml
---
- hosts: localhost
  connection: local
  sudo: yes
  vars:
    - python_version: 3.5.2
  tasks:
    - name: disable iptables
      service: name=iptables state=stopped enabled=no
    - name: install libselinux-python
      yum: name=libselinux-python state=latest
    - name: remove localtime
      file: path=/etc/localtime state=absent
    - name: change timezone
      file: src=/usr/share/zoneinfo/Asia/Tokyo dest=/etc/localtime state=link force=yes mode=0644
    - name: change locale
      lineinfile: >-
        dest=/etc/sysconfig/i18n
        state=present
        regexp=^LANG=
        line='LANG="ja_JP.UTF-8"'

    - name: install dependencies
      yum: name={{item}} state=present
      with_items:
        - gcc
        - openssl
        - openssl-devel
        - rpm-build
        - gcc-c++
        - bzip2
        - bzip2-devel
        - libtool
        - zlib
        - zlib-devel
        - httpd-devel
        - openssl-devel
        - curl-devel
        - ncurses-devel
        - gdbm-devel
        - readline
        - readline-devel
        - sqlite
        - sqlite-devel
        - libyaml-devel
        - libffi-devel
        - bison

    - name: check pyenv installed
      command: test -x /home/vagrant/.pyenv
      register: pyenv_present
      ignore_errors: yes
      become: no
    - name: git clone pyenv
      git: repo=https://github.com/yyuu/pyenv.git dest=/home/vagrant/.pyenv
      when: pyenv_present.rc != 0
      become: no

    - name: check pyvirtual installed
      command: test -x /home/vagrant/.pyenv/plugins/pyenv-virtualenv
      register: pyvirtual_present
      ignore_errors: yes
      become: no
    - name: git clone pyenv-virtual
      git: repo=https://github.com/yyuu/pyenv-virtualenv.git dest=/home/vagrant/.pyenv/plugins/pyenv-virtualenv
      when: pyvirtual_present != 0
      become: no

    - name: update pyenv
      command: git pull --rebase chdir=/home/vagrant/.pyenv
      become: no
    - name: update pyenv-virtualenv
      command: git pull --rebase chdir=/home/vagrant/.pyenv/plugins/pyenv-virtualenv
      become: no

    - name: check python installed
      shell: /bin/bash -lc "pyenv versions | grep {{python_version}}"
      register: python_installed
      ignore_errors: yes
      become: no
    - name: install python
      shell: /bin/bash -lc "pyenv install {{python_version}} && pyenv rehash && pyenv global {{python_version}}"
      when: python_installed.rc != 0
      become: no
  • Playbook 実行
$ ansible-playbook playbook.yml
  • エラーとなるため下記を手動で実施 (to be automated)
$ vi .bashrc
export PYENV_ROOT="${HOME}/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
    export PATH=${PYENV_ROOT}/bin:$PATH
    eval "$(pyenv init -)"
fi
$ source ~/.bashrc
  • Playbook 再実行
$ ansible-playbook playbook.yml
  • Python バージョン確認
$ python -V
Python 3.5.2
  • 作業ディレクトリ
$ pwd
/home/vagrant/python3_lessons

はじめてのPythonプログラム

  • インタラクティブモード
$ python
Python 3.5.2 (default, May 20 2017, 02:46:30)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 3 + 2
5
>>> exit()
  • スクリプト作成 (myapp.py)
# coding: utf-8
print("Hello World")
  • 実行結果
$ python myapp.py
Hello World
  • コメント
# coding: utf-8
"""
Comment
Comment
Comment
"""
# Comment
print("Hello World")
  • Python 2 と Python 3 の違い
    • Python 2 では print に括弧は不要だが Python 3 では必須
    • Python 2 では日本語コメントを記載する場合に # coding: utf-8 を明記したが Python 3 では必須ではない

定数について

  • 値を再代入できない
  • Python では言語仕様として定数はサポートされていない
  • 変数名を全て大文字にすると慣習的に定数とみなすことが多いので値の変更は避ける
ADMIN_EMAIL = "yuji@example.com"

データの演算について

  • 変数に他の変数を代入
y = 4
# y = y + 12
y += 12
print(y) # 16
  • 論理計算
print(True and False) # False
print(True or False) # True
print(not True) # False

文字列に値を埋め込んでみよう

  • % を利用した記法
name = "yuji"
score = 52.8

print("name: %s, score: %f" % (name, score))
  • 実行結果
$ python myapp.py
name: yuji, score: 52.800000
  • % を利用した記法 (桁数指定、行揃い指定)
name = "yuji"
score = 52.8
 
print("name: %-10s, score: %10.2f" % (name, score))
  • 実行結果
$ python myapp.py
name: yuji      , score:      52.80
  • {} を利用した記法
name = "yuji"
score = 52.8

print("name: {0}, score: {1}".format(name, score))
  • 実行結果
$ python myapp.py
name: yuji, score: 52.8
  • {} を利用した記法 (桁数指定、行揃い指定)
name = "yuji"
score = 52.8

print("name: {0:>10s}, score: {1:<10.2f}".format(name, score))
  • 実行結果
$ python myapp.py
name:       yuji, score: 52.80

ifで条件分岐をしてみよう

  • ユーザーからの入力を受け付けて if 文で条件分岐 ユーザー入力は文字列が返るので数値に変換が必要
score = int(input("score ? "))

if score > 80:
    print("Great!")
elif score > 60:
    print("Good!")
else:
    print("so so ...")
  • 実行結果
$ python myapp.py
score ? 90
Great!
  • 条件演算子を使った記法 (if else)
score = int(input("score ? "))

print("Great!" if score > 80 else "so so ...")
  • Python ではインデントに半角スペース4つを利用

関数の返り値を使ってみよう

  • 返り値を指定した関数
def say_hi():
     return "hi"
    print("hello") # return 後の記述のため処理されない

msg = say_hi()
print(msg)
  • 実行結果
$ python myapp.py
hi
  • pass の利用 返り値は None という特殊な値
def say_hi():
    pass

msg = say_hi()
print(msg)
  • 実行結果
$ python myapp.py
None

変数のスコープを理解しよう

  • ローカル変数: 関数内で定義された変数
  • グローバル変数: 関数の外で定義された変数
    • 関数内から参照は可能だが書き換えは不可
  • 関数内でグローバル変数を書き換える方法 (明示的にグローバル変数を定義)
msg = "hello" # グローバル変数

def say_hi():
    global msg
    msg = "hello global"
    print(msg)

say_hi()
print(msg)

クラス変数を使ってみよう

class User:
    # クラス変数
    count = 0
    def __init__(self, name):
        User.count += 1
        self.name = name

print(User.count) # 0
tom = User("tom")
bob = User("bob")
print(User.count) # 2

print(tom.count) # 2
  • 実行結果
$ python myapp.py
0
2
2

メソッドを使ってみよう

  • メソッド: クラスに定義した関数
  • コンストラクタもメソッドの一つ
  • インスタンスメソッドとクラスメソッド
class User:
    count = 0
    def __init__(self, name):
        User.count += 1
        self.name = name
    # インスタンスメソッド
    def say_hi(self):
        print("hi {0}".format(self.name))
    # クラスメソッド
    @classmethod
    def show_info(cls):
        print("{0} instances".format(cls.count))

tom = User("tom")
bob = User("bob")

tom.say_hi()
bob.say_hi()

User.show_info()
  • 実行結果
$ python myapp.py
hi tom
hi bob
2 instances

アクセス制限をしてみよう

  • Python では public や private 等のアクセス修飾子はなく慣習的な記法が存在する
  • クラス外からアクセスを禁止したい場合には慣習的に変数名の先頭にアンダースコア「_」を付ける
class User:
  def __init__(self, name):
    self._name = name
  def say_hi(self):
    print("hi {0}".format(self._name))

tom = User("tom")
print(tom._name)
tom.say_hi()
  • 実行結果
$ python myapp.py
tom
hi tom
  • 更に厳密に制限したい場合には変数名の先頭にアンダースコアを2つ「__」付ける
class User:
  def __init__(self, name):
    self.__name = name
  def say_hi(self):
    print("hi {0}".format(self.__name))

tom = User("tom")
print(tom._name)
# print(tom._User__name) # 左記だとアクセス可能という抜け道あり
tom.say_hi()
  • 実行結果
$ python myapp.py
Traceback (most recent call last):
  File "myapp.py", line 18, in <module>
    print(tom._name)
AttributeError: 'User' object has no attribute '_name'

クラスを継承してみよう

  • クラスの継承 (User -> AdminUser)
class User:
    def __init__(self, name):
        self.name = name
    def say_hi(self):
        print("hi {0}".format(self.name))

class AdminUser(User):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
    def say_hello(self):
        print("hello {0} ({1})".format(self.name, self.age))

bob = AdminUser("bob", 23)
print(bob.name)
bob.say_hi()
bob.say_hello()
  • 実行結果
$ python myapp.py
bob
hi bob
hello bob (23)
  • クラスの継承 (オーバーライド)
class User:
    def __init__(self, name):
        self.name = name
    def say_hi(self):
        print("hi {0}".format(self.name))

class AdminUser(User):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
    def say_hello(self):
        print("hello {0} ({1})".format(self.name, self.age))
    # override
    def say_hi(self):
        print("[admin] hi {0}".format(self.name))

bob = AdminUser("bob", 23)
print(bob.name)
bob.say_hi()
bob.say_hello()
  • 実行結果
$ python myapp.py
bob
[admin] hi bob
hello bob (23)

クラスの多重継承をしてみよう

  • Python では親クラスを複数持つことが可能
  • Class A, B を継承した Class C を作成
class A:
    def say_a(self):
        print("A!")
class B:
    def say_b(self):
        print("B!")

class C(A, B):
     pass

c = C()
c.say_a()
c.say_b()
  • 実行結果
$ python myapp.py
A!
B!
  • 親クラスに同名のメソッドが存在する場合は先に継承した親クラスのメソッドが実行される
class A:
    def say_a(self):
        print("A!")
    def say_hi(self):
        print("hi! from A!")
class B:
    def say_b(self):
        print("B!")
    def say_hi(self):
        print("hi! from B!")

class C(B, A):
    pass

c = C()
c.say_hi()
  • 実行結果
$ python myapp.py
hi! from B!

モジュールでファイル分割してみよう

  • モジュール: ファイルを分割するための仕組み
  • user.py を作成し User 関連のコードを分割
class User:
    def __init__(self, name):
        self.name = name
    def say_hi(self):
        print("hi {0}".format(self.name))

class AdminUser(User):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
    def say_hello(self):
        print("hello {0} ({1})".format(self.name, self.age))
    def say_hi(self):
        print("[admin] hi {0}".format(self.name))

print("hello")
  • myapp.py にて user.py をインポート import で読み込んだ瞬間に user.py が実行されるので注意
import user
  
bob = user.AdminUser("bob", 23)
   
print(bob.name)
bob.say_hi()
bob.say_hello()
  • 実行結果
$ python myapp.py
hello
bob
[admin] hi bob
hello bob (23)
  • モジュールから指定したクラスや関数のみを import することも可能
  • myapp.py (AdminUser, User クラスを個別にインポート)
from user import AdminUser, User

bob = AdminUser("bob", 23)

tom = User("tom")

print(bob.name)
bob.say_hi()
bob.say_hello()
  • user.py
class User:
    def __init__(self, name):
        self.name = name
    def say_hi(self):
        print("hi {0}".format(self.name))

class AdminUser(User):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
    def say_hello(self):
        print("hello {0} ({1})".format(self.name, self.age))
    def say_hi(self):
        print("[admin] hi {0}".format(self.name))

# print("hello")
  • 実行結果
$ python myapp.py
bob
[admin] hi bob
hello bob (23)

パッケージでモジュールを管理しよう

  • パッケージ: モジュールをフォルダにまとめたもの
  • パッケージを Python で認識させるにはフォルダの中に特殊なファイル "__init__.py" が必要
  • ディレクトリ構造 (mypackage 配下に user.py を移動)
/home/vagrant/python3_lessons
|--myapp.py
|--mypackage
|  |--__init__.py
|  |--user.py
  • myapp.py
import mypackage.user
  
bob = mypackage.user.AdminUser("bob", 23)
  
print(bob.name)
bob.say_hi()
bob.say_hello()
  • 実行結果
$ python myapp.py
bob
[admin] hi bob
hello bob (23)
  • myapp.py (パッケージ名に別名を付ける)
import mypackage.user as mymodule

bob = mymodule.AdminUser("bob", 23)

print(bob.name)
bob.say_hi()
bob.say_hello()
  • myapp.py (AdminUser のみインポート)
from mypackage.user import AdminUser

bob = AdminUser("bob", 23)

print(bob.name)
bob.say_hi()
bob.say_hello()

例外処理をしてみよう

  • myapp.py (Python 標準の例外を処理)
def div(a, b):
    try:
        print(a / b)
    except ZeroDivisionError:
        print("not by zero!")
    else:
        print("no exception!")
    finally:
        print("-- end --")

div(10, 3)
div(10, 0)
  • 実行結果
$ python myapp.py
3.3333333333333335
no exception!
-- end --
not by zero!
-- end --
  • myapp.py (Exception クラスを継承して独自の例外を処理)
class MyException(Exception):
    pass

def div(a, b):
    try:
        if (b < 0):
            raise MyException("not minus")
        print(a / b)
    except ZeroDivisionError:
        print("not by zero!")
    except MyException as e:
        print(e)
    else:
        print("no exception!")
    finally:
        print("-- end --")

div(10, -3)
  • 実行結果
$ python myapp.py
not minus
-- end --

リスト型を使ってみよう

  • リスト型
    • 順序性を保持した値の集合
    • 異なる型の値を保持可能
  • for 文で enumerate を利用して何番目の要素かも取り出すことが可能
scores = [40, 50]
# print(scores[0]) # 40
# scores[0] = 45
# print(len(scores)) # 2
# scores.append(100)
# print(scores)

# for score in scores:
#     print(score)

for i, score in enumerate(scores):
    print("{0}: {1}".format(i, score))
  • 実行結果
$ python myapp.py
0: 40
1: 50

タプルを使ってみよう

  • タプル
    • 順序性を保持した値の集合
    • 異なる型の値を保持可能
    • 値の変更が不可
  • リストと相互に変換可能
# items = (50, "apple", 32.5)
# print(items[1])
# items[1] = "pen"  # エラー発生

print(list((1, 3, 5)))
print(tuple([1, 3, 5]))
  • 実行結果
$ python myapp.py
[1, 3, 5]
(1, 3, 5)

スライスで要素を切り出してみよう

  • スライス: 部分的なリストを作る機能
  • リスト型に対するスライスの使用
scores = [40, 50, 70, 90, 60]
print(scores[1:4]) # 50, 70, 90
print(scores[:2]) # 40, 50
print(scores[3:]) # 90, 60
print(scores[-3:]) # 70, 90, 60
  • 実行結果
$ python myapp.py
[50, 70, 90]
[40, 50]
[90, 60]
[70, 90, 60]
  • 文字列に対するスライスの使用
s = "hello"
print(s[1:4])
  • 実行結果
$ python myapp.py
ell

集合型を使ってみよう

  • セット (集合型)
    • 順序性を保持しない
    • 重複を許さない値の集合
  • myapp.py
# a = set([5, 4, 8, 5])
a = {5, 3, 8, 5}
print(a)
print(5 in a) # True
a.add(2)
a.remove(3)
print(a)
print(len(a))
  • 実行結果
$ python myapp.py
{8, 3, 5}
True
{8, 2, 5}
3
  • myapp.py (集合演算を実行)
a = {1, 3, 5, 8}
b = {3, 5, 8, 9}
print(a | b)
print(a & b)
print(a - b)
  • 実行結果
$ python myapp.py
{1, 3, 5, 8, 9}
{8, 3, 5}
{1}

辞書型を使ってみよう

  • 辞書型: キーと値でデータを管理するデータ型
  • myapp.py
sales = {"tanaka": 200, "sato": 400}
print(sales["tanaka"])
sales["tanaka"] = 300
sales["kobayashi"] = 500
del(sales["sato"])
print(sales)
  • 実行結果
$ python myapp.py
200
{'kobayashi': 500, 'tanaka': 300}
  • 辞書型に対するループ処理 (items を利用)
sales = {"tanaka": 200, "sato": 400}
     
for key, value in sales.items():
    print("{0}: {1}".format(key, value))
  • 実行結果
$ python myapp.py
sato: 400
tanaka: 200

イテレータを理解しよう

  • イテレータ: 次の要素を返すデータの集合
  • リストからイテレータへの変換
scores = [40, 50, 70, 90, 60]
it = iter(scores)
print(next(it))
print(next(it))
print("hello")
print(next(it))
  • 実行結果
$ python myapp.py
40
50
hello
70
  • 以下の for 文では内部的にイテレータに変換して処理されている
for score in scores:
    print(score)
  • リストからの変換ではない独自のイテレータ作成
  • ジェネレータ
    • イテレータを作る関数
    • next() が呼ばれた時に初めて次の要素を探しにいく仕様のため無限の要素を扱うことも可能
def get_infinite(): # ジェネレータ
    i = 0
    while True:
        yield i * 2
        i += 1

g = get_infinite()
print(next(g))
print(next(g))
print(next(g))
  • 実行結果
$ python myapp.py
0
2
4

map、lambdaを使ってみよう

  • map
    • イテレータの関数を加工するもの
    • 第1引数に関数、第2引数にイテレータを指定
    • ジェネレータを返す
def triple(n):
    return n * 3

print(list(map(triple, [1, 2, 3])))
  • 実行結果
$ python myapp.py
[3, 6, 9]
  • ラムダ式を利用した記述
    • lambda 引数: 処理
print(list(map(lambda n: n * 3, [1, 2, 3])))
  • 実行結果
$ python myapp.py
[3, 6, 9]

filterで要素を抽出しよう

  • filter
    • 条件に合致したものを抽出してくれる関数
    • 第1引数が関数、第2引数がイテレータ
  • 0〜9 のリストから偶数を抽出
def is_even(n):
    return n % 2 == 0

print(list(filter(is_even, range(10))))
  • 実行結果
$ python myapp.py
[0, 2, 4, 6, 8]
  • ラムダ式を利用した記述
print(list(filter(lambda n: n % 2 == 0, range(10))))
  • 実行結果
$ python myapp.py
[0, 2, 4, 6, 8]

内包表記を使ってみよう

  • 内包表記
    • リストやジェネレータを生成したり加工する際に書くための記法
  • 0〜9 のリストを作成し1つずつ要素を取り出して表示
print([i for i in range(10)])
  • 実行結果
$ python myapp.py
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • 要素を取り出す際に各要素を3倍
print([i * 3 for i in range(10)])
  • 実行結果
$ python myapp.py
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
  • if 文を利用して条件付きで要素を抽出
print([i * 3 for i in range(10) if i % 2 == 0])
  • 実行結果
$ python myapp.py
[0, 6, 12, 18, 24]
  • ジェネレータや集合型を作成
print(i * 3 for i in range(10) if i % 2 == 0) # ジェネレータ
print({i * 3 for i in range(10) if i % 2 == 0}) # 集合型
  • 実行結果
$ python myapp.py
<generator object <genexpr> at 0x7ff29cb74bf8>
{0, 24, 18, 12, 6}

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-06-29 (木) 11:33:14 (2490d)