#contents

** Pythonを使ってみよう [#peb4c9dd]

- 概要
-- シンプルで習得がしやすいオブジェクト指向言語
-- データ解析、機械学習

- 公式サイト
-- https://www.python.org/

- 環境
-- Vagrant ローカル開発環境 (CentOS 6.7)

** Python 3 インストール [#j4dacc82]

- 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

-  &color(red){※}; エラーとなるため下記を手動で実施 (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プログラム [#x1a702dc]

- インタラクティブモード

 $ 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 では必須ではない

** 定数について [#s903f012]

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

 ADMIN_EMAIL = "yuji@example.com"

** データの演算について [#z883940a]

- 変数に他の変数を代入

 y = 4
 # y = y + 12
 y += 12
 print(y) # 16

- 論理計算

 print(True and False) # False
 print(True or False) # True
 print(not True) # False

** 文字列に値を埋め込んでみよう [#sadcc680]

- % を利用した記法

 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で条件分岐をしてみよう [#p91e87f8]

- ユーザーからの入力を受け付けて if 文で条件分岐 &color(red){※}; ユーザー入力は文字列が返るので数値に変換が必要

 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 ...")

- &color(red){※}; Python ではインデントに半角スペース4つを利用

** 関数の返り値を使ってみよう [#qa75b13b]

- 返り値を指定した関数

 def say_hi():
      return "hi"
     print("hello") # return 後の記述のため処理されない
 
 msg = say_hi()
 print(msg)

- 実行結果

 $ python myapp.py
 hi

- pass の利用 &color(red){※}; 返り値は None という特殊な値

 def say_hi():
     pass
 
 msg = say_hi()
 print(msg)

- 実行結果

 $ python myapp.py
 None

** 変数のスコープを理解しよう [#ka60680e]

- ローカル変数: 関数内で定義された変数
- グローバル変数: 関数の外で定義された変数
-- 関数内から参照は可能だが書き換えは不可

- 関数内でグローバル変数を書き換える方法 (明示的にグローバル変数を定義)

 msg = "hello" # グローバル変数
 
 def say_hi():
     global msg
     msg = "hello global"
     print(msg)
 
 say_hi()
 print(msg)

** クラス変数を使ってみよう [#v2f54ead]

 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

** メソッドを使ってみよう [#cbef8a74]

- メソッド: クラスに定義した関数
- コンストラクタもメソッドの一つ

- インスタンスメソッドとクラスメソッド

 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

** アクセス制限をしてみよう [#x4a6b95e]

- 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'

** クラスを継承してみよう [#k0c88893]

- クラスの継承 (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)

** クラスの多重継承をしてみよう [#p48508e6]

- 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!

** モジュールでファイル分割してみよう [#y599f84d]

- モジュール: ファイルを分割するための仕組み
- 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 をインポート &color(red){※}; 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)

** パッケージでモジュールを管理しよう [#p7a80104]

- パッケージ: モジュールをフォルダにまとめたもの
- パッケージを 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()



トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS