Skip to content

Instantly share code, notes, and snippets.

@Rokt33r
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rokt33r/53ea35820d51840ee864 to your computer and use it in GitHub Desktop.
Save Rokt33r/53ea35820d51840ee864 to your computer and use it in GitHub Desktop.
Python 3rd week

Function(関数)

今回はFortranのSubroutineのような役割をするFunctionを使ってみよう。

書き方

関数もifwhileのようにインデントで関数の中なのか外なのかを判断する。

例は次のようになる。

def plusOne(x) :
	x = x + 1
	return x

print(plusOne(1))

plusOneは関数の名前であって、()は引数をどんな名前の変数でもらうのかを決める。 括弧内のxは中のLocal variable(地域変数)であって、そとに同じ名前の変数がある場合、独立的である。

>>> x = 1
>>> def plusOne(x) :
...     x = x + 1
...     return x
...
>>> print(plusOne(1))
2
>>> print(x)
1

見ているようにplusOne()の変数xの値が1増えても、関数の外で宣言されているxにはどんな影響も与えない。

引数と返し値は両方とも必修ではないので、引数を定義する()を空にして、returnは省略してもいい。

なら、外側に宣言された変数は因数として入れないといけない??

幸いにPythonはFortranのsubroutineのように一々定義する必要はない。

まず、Pythonが自動的に判断して、関数内で定義されなかった変数なら外から呼ぶようになっている。

>>> x = 1
>>> def plusOne() :
...     return x + 1
...
>>> plusOne()
2

見ているように関数の中ではxが宣言されていないので、Pythonは自動的に外側の変数を持ってきてくれる。

だが、ここでxの値を関数内で変更するようにしたらエラーが生じる。

>>> x = 1
>>> def plusOne() :
...     x = x + 1
...     return x
...
>>> plusOne()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in plusOne
UnboundLocalError: local variable 'x' referenced before assignment

これは、xが関数内で一回代入されたせいである。

つまり、Pythonは変数の定義と代入を分けて考えていないので、値を代入しようとしたことを関数内に新しい変数(地域変数)を定義したと判断する。
それで、地域変数xを入れる時、まだ値が決まっている自分自身に+1しようとするからエラーが生じるようになる。

この問題を押さえるため、Pythonはglobalというkeywordで外側の変数を呼ぶ方法を提供している。

使い方は次のようになる。

>>> x = 1
>>> def plusOne() :
...     global x
...     x = x + 1
...     return x
...
>>> plusOne()
2
>>> x
2

引数の初期値の宣言

引数に初期値を登録しておいて、引数を省略して関数を使う方法もある。

>>> def sayHello(name = "Guest") :
...     print("Hello, " + name)
...
>>> sayHello("Mr. Choi")
Hello, Mr. Choi
>>> sayHello()
Hello, Guest

Object Oriented Programming(Object指向プログラミング)

Object Oriented Programming(OOP)はプログラミングにおいての一つのパラダイムである。

既存のプログラムは順序通りに命令を行うだけであって、SubroutineやFunctionはただの命令の固まりに過ぎない。 ここで発生する問題は、Subroutineなどでコードをできる限り簡略化しようとしても、Projectが大きくなればなるほど維持管理が大変になる。

しかし、OOPはただのコードの固まりじゃなくて、プログラムの中に独立的なプログラム(Object)を作る感じになる。

つまり、Objectは一つのプログラムのように自分自身の変数と関数を持っていて、私たちが作るプログラムはそのObjectを呼んできて、内蔵されている変数や関数を呼ぶようになっている。

ここで、Objectに内蔵されている変数をMember Variable、関数をMethodと呼ぶ。 混用して書く場合が多いので、これらの言葉も知っておいた方がいい。

Class

プログラムの中でObjectを作って使おうとする時、そのObjectの機能について先に前述する必要がある。 簡単に言うと変数を宣言することとほぼ同じである。

ここで、その前述しておくものをClassと言う。

つまり、Classは鋳型であって、Objectはその鋳型(Class)で作った実際に機能をする製品である。

では、どう書けばいいのかを確認してみよう。

class Person :
    name = "Choi"
    def setName(self, name) :
        self.name = name
    def eat(self) :
        print(str(self.name) + "さんが飯を食べています。")

関数作るときと似ているようにclassというkeywordで作る。そして、PersonClassの名前である。

慣例的にClassと変数を区別するため、Class名の一番最初の文字は大文字にする。 他の言語にも同じ慣例があるので、必ず守った方がいい。

ObjectのMember VariableMethodは普通に変数と関数を宣言する方法と同じである。

では、今から実際にObjectを活用してみよう。

Instance

では、先作っておいたClassでObjectを使ってみよう。

class Person :
    name = "Choi"
    def setName(self, name) :
        self.name = name
    def eat(self) :
        print(str(self.name) + "さんが飯を食べています。")

p1 = Person()
p2 = Person()

p2.setName('Watanabe')

print("p1の名前は" + str(p1.name) + "です。")
p1.eat()
print("p2の名前は" + str(p2.name) + "です。")
p2.eat()

