#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()