LoginSignup
433
523

More than 3 years have passed since last update.

Python3基礎文法

Last updated at Posted at 2017-03-31

Python3を基礎から学ぶ。

※注意
私が書いたこの記事は、私が理解できる内容の情報量で書いてしまった部分があり、抜け落ちている部分があります。なのでこの記事ではPython3の文法の一部をさらっとでしか紹介できてません。従って実践的なPython3の文法を身に付けたい場合は以下の本家のチュートリアルを参考にして写経するのを、強く強くお勧めします。 :pencil:

Python チュートリアル

Pythonを始めてみよう。

  • 概要
    • シンプルでわかりやすいオブジェクト指向プログラミング言語である。
    • 取得しやすい。
    • 機械学習でも使いやすい。

環境構築

  • Qiitaに導入記事を上げました。

初期セットアップ

# いつもの
sudo apt-get update
# -yで問い合わせがあった場合はすべて「y」と答える
sudo apt-get upgrade -y
# パッケージ構成の変更に追随してアップグレード
sudo apt-get dist-upgrade
# Pythonのビルドに必要なものをインストール。
sudo apt-get install build-essential libncursesw5-dev libgdbm-dev libc6-dev zlib1g-dev libsqlite3-dev tk-dev libssl-dev openssl libbz2-dev libreadline-dev


Pythonセットアップ

pyenvを使う為にセットアップしていきます。

git clone https://github.com/yyuu/pyenv.git ~/.pyenv
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profile
source ~/.profile

pythonの最新バージョンを確認する。
今回は3.6.0をインストールします。

Python3をインストールする。

pyenv install 3.6.0

この状態ではまだデフォルトが2.7.9なので、導入した3.6.0をglobalとして設定を反映させます。

pyenv global 3.6.0
pi@raspberrypi:~ $ python -V
Python 3.6.0
pi@raspberrypi:~ $

でokです。

Hello Python3!

Hello wold!を実行してみましょう。

  • 1行:#
  • 復数行:""" コメント """

ex:コメントアウト

"""
この中もコメントアウトになります。
複数行
コメント!
コメント!
"""
# コメントです!
print("Hello wold!")

#result
python hello.py
Hello wold!
  • Python3ではprintの後ろは必ず()で囲って上げる。
  • セミコロンはいらない。

それから、Python 2 まではソースコードに日本語が含まれていた場合、1 行目か 2 行目に # coding: utf-8 と書く必要があったのですが、Python 3 では不要になっています。

変数を使ってみよう

  • 変数

ex:変数

msg = "Heelo wold!"
print(msg)

変数を1つにして、値を変える。

ex:変数を1つにする。

msg = "Hello wold!"
print(msg)
msg = "Hello Endo!"
print(msg)

# result
Hello wold!
Hello Endo!

定数

値の再代入はできない。

実は Python ではそうした定数を言語としてサポートしていないのですが、変数名を全て大文字にしたら定数のように扱おう、というのが慣習的なルールになっています。

ex:定数

ADMIN_EMAIL = "endo@gmail.cpm"

msg = "Hello wold!"
print(msg)
msg = "Hello Endo!"
print(msg)
print(ADMIN_EMAIL)

# result

pi@raspberrypi:~/src/python3_study $ python hello.py
Hello wold!
Hello Endo!
endo@gmail.cpm

扱えるデータ型

  • 文字列
    • ""で囲む。
    • 復数の行を表現したい時は"""で囲む
      • この記法を使ってプログラム中に文章を書いても処理には影響を与えないという特徴があるので、結果的にこれらがコメントとして使われているという仕組みだったりします。
    • 特殊文字
      • 改行`\n
      • tab \t``
  • 数値
  • 整数
    • i=10
  • 浮動小数
    • v=23.4
  • 論理値
    • True(Tは大文字),False(Fは大文字)

データの演算

  • 基本 : + - * % /
  • 切り捨て除算 ://
  • べき乗 : **

ex:データ演算

x = 10

#割り算
 print(x/3)

# 除算
print(x //3)

# 余り
print(x % 3)

#べき乗
print(3 ** 2)

result

3.3333333333333335
3
1
9

計算の簡略化

ex:計算の簡略化

# 短い演算
y = 4
#y = y+12
y += 12
print(y) # 16

True False

  • andの時はFalseが優先される。
  • orの時はTrueが優先される。

ex:True,Flaseの評価式

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

# result
False
True
False

文字連結,繰り返し

ex:文字列の連結,繰り返し


print("hello"+"world")
print("hello" * 3)

# result

helloworld
hellohellohello

文字列に値を埋め込む。

文字列フォーマット指定

  • %s:文字列型
  • %d:数値型 
  • %f:浮動少数

ex:文字列の埋め込み

name = "Endo"
score = 52.6

# %で文字列埋め込み(整数は%d)
print("name: %s,score:%f" %(name,score))

# 桁数表示幅を指定する。
# %10s =10の幅を持たせる。%10.2f=10の幅を持たせて小数点2桁にする。
print("name: %10s,score:%10.2f" %(name,score))
# 左揃えにする。
print("name: %-10s,score:%-10.2f" %(name,score))

result

name: Endo,score:52.600000
name:       Endo,score:     52.60
name: Endo      ,score:52.60

{ }:波括弧で指定する。

  • {}で囲んだ部分にformatで指定する。

ex:formatで指定する。


name = "Endo"
score = 52.6
# {}を使う。
print("name:{0},score:{1}".format(name,score))
# 桁数を指定する。
print("name:{0:10s},score:{1:10.2f}".format(name,score))
# >右揃え <左揃え
print("name:{0:>10s},score:{1:<10.2f}".format(name,score))


#result

name:Endo,score:52.6
name:Endo      ,score:     52.60
name:      Endo,score:52.60

if文

基本

  • if
  • elif(else if)
  • else

ex:if文

# if
score=int(input("score ? "))
if score > 80:
    print("Great!")
elif score > 60:
    print("Good!")
else:
    print("So So!")

条件演算子

ex:条件演算子

# 条件演算子
print("Great!" if score > 80 else "so so! ..")

Whileループ

Whileの条件が真(True)である限り繰り返します。

ex:whileループ

i = 0
name = "endo"

while i < 10:
    if i == 5:
        break
    #print("{0:}:{1:}".format(i,name)
    print("%d:%s"%(i,name))
    i += 1
else:
    print("finish!")


# result

0:endo
1:endo
2:endo
3:endo
4:endo

forループ

  • for 変数 in データの集合

データの集合が肝。Pythonの場合は組み込み関数であるrangeを使うことで、データの集合が出来る。

ex:for文

# for文

# for 変数 in データの集合
# 処理

# range(0,10)なので、0から9が含まれる集合が作られる。
for i in range(0,10):
    if i == 5:
        #break
        # iが5の時にスキップする。
        continue
    print(i)
#終了後の処理
else:
    print("Finish!")

result

0
1
2
3
4
#5がcontinueでスキップされている。
6
7
8
9
Finish!

関数

基本型

ex:関数の基本形

def 関数名():
    #インデントを空ける。
    ****

ex:say_hi関数

# 関数
#
def say_hi(name,age):
    print("Hi! {0} age({1})".format(name,age))

# 関数呼び出し
say_hi("tom",23)
say_hi("Bob",24)

# result

Hi! tom age(23)
Hi! Bob age(24)

デフォルト値。

  • デフォルト値を予め決めておく事も出来る。
    • def say_endo(name="endo",age=23):

ex:デフォルト値の設定。


def say_endo(name="endo",age=23):
    print("Hi! {0} age({1})".format(name,age))

say_endo()
say_endo("steave")
# 順番は関係なく引数を与える。
say_endo(age=18,name="Takahashi")


# result

Hi! endo age(23)
Hi! steave age(23)
Hi! Takahashi age(18)

返り値がある場合

  • returnを使って任意の返り値を記述する。

ex:返り値ありの関数

# 関数 返り値が返ってくる。

def say_hi():
    # print("hi")
    return "hi"
#これ以降の処理は実行されないです。
    print("Hello")
# あくまでも値が返ってくるので、関数呼び出しでは標示されない
say_hi()
msg = say_hi()
print(msg)

result

hi

pass付き関数

  • passは関数の中身を書かずに、関数だけ用意できる。返り値はNoneとなる。

ex:pass付き関数

def test():
    # 関数の中身を今書かないであとで記述したい時にpassを入れる。
    pass

msg = test()
# 何も返ってこないので`None`が返ってくる。
print(msg)

result

None

スコープ

  • グローバル変数:どこからでもアクセスできる。
  • ローカル変数:関数内からアクセスを行う。

ex:スコープ

# 関数

msg = "Hello Global!" #グローバル変数

def say_hi():
    #関数の中で宣言された変数はこの関数の中でのみ有効である。
    #スコープ
    msg = "Hello Local!" # ローカル変数
    print(msg)
say_hi()
print(msg)

result

Hello Local!
Hello Global!

それからグローバル変数なのですが、関数の中からは参照できるけれども書き換えることはできないというルールがあります。

変数の前にglobalを付ける事で関数内から書き換えが簡単となる。


msg = "Hello Global!" #グローバル変数
def say_hi():
    #globalを付ける事で関数内で書き換え可能となる。
    global msg
    msg = "change global 2 local "
    print(msg)#グローバル変数を参照できる。
say_hi()
print(msg)

result

change global 2 local
Hello Global!

クラス

  • Python3におけるクラスは、クラス宣言で事前にプロパティを書かなくても、後からインスタンス呼び出し後に好きにプロパティを追加できる。

これ凄い...!つまりpassで空クラス作るだけで、オブジェクトに自由にプロパティを後から追加してもいい。

けどなんか気持ち悪いなぁ....

ex:クラス

# クラス

# クラスの中身は空
class User:
    pass # 空のクラス

tom = User()#インスタンス
tom.name = "Tom Jyon"
tom.score = 20

bob = User()#インスタンス
bob.name = "Bob"
bob.level = 10

print(tom.name)
print(tom.score)

print(tom.name)
print(bob.level)

result

Tom Jyon
20
Tom Jyon
10

コンストラクタ

前回見た User クラスなのですが、空のクラスを作って好きに属性を加えていってもいいのですが、クラスごとに属性を統一させたり、インスタンスを作るときに初期値を与えたい場合がほとんどです。

コンストラクタは以下の様に記述する。

ex:コンストラクタの基本形(def __init__():)

class
    def __init__():

ex:コンストラクタによる初期化

class User:
    #コンストラクタ(初期値)a

    #selfはこのクラスから作られるインスタンスを指します。
    def __init__(self,name):
        # インスタンス変数
        self.name = name

tom = User("Tom")
bob = User("Bob")

print(tom.name)
print(bob.name)

result

Tom
Bob

この時self.nameはインスタンス変数として扱います。

クラス変数

クラス変数はインスタンスを作らなくても呼び出せます。
呼び出す際は、クラス名:プロパティ名とここではUser.countがクラス変数に相当します。

ex:クラス変数

class User:
    count = 0
    #コンストラクタ(初期値)
    def __init__(self,name):
        # クラス変数
        User.count += 1;
        # インスタンス変数
        self.name = name

print(User.count)

tom = User("Tom")
bob = User("Bob")
print(User.count)

# クラスのプロパティであるから、tomのインスタからでも呼び出す事が出来る。
print("tom is count {0}".format(tom.count))

result

0
2
tom is count 2

メソッド

クラスなのですが、コンストラクタ以外にも関数を定義することができて、クラスに定義した関数をメソッド というので、まずは用語としておさえておいてください

インスタンスメソッド

名前の通りで**インスタンス変数(self)**をそのまま使えうメソッド

ex:インスタンスメソッド


class User:
    count = 0
    #コンストラクタ
    def __init__(self,name):
        User.count += 1;
        self.name = name
    #インスタンスメソッド
    def say_hi(self):
        print("hi! {0}".format(self.name))

tom = User("Tom")
bob = User("Bob")

tom.say_hi()
bob.say_hi()

result

Tom
Bob

クラスメソッド

  • **クラス変数(cls)**をそのまま使えるメソッドです。
  • インスタンスを生成しないで、クラス内のメソッドを呼び出せます。

ex:クラスメソッド

class User:
    count = 0
    #コンストラクタ
    def __init__(self,name):
        User.count += 1;
        self.name = name
    #クラスメソッド
    @classmethod#(デコレーター)
    def show_info(cls):
        print("{0}:instances".format(cls.count))

# クラスメソッド
User.show_info()
tom = User("Tom")
User.show_info()

result

0:instances
1:instances

アクセス制限

  • Pythonにはprivatepublic的なアクセス権を明示的に宣言できないので、暗黙のルールーとして__を変数名の前につける。

ex:アクセス制限

class User:
    count = 0
    #コンストラクタ
    def __init__(self,name):
        User.count += 1;
    # クラス外からアクセスしない様に明示的に宣言する。
        self.__name = name
    #インスタンスメソッド(インデントは上に合わせる!)
    def say_hi(self):
        print("hi! {0}".format(self.__name))


tom = User("Tom")
bob = User("Bob")

##  見える
print(tom.__name)

エラーが起きる。

result

Traceback (most recent call last):
  File "method_limt.py", line 20, in <module>
    print(tom.__name)
AttributeError: 'User' object has no attribute '__name'

が、これは特集な機能をつかっているだけであって例えば
tom._User__nameで書き直すと、表示出来てしまいます。

print(tom._User__name)

result

Tom

クラス継承

name のほうは親クラスのコンストラクタを使って設定してあげます。
親クラスは super() というキーワードで表現できるので、super().__init(name)__ としてあげれば OK でしょう。

クラス継承とsuper() メソッド

ex:クラスの継承

# User(親クラス) -> AdminUser(サブクラス)
class User:

    """ 親クラスのコンストラクタ """
    #selfはクラスのインスタンス自身
    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):
        """
        親クラス(Userの)__init__ メソッド
        (コンストラクタ)で
        name を初期化する処理がすでに存在するので、
        それをサブクラス(AdminUser)の中でも再利用を
        する為にsuper()を使う。
        """
        #これを呼び出す事で`self.name`が使える。
        # つまりここは、親クラスのself.nameと同じ場所を参照している。
        super().__init__(name)

        self.age = age

        #親クラスのプロパティを書き換える前。
        print("子クラスでsuper()を使った親クラスのプロパティ呼び出すされるnameは{0}".format(self.name))

        #親クラスのプロパティを書き換える。
        self.name = "Endo"
        print("子クラスで親クラスのプロパティを書き換えた後に呼び出されるname>は{}".format(self.name))

    # インスタンスメソッド
    def say_hello(self):
        print("Hello!! {0} age:{1}".format(self.name, self.age))

print("継承前の世界")
bob = User("Bob")
bob.say_hi()

print("継承後の世界")
bob = AdminUser("bob",22)
bob.say_hi()

print(bob.name)
# 小クラス(サブクラス)のインスタンスメソッド
bob.say_hello()
bob.say_hi()

result

継承前の世界
親クラスでのnameはBob
[親クラスのメソッド]Hi! Bob

継承後の世界
親クラスでのnameはbob
子クラスでsuper()を使った親クラスのプロパティ呼び出すされるnameはbob
子クラスで親クラスのプロパティを書き換えた後に呼び出されるnameはEndo
[親クラスのメソッド]Hi! Endo

Endo
Hello!! Endo age:22
[親クラスのメソッド]Hi! Endo

ここで注目して欲しいのは

  • 継承後の親クラスメソッドであるsay_hiが呼び出される際に、サブクラスで定義した、コンストラクタ(def __init__(self,name,age):)も実行される為に以下の2つも実行されている。

    • print("子クラスでsuper()を使った親クラスのプロパティ呼び出すされるnameは{0}".format(self.name))
    • print("子クラスで親クラスのプロパティを書き換えた後に呼び出されるname>は{}".format(self.name))
  • super().__init__(name)は親クラスで定義しているコンストラクタ()を子クラスでも使う為にsuper() を呼び出している。super()は親クラスを指す。従ってこの宣言をする事で、子クラスでもself.nameを使えるようになる。

親クラスのメソッドを小クラスでオーバーライドする。

子クラス(AdminUsr)で親クラス(User)クラスメソッド(say_hi)をオーバーライドする為に、同じ名前のメソッドを追加する。

ex:AdminUserクラスにsay_hi()追加後


class User:
    def __init__(self,name):
        self.name= name
        print("親クラスでのnameは{0}".format(self.name))
    def say_hi(self):
        print("[親クラスのメソッド]Hi! {0}".format(self.name))
# クラスの継承
class AdminUser(User):
    def __init__(self,name,age):
        #初期化
        super().__init__(name)
        self.name = "Endo"

    def say_hello(self):
        print("Hello!! {0} age:{1}".format(self.name, self.age))

    #親クラスのメソッドのオーバーライド
    def say_hi(self):
        print("[子クラス()でオーバーライド後のメソッド] hi {0}".format(self.name))

print("継承前の世界")
bob = User("Bob")
bob.say_hi()

print("継承後の世界")
bob = AdminUser("bob",22)
bob.say_hi()

print(bob.name)
# 小クラス(サブクラス)のインスタンスメソッド
bob.say_hello()
#親クラスのメソッドをOverrideする
bob.say_hi()

result

継承前の世界
親クラスでのnameはBob
[親クラスのメソッド]Hi! Bob

継承後の世界
親クラスでのnameはbob
子クラスでsuper()を使った親クラスのプロパティ呼び出すされるnameはbob
子クラスで親クラスのプロパティを書き換えた後に呼び出されるnameはEndo
[子クラス()でオーバーライド後のメソッド] hi Endo ## 子クラスでオーバーライドされた。

Endo
Hello!! Endo age:22
[子クラス()でオーバーライド後のメソッド] hi Endo ## 子クラスでオーバーライドライドされた。

クラスの多重継承

ex:CにA,Bを多重継承を行う。

# クラスの継承を考える。

# A,B->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()

result

A
B

ただ、多重継承で問題になるのが、クラス A、B で同じメソッドがあった場合です

なのでもしメソッド名を一緒にするとこうなる。

ex:先にAが来ているので多重継承したCではAメソッド優先される。

# クラスの継承を考える。

# A,B->C

class A:
    def say_hi(self):
        print("Hi Form A")

class B:
    def say_hi(self):
        print("Hi Form B")

# クラスの多重継承

class C(A, B):
    pass

c = C()
c.say_hi() # Hi from Aになる。

result

Hi from A

これは継承を指定するときの順番が影響していて、同じメソッドがあった場合は、先に指定したほうのメソッドが優先されます。

なので逆にC(B,A)とすると

ex:先にBが来ているので多重継承したCではBメソッド優先される。

class C(B, A):
    pass
c = C()
c.say_hi() # Hi from Bになる。

モジュール分割

  • モジュールを読み込み為には

    • import モジュール名
  • 特定のモジュール名らクラスやメソッドを呼び出したい時はどうするか。

    • from モジュール名 import クラス名
    • from モジュール名 import メソッド名

モジュールを読み込みとprint()などの命令が実行されてしまう事に注意します。

ex :モジュールファイル

# 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):
        #self.name = name
        super().__init__(name)
    def say_hello(self):
        print("Hello!{0}".format(self.name))

print("モジュールから出力したHello!です")

ex:呼び出しファイル

# モジュール
# この時はモジュール名を指定してあげないといけない。
import user

# モジュールから指定した関数やクラスを読み込む
# この時はモジュール名を指定しなくて良い。
from user import AdminUser

# import呼び出しでのUserクラス
tom =user.User("tom")

# from呼び出しでのUserモジュールのAdminUserクラス
bob = AdminUser("bob",23);

print(bob.name)
bob.say_hi()#親クラスのメソッド
bob.say_hello() #抽象クラスのメソッド

result

モジュールから出力したHello!です
bob
Hi!bob
Hello!bob

  • 複数のクラスを指定して読み込むにはカンマ区切りにしてげればいい。

from user import AdminUser //Userを継承したAdminUserクラス をimportする。

  • 復数のモジュールを読み込際には以下の様に、(カンマ)区切で記述する)

ex:復数のモジュールを読み込む

from user import AdminUser,User
#import
#tom =user.User("tom")

#from
tom =User("tom")
# from
bob = AdminUser("bob",23)

print(bob.name)
bob.say_hi()#親クラスのメソッド
bob.say_hello() #抽象クラスのメソッド

resultは同じ。

パッケージをモジュールで管理する。

パッケージを Python で認識させるには、そのフォルダの中に特殊なファイルが必要です。ファイル名は決まっていて、init.py としてあげてください。

パッケージはフォルダがモジュール化したものと考えて良い。

パッケージからモジュール呼び出し。

  • import パッケージ名.モジュール名
  • インスタンス呼び出し
    • hoge = パッケージ名.モジュール名.クラス名()

パッケージとモジュールファイルが置かれているツリー構造は以下の通りになる。

mypackage # パッケージ(ディレクトリ名)
    |--  user.py # モジュール
    |-- __init__.py

ex:モジュールファイル(user.py)をパッケージ経由で呼び出す。

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):
        #self.name = name
        super().__init__(name)
    def say_hello(self):
        print("Hello!{0}".format(self.name))

# モジュールが呼び出された時点で実行される。
print("パッケージから呼び出したモジュールから出力したHello!です")

ex:呼び出した元ファイル

#(1) 一般的なモジュール呼び出し
import mypackage.user

# (1)
tom = mypackage.user.User("tom")
bob = mypackage.user.AdminUser("bob",23)

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

result

#パッケージから呼び出したモジュールから出力したHello!です
tom
Hi! tom
bob
Hello! bob

asを使って、名前付けする。

  • import パッケージ名.モジュール名 as Name
  • インスタンス呼び出し
    • hoge = Name.クラス名()

ex:asで名前付けして簡略化させる。

#(2) を使って明示的に名前をつける。
import mypackage.user as MyModule

#(2)
tom =MyModule.User("tom")
bob = MyModule.AdminUser("bob",23)
print(tom.name)
tom.say_hi()
print(bob.name)
bob.say_hello()

result

パッケージから呼び出したモジュールから出力したHello!です
tom
Hi!tom
bob
Hello!bob

特定のクラスやメソッドだけを呼び出す。

  • from パッケージ名.モジュール名 import クラス名
  • インスタンス呼び出し
    • hoge = クラス名() # そのまま書ける。

ex:モジュールから特定のクラス、メソッドを呼び出す。


#(3)fromで特定の関数のみ読み込む => パッケー名.モジュール名は省略して良い。
from mypackage.user import AdminUser


#(3)
bob = AdminUser("bob",23)
print(bob.name)
bob = AdminUser("bob",23)
print(bob.name)
bob.say_hi() # 親クラスメソッド
bob.say_hello() #子クラスメソッド

result

パッケージから呼び出したモジュールから出力したHello!です
bob
Hi!bob
Hello!bob

例外処理

予め用意されているクラスを使う。

ex:例外処理の基本構文

def Hge()
    try:
        # 例外が起こりそうな処理を記述する。
    except 例外が起きた際に呼び出されるクラス名:
        # 表示するメッセージ
    else:
        # 例外がおきなかった場合の処理
    finaly:
        # 例外関係なく実行して欲しい処理

ex:Pythonで備え付けられるクラス(0除算:ZeroDivisionError)を元に例外を発生させる。

# 例外処理
def div(a,b):
    try:
        #0除算
        print(a/b)
    #例外発生時の処理
    except ZeroDivisionError:
        print("not by zaro")
    #例外が発生しなかった時の処理
    else:
        print("no exception!")
    #例外が発生しようが、しないようが最期に実行に実行して欲しい処理を記述する
    finally:
        print("-- end -- 処理が終わりました")
div(10,3)
div(10,0)

result

3.3333333333333335
no exception!
-- end -- 処理が終わりました
not by zaro
-- end -- 処理が終わりました

独自で例外処理を記述する。

ex:基本構文

class MyException(Exception):
    # 空のクラスを作る
    pass

def hoge:
    try:
            raise MyException("not minus!")
    #独自例外発生時の処理
    except MyException as e:
        # eには先程自分で作った独自の例外処理のエラーメッセージが入っている
        print(e)

ex:独自で例外処理を作った場合

# 独自の例外処理を作る
class MyException(Exception):
    # 空のクラスを作る
    pass

def div(a,b):
    try:
        if( b < 0):
            raise MyException("not minus!")
    #例外発生時の処理
    except ZeroDivisionError:
        print("not by zaro")
    #例外発生時の処理
    except MyException as e:
        # eには先程自分で作った独自の例外処理のエラーメッセージが入っている
        print(e)


    #例外が発生しなかった時の処理
    else:
        print("no exception!")
    #例外が発生しようが、しないようが最期に実行に実行して欲しい処理を記述する
    finally:
        print("-- end -- 処理が終わりました")
div(10,-3)
div(10,0)

result

not minus!
-- end -- 処理が終わりました
no exception!
-- end -- 処理が終わりました

リスト型とタプル

  • リスト型とタプル:順序付きのデータ型

リスト型

リストってキーとバリューがセットだと思ったので、「それ配列じゃね?」と思ったけど、調べてみたら違ってた。

具体的にはこういう事らしい。

データ構造 要素の数 格納できるデータ型 メモリの確保
配列 決まっている。 予め決められた型だけ 静的メモリ確保
リスト 決まっていない。 どんな型でも 動的メモリ確保
  • [ ]:中に値をいれていけば、その時点でlistになる。
  • 要素は0から始まる。

ex :list1

scores = [40,50]

print(scores[0])
print(scores[1])

resut

40
50
  • len:要素の長さを求める。
  • appened:要素の末尾に値を追加する。

ex:list2

scores = [40,50]

print(scores[0])
print(scores[1])


# 要素の個数を調べる = len
print("要素の長さは:{0}".format(len(scores)))
# 要素の末尾にに追加する。 = append
scores.append(100)
print(scores)
print("要素の長さは:{0}".format(len(scores)))

result

40
50
要素の長さは:2
[40, 50, 100]
要素の長さは:3
  • enumerate:要素番号を指定して値を取り出したい場合には、enumerate という命令を使う。

ex:list3

scores = [40,50]

print(scores[0])
print(scores[1])

scores.append(100)

print("バリューだけ表示する。")
#  forと組み合わせる。
for score in scores:
		#各要素を順々に出力する。
		print(score)
# 何番目の要素かも取り出したい場合には、enumerate という命令を使えば OK です。

print("要素数とバリューを表示する。")

for i,score in enumerate(scores):
		print("{0}:{1}".format(i,score))

result

バリューだけ表示する。
40
50
100
要素数とバリューを表示する。
0:40
1:50
2:100

タプル型

リストでは同種のデータを扱うことが多いのですが、タプルでは違う種類のデータを含めることが多い。勿論リストでも同じ様に違う種類のデータを含める事は可能

  • ():中に値をいれていけば、その時点でtupleになる。
  • 要素は0から始まる。

ex:tuple1

# タプル

items = (50,"apple",32.5)

# for文で回す
for item in items:
    print(item)

result

50 # 整数
apple #文字列
32.5 #浮動小数点
  • タプルでは値を書き換えられません

ex:tuple2

items = (50,"apple",32.5)
items[0] = 20
~

result:エラーが実行される。(値の変更ができない)

raceback (most recent call last):
  File "taple.py", line 2, in <module>
    items[0] = 20
TypeError: 'tuple' object does not support item assignment

list型からtuple型への双方変換

ex:list→tuple,tuple

# タプル
items_tuple = (50,"apple",32.5)
items_list  = [50,80,450]

print(list(items_tuple)) # list(((50,"apple",32.5))
print(tuple(items_list))# tuple([50,80,450])

result

[50, 'apple', 32.5] # list型
(50, 80, 450) #tuple型

スライス

ex:listとtupleのスライス例

scores_lists= [40,50,60,70,100]
scores_tuples = (40,50,60,70,100)

print("要素番号と中身")

for i,scores_list in enumerate(scores_lists):
        print("{0}:{1}".format(i,scores_list))

print("要素数の始点,終点指定 [1:4]")
print("リスト{0}".format(scores_lists[1:4]))
print("タプル{0}".format(scores_tuples[1:4]))


print("終点のみ指定 [:2]")
print(scores_lists[:2])

print("始点のみ指定 [3:]")
print(scores_lists[3:])

print("末尾から要素数から-3まで  [-3:]")
print(scores_lists[-3:])

# 文字列でも使える。

s = "Hello"
print(s[1:4]) #ello

result

要素番号と中身
0:40
1:50
2:60
3:70
4:100
要素数の始点,終点指定 [1:4]
リスト[50, 60, 70]
タプル(50, 60, 70)
終点のみ指定 [:2]
[40, 50]
始点のみ指定 [3:]
[70, 100]
末尾から要素数から-3まで  [-3:]
[60, 70, 100]
ell

集合型(set)

  • 集合型は順序なし、なおかつ重複を許さないデータ型
  • { }:中に値をいれていけば、その時点でsetになる。

ex:set,{ }の2つでの集合型の例

a = set([5,4,8,5]) #この形でも集合型になる。
a = {5,4,8,5,8}
print(a)

result

{8, 4, 5}

要素の確認,削除,追加

  • 確認:in
  • 削除:remove
  • 追加:add

ex:要素の確認,削除,追加

a = set([5,4,8,5])
a = {5,4,8,5,8}  
print(a)


#要素の中に5があるか確認する。
print(5 in a)

#値を追加する。
a.add(2) #位置はバラバラである
print(a)

#値を削除する。
a.remove(8)
print(a)

result

{8, 4, 5}
True
{8, 2, 4, 5} #2が追加されている。
{2, 4, 5} # 8がきえている。
3 #要素数

和集合,積集合,差集合

  • 和集合:( x | y)
  • 差集合:(x - y )
  • 積集合:(x & y)

ex:和集合,積集合,差集合

a1 = {1,3,5,8}
b1 = {3,5,4,9}


for i,a in enumerate(a1):
    print("a{0}:{1}".format(i,a))

for i,b in enumerate(b1):
    print("b{0}:{1}".format(i,b))


print("(|):和集合")
print(a1 | b1)
print("(&):積集合")
print(a1 & b1)
print("(-):差集合")
print(a1 - b1)

result

a0:8 a1:1 a2:3 a3:5
b0:9 b1:3 b2:4 b3:5
(|):和集合
{1, 3, 4, 5, 8, 9}
(&):積集合
{3, 5}
(-):差集合
{8, 1}

辞書型

  • ** 辞書型はキーと値でデータを管理していく型**
  • {key:value}の形でdect型になる。
  • keyで値を指定する。

ex1:dect型

# 辞書型 {"文字列":200,"文字列"}

sales = {"taguch":200,"fkoji":400}
print(sales["taguch"])

# 置き換え
sales["taguch"] = 400
print(sales["taguch"])

# 追加
sales["dotinstall"] = 400
print(sales)

#消去
del(sales["fkoji"])
print(sales)

result

200
400
{'taguch': 400, 'fkoji': 400, 'dotinstall': 400}
{'taguch': 400, 'dotinstall': 400}

items()でkeyとvalueを取得する。

ex2:dect型の値をitems()で取得する。

# 辞書型 {"文字列":200,"文字列"}
sales = {"taguch":200,"fkoji":400}
print(sales["taguch"])

# items()でkeyとitemを取得する。
for key,value in sales.items():
        print("{0}:{1}".format(key,value))

result

taguch:200
fkoji:400

イテレータ

[10,20,30,40,60]
このようなデータ構造の要素を簡単に返してくれるデータの集合をイテレータと呼ぼます。またイテレータは別の処理を挟んでもちゃんとどこまで要素を取得したかを覚えていてくれます。

  • 要素の値を順々に取得する。:next(it)

ex:イテレータの基本構文

score = [40,50,70,90] # list
# イテレータ化
it= iter(score)

print(next(it)) #40
print(next(it)) #50
print("Hello Iterator")
print(next(it))

result

40
50
Hello Iterator
70

for文とイテレータの関係

for文の内部構造もイテレータを使っている。

今まで見てきた次のような for 文ではこのように for score in scores: print(score) としてきましたが、実は for 文では、ここにくる変数にイテレータを期待していて、ここにリストを書くと自動的にイテレータに変換してくれます。そして内部的に next() を呼ぶことで print(score) の処理を実現していることも知っておくといいでしょう。

ex:forとイテレータの関係

scores = [40,50,70,90] # list
# イテレータ
print("イテレータ文")
it= iter(scores)

print(next(it)) #40
print(next(it)) #50
print("Hello Iterator")
print(next(it))
print(next(it))

print("for文")
# forの内部でもイテレータを使っている

for score in scores:
        print(score)

result

イテレータ文
40
50
Hello Iterator
70
90
for文
40
50
70
90

ジェネレーター

イテレータを作る関数を ジェネレーターと呼びます。今回listでは扱えないような無限の要素を持つ、イテレータ(データ集合)をジェネレーターで作ってみる。

ex:ジェネレーター

def get_infinite(): #ジェネレーター(イテレータを作る関数)
    i = 0
    while True:
            yield i*2 #要素を順々に引っぱてくる。
            i += 1

g = get_infinite()

print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

result

0
2
4
6
8
10

従ってジェネレータでは、next() を呼ばれた時に初めて次の要素を探しにいく仕様になっているので、今回のように無限の要素を扱うことができるようになっていることも知っておく。

Map,Lambda

Map

mapとイテレータあるとめっちゃ便利だ!

  • map:イテレータの要素を加工する際に使う。
    • map(関数,イテレータ)
  • mapは返り値としてジェネレーターを返す。
  • またイテレータが期待されているところでは自動的にイテレータに変換してくれる。 従って、listtuple,set,dec型をそのまま引数に渡してもイテレータ型に変換してくれる。

ex:mapの使い方

#map

#4倍にする関数

def triple(n):
>---return n*4
>
#map(関数,イテレータ)を使う
#mapはジェネレーターを返すので、そのままprintできない。

#listで固める。
print(list(map(triple,[1,2,3])))

result

[4, 8, 12]

Lambda(無名関数)

sorted,map,filterと合わせて使うと便利.

  • lambda 引数:返り値で使う。

ex:lambda 要素を2倍にして返す。

#一般的なlambda

# 2倍にして返す
myfunc = lambda x:x*2

print(myfunc(2))
print(myfunc(4))

result

4
8

mapと合わせて使う。

map()は、リストやタプルの各要素に対して同じ処理を施して、同じ長さの要素にそのすべての結果を格納して返してくれる関数です。map(関数, リスト)という形で使います。

ex:map(list)とlamodaで要素を5倍にして返す

#lambda とmap(list)を組み合わせて要素を5倍にする。
li = [1,2,3,4]
#リスト型に変換する。
li2 = list(map(lambda n:n*5,li))
print(li)
print(li2)

result

[1, 2, 3, 4]
[5, 10, 15, 20]

これは1行で以下に様に表現できるる。
こっちの方が短くて綺麗だね。

print(list(map(lambda n:n*5,[1,2,3])))

これなら大量の要素(行列)を持つ画像にも効率よく値を書き換えれるので、確かにpythonは画像処理に強いという事がわかる。

filter

条件に合致したものを抽出してくれる関数です。

ex:偶数だけを抽出してリストに変換する。

#偶数だけ抽出する。

def is_even(n):
    return n % 2 == 0
print(list(filter(is_even,range(20))))

result

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

lambda と合わせて使う事ができる。

ex:lamdaとfilterを合わせて利用する。

print(list(filter(lambda n: n%2 == 0,range(20))))

内包表記

リストやジェネレータを生成したり加工する際に書くための記法です。

内包表記で0-9までのリストを作る。

ex:内包表記の基本例

print([i for i in range(10) ])

このコードの意味としては
range(10) で 0 から 9 のリストができるので、そのリストから 1 つずつ>要素を取り出して点前のi に入れて、それをそのまま i として取り出すという意味になる。

result

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range()とは

range() が返すオブジェクトは、いろいろな点でリストであるかのように振る舞いますが、本当はリストではありません。これは、イテレートした時に望んだ数列の連続した要素を返すオブジェクトです。しかし実際にリストを作るわけではないので、スペースの節約になります。このrange(0, 10)オブジェクトは **イテラブル (iterable) **と呼ばれます。これらは関数やコンストラクタのターゲットとして、あるだけの項目を逐次与えるのに適しています。 for 文がそのような イテレータ であることはすでに見てきました。関数 list() もまた一つの例です。 これはイテラブルからリストを生成します。

ex:range()

#0-10にrangeオブジェクトを生成する。
print(range(10))
# イテラブル(rangeオブジェクト)からリスト(list())を作成している。
print(list(range(10)))

result

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

※曖昧な予測
forの内部構造も結局の所イテレータを使っているのでこの様に要素を取り出しているので、内包表記のように記述する事が出来る。

map的な使い方

listの要素取り出して3倍にする。

ex:内包表記のmap()用途。

#内包表記
print([i*3 for i in range(10) ])

# #map
print(list(map(lambda n:n*3,range(10))))

result

[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

filter的な使い方。

listの要素取り出して3倍にした値から、偶数だけを取りだす。

ex:内包表記のfilter()用途。

# 内包表記
print([ i*3 for i in range(10) if i % 2 == 0])

# filter()で書く
list3 = list(map(lambda n:n*3,range(10)))
print(list(filter(lambda n: n%2 == 0, list3)))
)))

#こっちで見ると明らかに内包表記のほうが短くてわかりやすい。
#print(list(filter(lambda n: n%2 == 0, list(map(lambda n:n*3,range(10)))
)))

集合型

  • { }で囲む。

ex:集合型を扱う

print({i*3 for i in range(10) if i % 2 == 0  })

result

{0, 6, 12, 18, 24}

ジェネレーター方式

構文から勘違いしやすいですが、()で囲んでもタプル内包表記にならずにジェネレータ式になります。むしろタプル内包表記より使います。**リストと違ってメモリ中に全要素を格納しないで、次の要素を順番に生成します。**一旦 ジェネレータを生成する関数を作らないと行けないので面倒だ。

ex:ジェネレータ

# ジェネレーター ()
print(i*3 for i in range(10) if i % 2 == 0) #<generator object <genexpr> at 0x7f021d05ae60>

result

<generator object <genexpr> at 0x7f02612d9e60>  #内包標記でジェネレーターが生成された意

ジェネレーターとはイテレータの一種であり、1要素を取り出そうとする度に処理を行い、要素をジェネレートするタイプのもの。Pythonではyield文を使った実装を指すことが多いと思われる。

compre_gen = (i*3 for i in range(10) if i % 2 == 0)

for i in compre_gen:
 print(i)

result

0
6
12
18
24
433
523
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
433
523