まず、Objectの生成は関数のようにPerson()で行う。 この時、生成されるObjectのことをInsatance(インスタンス)といって、 このInstanceが代入されている変数p1p2のことをInstance Variableと呼ぶ。

そして、今作ったObjectMember VariableMethodp1.namep1.eat()のように使えばいい。

ここで注目するべきであるのはp1p2は独立的であって、二つは違う名前を持つことだ。

もちろん、同じクラスで作ったので、形だけを考えたら同じである。

では、Objectはいつ使えばいいのか

たぶん、まだObjectをどんな形で使えばいいのかは分かりにくいと思う。 正直に言って先の例題ぐらいなら、classを使わなくても十分簡単にできる。

結局、OOPで大事な問題はどういう機能をObjectとして作ればいいのかである。 これはプログラムの企画ができていないと、決められない。

なので、次は実際にObject Oriented Programmingで設計をしてみる。

OOPを用いたVector演算

本格的にOOPの概念を用いてプログラムを作ってみよう。

最終的には軌道力学の課題の解決までやってみる

Vector

Vectorは方向(Direction)と大きさ(Magnitude)で定義できる。

それで、3次元のVectorを作るためには4つの情報(Euler角3つと大きさ一つ)がひつようである。

だが、もっと分かりやすくVectorが定義できるように、Vectorの出発点と到着点をもらってVectorを宣言するようにしよう。

class Vector :
	def __init__(self, x2, y2, z2, x1 = 0, y1 = 0, z1 = 0) :
		self.x2 = x2
		self.y2 = y2
		self.z2 = z2
		self.x1 = x1
		self.y1 = y1
		self.z1 = z1

VectorというClassを作って、__init__という関数を定義した。

まだ、説明をしていないけど、__init__は全てのObjectが持っているMethodであって、Objectが生成されるときに呼ばれている関数である。 その上にこの関数は引数をもらっているので、Vector()でObjectを生成するときにx2,y2,z2は必ず必要とする。

x1, y1, z1は初期値が与えられているので、引数を入れなくてもいい。

なので、次のようにObjectを生成する。

class Vector :
	def __init__(self, x2, y2, z2, x1 = 0, y1 = 0, z1 = 0) :
		self.x2 = x2
		self.y2 = y2
		self.z2 = z2
		self.x1 = x1
		self.y1 = y1
		self.z1 = z1

v1 = Vector(30, 20, 10)
v2 = Vector(10, 30, 25, 0, 20, 15)

では、本格的にVector演算でひつようである機能を一つずつ作ってみる。

絶対値

Vectorの大きさ(絶対値)を求める機能を作る。

class Vector :
    def __init__(self, x2, y2, z2, x1 = 0, y1 = 0, z1 = 0) :
        self.x2 = x2
        self.y2 = y2
        self.z2 = z2
        self.x1 = x1
        self.y1 = y1
        self.z1 = z1
    def abs(self) :
        dx = self.x2-self.x1
        dy = self.y2-self.y1
        dz = self.z2-self.z1
        return (dx ** 2 + dy ** 2 + dz ** 2) ** 0.5

v1 = Vector(30, 20, 10)
v2 = Vector(10, 30, 25, 0, 20, 15)

print("v1の絶対値は " + str(v1.abs()))
print("v2の絶対値は " + str(v2.abs()))

Operator Override

Vectorを扱う時、Vectorお互いの足し算や減り算をする場合がある。

class Vector :
	def __init__(self, x2, y2, z2, x1 = 0, y1 = 0, z1 = 0) :
		self.x2 = x2
		self.y2 = y2
		self.z2 = z2
		self.x1 = x1
		self.y1 = y1
		self.z1 = z1
	def abs(self) :
		dx = self.x2-self.x1
		dy = self.y2-self.y1
		dz = self.z2-self.z1
		return (dx ** 2 + dy ** 2 + dz ** 2) ** 0.5

	def sum(self, other) :
		return Vector(self.x2+other.x2, self.y2+other.y2, self.x1+other.x1, self.y1+other.y1)

v1 = Vector(30, 20, 10)
v2 = Vector(10, 30, 25, 0, 20, 15)

vSum = v1.sum(v2)

これも悪くはないが、Pythonではもっと格好いいやり方がある。

それはOperator Overrideということで、 Overrideの意味は優先する踏みつぶすと言う意味で、 既存の関数を再定義することであって、Operator OverrideOperator(演算子)を上書きすることである。

	def __add__(self, other) :
		return Vector(self.x2+other.x2, self.y2+other.y2, self.x1+other.x1, self.y1+other.y1)

それで、こんな書き方ができる。

vSum = v1 + v2

OverrideせずにObjectを+を使う場合、Objectの+で何をするのかがまだ定義されていないのでErrorが起きる。

課題

Vectorを完成させよう!

  1. Vectorの減り算-、外積**、内積*の関数を完成させる。

ex : def __sub__(self, other) / def __pow__(self, other) / def __mul__(self, other)

  1. VectorのX, Y, Z軸に基づいた回転関数を作る。

ex : def rotateX(self, phi)

  1. 2.で作ったX, Y, Z軸に基づいて回転する関数を使って、Euler回転を全部具現する。

ex : def rotateXYX(self, phi, theta, psi) ... 全部12個

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment