Python/クラス
Pythonのクラスについて学ぶことで、自分自身のデータ型を定義して、その型に基づいて作成されたオブジェクトにアクセスする方法を学ぶことができます。 このチュートリアルでは、Pythonでクラスを定義する方法、クラスオブジェクトとインスタンスオブジェクトの違い、クラス変数とインスタンス変数、メソッド、継承、プライベート変数とメソッド、プロパティ、抽象基底クラスなどのトピックについて説明します。
クラスの概要
[編集]Pythonのクラスは、オブジェクト指向プログラミングにおける基本的な概念の一つで、データと関数をまとめて扱うことができます。
クラスは、プログラム内でオブジェクトを作成するための設計図のようなものです。クラスには、そのオブジェクトが持つ属性(データ)や振る舞い(メソッド)が定義されています。クラスを定義することで、同じような性質を持ったオブジェクトを簡単に作成することができます。
クラスの中で定義されたデータは、クラス変数とインスタンス変数の2種類があります。クラス変数は、そのクラスが持つデータであり、全てのインスタンスで共有されます。インスタンス変数は、オブジェクトごとに異なる値を持つデータであり、各インスタンスごとに独立しています。
メソッドは、オブジェクトの振る舞いを定義するための関数です。クラスに定義されたメソッドは、インスタンスを通じて呼び出すことができます。
クラスは、継承を使って他のクラスを拡張することができます。継承することで、既存のクラスの機能を再利用し、新たな機能を追加することができます。
また、Pythonにはプライベート変数やプロパティ、抽象基底クラスなど、クラスをより強力にするための機能があります。これらの機能を使うことで、より柔軟で安全なコードを書くことができます。
クラスの定義方法
[編集]Pythonでは class
キーワードを使用してクラスを定義します。基本的な構文は以下の通りです。
class ClassName: # クラスの本体
クラス名は、PascalCase で書かれた単語である必要があります。クラスの本体には、変数や関数を定義することができます。
クラスを定義する
[編集]以下の例では、Person
というクラスを定義しています。このクラスには、名前と年齢のインスタンス変数、およびそれらを設定するための __init__
メソッドが含まれています。
class Person: def __init__(self, name, age): self.name = name self.age = age
このクラスを使うと、以下のようにして Person
のインスタンスを作成することができます。
person1 = Person("Alice", 25) person2 = Person("Bob", 30)
クラスオブジェクトとインスタンスオブジェクト
[編集]クラス定義によって作成されたオブジェクトには、2つの種類があります。1つはクラスオブジェクトであり、もう1つはインスタンスオブジェクトです。
クラスオブジェクト
[編集]クラスオブジェクトは、クラス定義に基づいて作成され、クラス変数にアクセスするために使用されます。
class MyClass: class_variable = 0 print(MyClass.class_variable)
この場合は、MyClass
がクラスオブジェクトです。
インスタンスオブジェクト
[編集]インスタンスオブジェクトは、クラスから作成された各オブジェクトのことを指します。それぞれのインスタンスは、独自の状態を保持できます。
class MyClass: def __init__(self): self.instance_variable = 0 my_object1 = MyClass() my_object2 = MyClass() print(my_object1.instance_variable) print(my_object2.instance_variable)
この場合は、my_object1とmy_object2 がインスタンスオブジェクトです。
- 曖昧さのない場合は、クラスオブジェクトをクラス、インスタンスオブジェクトをインスタンスと呼びます。
クラス変数とインスタンス変数
[編集]クラス変数はクラス内で定義され、すべてのインスタンスで共有される変数です。インスタンス変数は、各インスタンスごとに異なる値を持つ変数です。
クラス変数とインスタンス変数の定義
[編集]以下は、クラス変数とインスタンス変数を定義する例です。
class MyClass: class_variable = 0 # クラス変数 def __init__(self, instance_variable): self.instance_variable = instance_variable # インスタンス変数
上記の例では、class_variable
はクラス変数、instance_variable
はインスタンス変数です。class_variable
はクラス内で定義され、インスタンス作成前に定義されます。instance_variable
は、__init__
メソッド内で初期化されるため、インスタンスが作成されるたびに異なる値が割り当てられます。
クラス変数とインスタンス変数のアクセス方法
[編集]以下は、クラス変数とインスタンス変数をアクセスする例です。
class MyClass: class_variable = 0 # クラス変数 def __init__(self, instance_variable): self.instance_variable = instance_variable # インスタンス変数 my_instance = MyClass(1) print(my_instance.class_variable) # クラス変数のアクセス方法 print(my_instance.instance_variable) # インスタンス変数のアクセス方法 MyClass.class_variable = 2 # クラス変数の変更 my_other_instance = MyClass(3) print(my_other_instance.class_variable) # クラス変数の変更後のアクセス方法
上記の例では、my_instance
はMyClass
のインスタンスであり、class_variable
とinstance_variable
にアクセスしています。MyClass.class_variable
を変更すると、MyClass
のすべてのインスタンスが新しい値を持つようになります。
メソッド
[編集]Pythonにおけるメソッドとは、オブジェクトが持つ関数のことです。メソッドは、クラス内に定義された関数であり、オブジェクトに対して呼び出されることが前提となっています。
メソッドは、インスタンスメソッド、クラスメソッド、スタティックメソッド、特殊メソッドなど、種類によって様々な特徴を持っています。
インスタンスメソッドは、そのオブジェクトに対して呼び出され、クラスメソッドは、そのクラスに対して呼び出されます。
スタティックメソッドは、オブジェクトやクラスに関係なく、独立して呼び出されます。
特殊メソッドは、Pythonが提供する特別な機能を持つメソッドであり、例えば、__init__
や__str__
などがあります。
インスタンスメソッド
[編集]インスタンスメソッドは、クラスのインスタンスによって呼び出されます。第1引数は必ず self
で、それを使ってインスタンスの属性にアクセスできます。
class MyClass: def instance_method(self, arg1, arg2): self.arg1 = arg1 self.arg2 = arg2 print(f"Called instance_method with {self.arg1} and {self.arg2}") obj = MyClass() obj.instance_method("hello", "world") # "Called instance_method with hello and world"
このコードは、インスタンスメソッドの例です。 instance_method
は、self
を最初の引数として受け取り、その引数はメソッドが呼び出されたインスタンス自体を指します。このインスタンスを介して、メソッドはオブジェクトの状態を変更することができます。引数arg1
とarg2
は、メソッドに渡され、メソッドの処理に使用されます。
上記のコードは、MyClassのインスタンスobj
を作成し、instance_method
を呼び出しています。 instance_method
は、 obj
がインスタンスであるため、self
として自分自身を参照し、 "Called instance_method with hello and world"という文字列を出力します。
- 単にメソッドと言った場合、インスタンスメソッドを示すことが多いですが、文脈に注意しましょう。
クラスメソッド
[編集]クラスメソッドは、クラス自体によって呼び出されます。第1引数は必ず cls
で、それを使ってクラスの属性にアクセスできます。
class MyClass: class_var = "class variable" @classmethod def class_method(cls, arg): cls.arg = arg print(f"Called class_method with {cls.arg} and {cls.class_var}") MyClass.class_method("hello") # "Called class_method with hello and class variable"
上記のコードは、MyClass
というクラスを定義し、その中に class_var
というクラス変数を定義し、class_method
というクラスメソッドを定義しています。
class_method
は、@classmethod
デコレータで修飾されており、第一引数が cls
というクラスオブジェクトであることが示されています。クラスメソッドは、クラス自身を第一引数として受け取るため、クラス変数にアクセスしたい場合は、cls.class_var
のようにしてアクセスすることができます。
このクラスメソッドは、arg
という引数を受け取り、cls.arg
にその値を代入し、cls.arg
と cls.class_var
を用いてメッセージを出力するという動作をします。
最後の行では、class_method
をクラス名で呼び出しています。class_method
がクラスメソッドであるため、第一引数にはクラスオブジェクト MyClass
が自動的に渡されます。
スタティックメソッド
[編集]スタティックメソッドは、クラス自体やインスタンスから呼び出すことができます。スタティックメソッドは self
や cls
が必要ないため、第1引数を定義しません。
class MyClass: @staticmethod def static_method(arg): print(f"Called static_method with {arg}") MyClass.static_method("hello") # "Called static_method with hello"
この例では、@staticmethod
デコレータが使われています。このデコレータを使うことで、メソッドがスタティックメソッドであることを明示的に示すことができます。
スタティックメソッドはクラスに属していますが、インスタンスには属していないため、引数に self
や cls
を必要としません。そのため、スタティックメソッドは通常、インスタンス変数を使用する必要がない場合に使用されます。
上記の例では、@staticmethod
を使って static_method
メソッドを定義しています。このメソッドは arg
という引数を受け取り、"Called static_method with {arg}"
というメッセージを出力します。
最後の行では、MyClass.static_method("hello")
というコードを実行することで、static_method
メソッドを呼び出しています。この結果、"Called static_method with hello"
というメッセージが出力されます。
特殊メソッド
[編集]特殊メソッドは、Pythonによって予約されたメソッドで、オブジェクトの様々な振る舞いを定義することができます。特殊メソッドは、名前が __
で始まり、終わります。
例えば、__init__()
は、オブジェクトが作成されるときに自動的に呼び出されるメソッドで、インスタンス変数の初期化などの処理を行います。
class MyClass: def __init__(self, arg1, arg2): self.arg1 = arg1 self.arg2 = arg2 print(f"Called __init__ with {self.arg1} and {self.arg2}") obj = MyClass("hello", "world") # "Called __init__ with hello and world"
このコードは、MyClassという名前のクラスを定義し、__init__という特殊メソッドを使ってインスタンスを初期化しています。 __init__メソッドは、クラスがインスタンス化される際に自動的に呼び出されます。このメソッドは、インスタンスの属性を初期化するのに使用されます。 上記の例では、MyClassのインスタンスを作成し、"hello"という値をarg1に、"world"という値をarg2に割り当て、__init__メソッドが呼び出されたことを示す出力が表示されます。
例えば、__add__
メソッドを定義すると、+
演算子をオーバーロードして、クラスのインスタンス同士を加算できるようになります。
class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __str__(self): return f"Point({self.x}, {self.y})" # 使用例 p1 = Point(1, 2) p2 = Point(3, 4) result = p1 + p2 print(result) # Point(4, 6)
上記の例では、Point
クラスに__add__
メソッドを定義して、2つのPoint
インスタンスを加算できるようにしています。__str__
メソッドはオブジェクトを文字列に変換する際に呼ばれる特殊メソッドであり、ここではprint
関数を使ってPoint
オブジェクトを出力する際に使用されています。
他にも、__sub__
(減算)、__mul__
(乗算)、__eq__
(等価)、__lt__
(小なり)など、さまざまな特殊メソッドがあります。これらを使うことで、クラスのインスタンスが自然な方法で演算子を扱えるようにすることができます。
は代表的な特殊メソッド メソッド名 説明 __init__(self[, ...])
インスタンスが作成されるときに呼び出される。初期化のためのメソッドで、必須の引数は self
以外にある。__str__(self)
str()
関数で呼び出される。オブジェクトを表す文字列を返す。__repr__(self)
repr()
関数で呼び出される。オブジェクトを表す公式的な文字列を返す。__len__(self)
len()
関数で呼び出される。オブジェクトの長さを返す。__getitem__(self, key)
インデックスを使用して要素を取得するために []
演算子で呼び出される。__setitem__(self, key, value)
インデックスを使用して要素を設定するために []
演算子で呼び出される。__delitem__(self, key)
インデックスを使用して要素を削除するために []
演算子で呼び出される。__contains__(self, item)
in
演算子で呼び出される。オブジェクトが指定された要素を含む場合にTrue
を返す。__call__(self[, args...])
オブジェクトが関数として呼び出されたときに呼び出される。
for
文を適用するには、クラスに __iter__()
と __next__()
メソッドを実装する必要があります。これらのメソッドを実装することで、クラスのインスタンスをイテレータとして扱うことができます。
__iter__()
メソッドは、イテレータ自身を返す必要があります。通常は、クラスのインスタンス自身を返します。__next__()
メソッドは、次の要素を返します。もう要素がない場合は、StopIteration を発生させます。
以下は、クラスのインスタンスに for
文を適用する例です。
class MyIterator: def __init__(self, items): self.items = items self.current = 0 def __iter__(self): return self def __next__(self): if self.current < len(self.items): item = self.items[self.current] self.current += 1 return item else: raise StopIteration my_iter = MyIterator([2, 3, 5]) for item in my_iter: print(item) # 2 # 3 # 5
上記の例では、MyIterator
というクラスを定義し、__iter__()
と __next__()
メソッドを実装しています。
MyIterator
クラスのインスタンスを for
文でループさせることができます。継承
[編集]継承とは、既存のクラスを基に新しいクラスを作り出すことで、既存のクラスの機能を引き継ぎながら、新たな機能を追加することができます。
スーパークラスの定義
[編集]スーパークラスは、継承元のクラスのことを指します。スーパークラスの定義は、通常のクラス定義と同じように行います。
以下の例では、Person
というクラスをスーパークラスとして定義しています。
class Person: def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print(f"My name is {self.name} and I am {self.age} years old.")
このスーパークラス Person
は、name
と age
の属性を持ち、say_hello()
メソッドを定義しています。
サブクラスの定義
[編集]サブクラスは、スーパークラスを継承して新たなクラスを作り出すことができます。サブクラスは、新たに追加する属性やメソッドを定義することができます。
以下の例では、Student
というクラスを、スーパークラスである Person
を継承して定義しています。
class Student(Person): def __init__(self, name, age, grade): super().__init__(name, age) self.grade = grade def say_hello(self): print(f"My name is {self.name}, I am {self.age} years old and my grade is {self.grade}.")
このサブクラス Student
は、Person
クラスを継承して、grade
の属性を追加し、say_hello()
メソッドをオーバーライドしています。
オーバーライド
[編集]サブクラスでスーパークラスのメソッドを再定義することをオーバーライドと呼びます。サブクラスで同名のメソッドを定義することで、スーパークラスのメソッドを上書きすることができます。
上記の例では、Student
クラスで say_hello()
メソッドを再定義し、出力内容を変更しています。
super() 関数
[編集]サブクラスでスーパークラスのメソッドを呼び出すには、super() 関数を使用します。super() 関数を呼び出すことで、スーパークラスのメソッドを呼び出すことができます。
上記の例では、Student クラスの __init__() メソッドで、super() 関数を使用して、スーパークラスの __init__() メソッドを呼び出しています。 これにより、Person クラスで定義した name と age の属性を、Student クラスでも使用することができます。
多重継承
[編集]Python では、複数のクラスを同時に継承することができます。これを多重継承と呼びます。多重継承では、カンマで区切って複数のスーパークラスを指定します。 以下の例では、Person クラスというスーパークラスを継承し、さらに、Swimmer というクラスも同時に継承しています。
class Swimmer: def swim(self): print("I'm swimming!") class SwimmingStudent(Person, Swimmer): def __init__(self, name, age, grade): super().__init__(name, age) self.grade = grade def say_hello(self): print(f"My name is {self.name}, I am {self.age} years old and my grade is {self.grade}.") def swim(self): print("I'm swimming like a pro!") SwimmingStudent("Alice", 10, 5).swim() # => I'm swimming like a pro!
上記の例では、Swimmer クラスを定義して、swim() メソッドを持たせています。 そして、SwimmingStudent クラスで Person クラスと Swimmer クラスの両方を継承しています。 さらに、SwimmingStudent クラスで swim() メソッドをオーバーライドして、Swimmer クラスで定義した swim() メソッドと異なる動作をするようにしています。 最後に、SwimmingStudent クラスのインスタンスを作成して、swim() メソッドを呼び出した結果、Swimmer クラスで定義した swim() メソッドではなく、SwimmingStudent クラスでオーバーライドした swim() メソッドが呼び出されることが確認できます。
collections.abc
モジュールIterable
: イテレーション可能なオブジェクトを定義する抽象基底クラスContainer
: 要素の有無を調べることができるオブジェクトを定義する抽象基底クラスSized
: 要素の数を返すlen()
関数を実装することができるオブジェクトを定義する抽象基底クラスCallable
: 呼び出し可能オブジェクトを定義する抽象基底クラスHashable
: ハッシュ可能なオブジェクトを定義する抽象基底クラスMapping
: キーと値の対応を表す辞書型オブジェクトを定義する抽象基底クラスMutableMapping
: キーと値の対応を表す辞書型オブジェクトを変更することができる抽象基底クラスSequence
: インデックスを用いて要素にアクセスできるオブジェクトを定義する抽象基底クラスMutableSequence
: インデックスを用いて要素にアクセスし、変更することができるオブジェクトを定義する抽象基底クラス
enum
モジュールEnum
: 列挙型オブジェクトを定義する基底クラス
abc
モジュールABC
: 抽象基底クラスを定義する基底クラスabstractmethod
: 抽象メソッドを定義するためのデコレータ
typing
モジュールType
: クラスオブジェクトを表す型を定義するクラスTypeVar
: 型変数を定義するクラスGeneric
: ジェネリッククラスを定義する基底クラスProtocol
: プロトコルを定義する基底クラス
プライベート変数とメソッド
[編集]プライベート変数やメソッドとは、クラスの外から直接アクセスできないようにするために用意されたものです。Pythonでは、アンダースコア(_)で始まる変数名やメソッド名を定義することで、プライベート変数やメソッドを作成することができます。
プライベート変数とメソッドの定義方法
[編集]プライベート変数を定義する場合、変数名の先頭にアンダースコアを付けます。以下の例では、Person クラスにプライベート変数 _password を定義しています。
class Person: def __init__(self, name, age, password): self.name = name self.age = age self._password = password def say_hello(self): print(f"My name is {self.name} and I am {self.age} years old.") def _show_password(self): print(f"My password is {self._password}.")
同様に、プライベートメソッドを定義する場合も、メソッド名の先頭にアンダースコアを付けます。上記の例では、Person クラスにプライベートメソッド _show_password() を定義しています。
プライベート変数とメソッドのアクセス方法
[編集]プライベート変数やメソッドは、クラスの外から直接アクセスすることができません。しかし、アクセスする方法が用意されています。
プライベート変数にアクセスする場合、変数名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベート変数 _password にアクセスしています。
p = Person("Alice", 25, "password123") print(p._password) # "password123" を出力
ただし、この方法は推奨されていません。Pythonでは、アンダースコアで始まる変数やメソッドは、外部から直接アクセスしないことが慣例となっています。プライベート変数やメソッドにアクセスする場合は、公開されているインターフェースを通じて行うようにしましょう。
プライベートメソッドにアクセスする場合、同様にメソッド名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベートメソッートメソッド _show_password() にアクセスしています。
p = Person("Alice", 25, "password123") p._show_password() # "My password is password123." を出力
同様に、クラス内で定義された公開メソッドを通じて、プライベート変数やメソッドにアクセスすることもできます。
以下の例では、Person クラスに公開メソッド get_password() を定義し、それを通じてプライベート変数 _password にアクセスしています。
class Person: def __init__(self, name, age, password): self.name = name self.age = age self._password = password def say_hello(self): print(f"My name is {self.name} and I am {self.age} years old.") def _show_password(self): print(f"My password is {self._password}.") def get_password(self): return self._password p = Person("Alice", 25, "password123") print(p.get_password()) # "password123" を出力
このように、Pythonでは、プライベート変数やメソッドを定義することで、クラスの外からの直接アクセスを制限することができます。 ただし、アクセスするための手段は用意されているため、必要な場合には適切に利用するようにしましょう。
プロパティ
[編集]プロパティとは、クラスの外からもアクセスできるようにしたい変数を指します。 しかし、変数に直接アクセスすると不適切な値が設定される可能性があるため、アクセス時に特定の処理を実行する必要があります。 このような場合に、プロパティを使います。
プロパティの定義方法
[編集]Pythonでは、プロパティを定義するには property
ビルトイン関数を使用します。プロパティを定義するには、以下のような方法があります。
getter関数のみを定義する場合
[編集]getter関数のみを定義する場合、以下のように @property
デコレータを使用して、getter関数にアクセスすることができます。
class Person: def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age
このように定義することで、インスタンスから以下のようにして name
や age
にアクセスすることができます。
person = Person("Alice", 25) print(person.name) # "Alice" を出力 print(person.age) # 25 を出力
getter関数とsetter関数の両方を定義する場合
[編集]getter関数とsetter関数の両方を定義する場合、以下のように @property
デコレータと @<property名>.setter
デコレータを使用して、getter関数とsetter関数にアクセスすることができます。
class Person: def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @name.setter def name(self, value): self._name = value @property def age(self): return self._age @age.setter def age(self, value): self._age = value
このように定義することで、インスタンスから以下のようにして name
や age
にアクセスし、変更することができます。
person = Person("Alice", 25) print(person.name) # "Alice" を出力 print(person.age) # 25 を出力 person.name = "Bob" person.age = 30 print(person.name) # "Bob" を出力 print(person.age) # 30 を出力
プロパティのアクセス方法
[編集]プロパティにアクセスする場合、通常のインスタンス変数と同様に、以下のようにしてアクセスします。
person = Person("Alice", 25) print(person.name) # "Alice" を出力 print(person.age) # 25 を出力
また、setter関数を定義している場合、以下のようにしてプロパティの値を変更することができます。
person.name = "Bob" person.age = 30 print(person.name) # "Bob" を出力 print(person.age) # 30 を出力
プロパティを使用することで、クラスの外部からもインスタンス変数にアクセスできるようになり、getter関数やsetter関数を使用することで、変数の値に対して特定の処理を行うことができます。 これにより、クラスのカプセル化が実現され、安全で信頼性の高いコードを作成することができます。
__getattr__ と __setattr__
[編集]__getattr__
と __setattr__
は Python の特殊メソッドで、オブジェクトの属性に対するアクセスをカスタマイズすることができます。
__getattr__
メソッドは、インスタンスの属性が未定義の場合に呼び出されます。通常の属性アクセスが失敗した場合に呼び出され、属性名を引数に取り、属性の値を返すように実装することができます。このメソッドを使用することで、動的な属性アクセスをサポートすることができます。
例えば、以下のようなクラス DynamicObject
を考えます。
class DynamicObject: def __getattr__(self, name): return f"{name} is not defined."
このクラスは、未定義の属性にアクセスした場合に、属性名と "is not defined." の文字列を連結したものを返します。
obj = DynamicObject() print(obj.foo) # 出力: foo is not defined.
一方、__setattr__
メソッドは、属性に値を代入する際に呼び出されます。通常の属性代入が行われた後に、属性名と代入された値を引数に取り、任意の処理を実行することができます。このメソッドを使用することで、属性代入時のチェックや変換処理を実装することができます。
例えば、以下のようなクラス PositiveNumber
を考えます。
class PositiveNumber: def __init__(self, value): self.value = value def __setattr__(self, name, value): if value < 0: raise ValueError("Value must be positive.") super().__setattr__(name, value)
このクラスは、属性に代入される値が負数である場合に、 ValueError
を発生させます。
n = PositiveNumber(1) n.value = 2 print(n.value) # 出力: 2 n.value = -1 # ValueError: Value must be positive.
- 注意点
__getattr__
メソッドや__setattr__
メソッドは、インスタンスの属性アクセスや属性代入時にのみ呼び出されます。- クラス自体にアクセスする場合には、
__getattr__
メソッドや__setattr__
メソッドは呼び出されません。 - 属性が存在する場合は
__getattr__
メソッドは呼び出されず、通常の属性アクセスが行われます。
クラス変数とインスタンス変数のプライベート化
[編集]Pythonでは、クラス変数とインスタンス変数をプライベート化することができます。プライベート変数は、クラスの外から直接アクセスすることができなくなり、情報の隠蔽や保護に役立ちます。
クラス変数とインスタンス変数のプライベート化
[編集]クラス変数とインスタンス変数をプライベート化するには、変数名の前にアンダースコア2つ(__
)をつけます。例えば、以下のように定義します。
class MyClass: __private_class_var = 10 # クラス変数のプライベート化 def __init__(self): self.__private_instance_var = 20 # インスタンス変数のプライベート化
これにより、MyClass
の外からは __private_class_var
や __private_instance_var
に直接アクセスできなくなります。ただし、Pythonでは名前修飾という仕組みがあり、アンダースコア2つを付けることで、クラス外からアクセスできなくするだけで、実際にはアクセス可能な変数として存在します。
プライベート変数のアクセス方法
[編集]プライベート変数にアクセスするためには、アンダースコア1つ(_
)を変数名の前に付けることでアクセスできます。例えば、以下のようにします。
class MyClass: __private_class_var = 10 # クラス変数のプライベート化 def __init__(self): self.__private_instance_var = 20 # インスタンス変数のプライベート化 def get_private_class_var(self): return MyClass.__private_class_var # アクセス方法 def get_private_instance_var(self): return self.__private_instance_var # アクセス方法
上記の例では、get_private_class_var()
メソッドと get_private_instance_var()
メソッドを定義し、それぞれでプライベート変数にアクセスする方法を示しています。
my_class = MyClass() print(my_class.get_private_class_var()) # 10 を出力 print(my_class.get_private_instance_var()) # 20 を出力
プライベート変数はクラスの外からアクセスできないようになっていますが、名前修飾を使用することで、直接アクセスすることができます。 ただし、名前修飾を使うことでアクセスできるようになっているため、注意が必要です。 プライベート変数は、クラス内部でしか使用しない変数であることを明確にし、情報を保護するために使用することが望ましいです。
抽象基底クラス
[編集]抽象基底クラスは、インスタンス化できない抽象的なクラスで、共通のインターフェースを定義することができます。
具体的な実装は、抽象基底クラスを継承したサブクラスで行います。
Pythonでは、抽象基底クラスを作成するために abc
モジュールを使用します。
抽象基底クラスの定義方法
[編集]抽象基底クラスを定義するには、abc.ABC
クラスを継承する必要があります。また、抽象メソッドを定義するには @abstractmethod
デコレータを使用します。
以下は、抽象基底クラスの定義例です。
import abc class MyABC(abc.ABC): @abc.abstractmethod def do_something(self): pass
上記の例では、MyABC
という抽象基底クラスを定義しています。このクラスには、do_something
という抽象メソッドが定義されています。
抽象基底クラスを継承したクラスの定義方法
[編集]抽象基底クラスを継承するサブクラスを定義する場合、@abstractmethod
で定義されたメソッドを実装する必要があります。また、抽象基底クラスを継承することで、共通のインターフェースを持つことができます。
以下は、抽象基底クラスを継承したクラスの定義例です。
class MyClass(MyABC): def do_something(self): print("MyClassの処理を実行しました")
上記の例では、MyClass
というクラスを定義し、MyABC
を継承しています。MyABC
に定義された do_something
メソッドを実装し、処理を行っています。
以上が、Pythonでの抽象基底クラスの定義方法、抽象基底クラスを継承したクラスの定義方法です。 抽象基底クラスを使用することで、共通のインターフェースを持つクラスを実装し、コードの再利用性を高めることができます。
例えば、以下のようにクラス定義時に属性に対して型アノテーションを指定することができます。
class MyClass: def __init__(self, value: int) -> None: self.value = value def add_value(self, x: int) -> int: return self.value + x
この例では、__init__
メソッドの引数value
と、add_value
メソッドの引数x
、そしてadd_value
メソッドの戻り値に対して、型アノテーションが指定されています。value
属性は整数型を持ち、add_value
メソッドは整数型の引数を受け取り、整数型の戻り値を返すことを表しています。
また、クラス全体に対して型アノテーションを指定することもできます。例えば、以下のようにクラス定義の先頭で型アノテーションを指定することができます。
class MyClass: value: int def __init__(self, value: int) -> None: self.value = value def add_value(self, x: int) -> int: return self.value + x
この例では、クラス定義の先頭でvalue
属性に対して整数型を指定しています。このように、クラス定義の先頭で型アノテーションを指定することで、クラス全体に対して型を指定することができます。
Ruby からの移植
[編集]Ruby#ユーザー定義クラスをPython3に移植しました。
- Ruby からの移植
import math class GeoCoord(object): def __init__(self, longitude, latitude): self.longitude, self.latitude = longitude, latitude def __str__(self): ew, ns = "東経", "北緯" long, lat = self.longitude, self.latitude if long < 0.0: ew = "西経" long = -long if lat < 0.0: ns = "南緯" lat = -lat return f"({ew}: {long}, {ns}: {lat})" def distance(self, other): i = math.pi / 180 r = 6371.008 return ( math.acos( math.sin(self.latitude * i) * math.sin(other.latitude * i) + math.cos(self.latitude * i) * math.cos(other.latitude * i) * math.cos(self.longitude * i - other.longitude * i) ) * r ) Sites = { "東京駅": [139.7673068, 35.6809591], "シドニー・オペラハウス": [151.215278, -33.856778], "グリニッジ天文台": [-0.0014, 51.4778], } for name in Sites: Sites[name] = GeoCoord(*Sites[name]) for name in Sites: print(f"{name}: {Sites[name]}") keys, len = tuple(Sites.keys()), len(Sites) for i in range(len): x, y = keys[i], keys[(i + 1) % len] print(f"{x} - {y}: {Sites[x].distance(Sites[y])} [km]")
- 実行結果
東京駅: (東経: 139.7673068, 北緯: 35.6809591) シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778) グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778) 東京駅 - シドニー・オペラハウス: 7823.269299386704 [km] シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km] グリニッジ天文台 - 東京駅: 9560.546566490015 [km]
- 内包表記などを使えば、もう少し「Pythonぽい」プログラムに出来たと思いますが、なるべく一対一に移植元と対応するよう実装しました。
- end が要らないのは簡便な反面、どこで定義が終わっているか判りづらいという問題もあり、__doc__ を充実させるなど工夫が必要そうです。
- 型アノテーションは付けていません。
附録
[編集]チートシート
[編集]# クラスの定義 class MyClass: class_variable = "hello" def __init__(self, instance_variable): self.instance_variable = instance_variable def instance_method(self): print("This is an instance method.") @classmethod def class_method(cls): print("This is a class method.") @staticmethod def static_method(): print("This is a static method.") # インスタンスの生成と属性へのアクセス obj = MyClass("world") print(obj.instance_variable) print(obj.class_variable) # インスタンスメソッドの呼び出し obj.instance_method() # クラスメソッドの呼び出し MyClass.class_method() # スタティックメソッドの呼び出し MyClass.static_method() # 継承 class MySubClass(MyClass): def __init__(self, instance_variable, sub_instance_variable): super().__init__(instance_variable) self.sub_instance_variable = sub_instance_variable def sub_instance_method(self): print("This is a subclass instance method.") # プロパティの定義 class MyClass: def __init__(self, instance_variable): self._instance_variable = instance_variable @property def instance_variable(self): return self._instance_variable @instance_variable.setter def instance_variable(self, value): self._instance_variable = value # 特殊メソッド class MyClass: def __init__(self, instance_variable): self.instance_variable = instance_variable def __str__(self): return f"MyClass object: {self.instance_variable}" def __eq__(self, other): return self.instance_variable == other.instance_variable # __getattr__と__setattr__による属性のカスタマイズ class MyClass: def __init__(self, instance_variable): self._instance_variable = instance_variable def __getattr__(self, name): return f"{name} is not defined." def __setattr__(self, name, value): print(f"{name} is being set to {value}.") super().__setattr__(name, value)
用語集
[編集]- クラス(class):オブジェクト指向プログラミングにおける基本的な概念の1つで、同じ属性やメソッドを持つオブジェクトの集合を定義します。
- インスタンス(instance):クラスを元に生成されるオブジェクトのことで、独自の属性やメソッドを持ちます。
- 属性(attribute):オブジェクトが持つデータを表します。クラスの属性は全てのインスタンスで共通です。
- メソッド(method):オブジェクトが持つ振る舞いを表します。クラスのメソッドは全てのインスタンスで共通です。
- コンストラクタ(constructor):クラスからインスタンスを生成する際に、インスタンスの初期化を行うメソッドです。通常、
__init__
メソッドとして定義されます。 - 継承(inheritance):既存のクラスを基に新たなクラスを定義することで、属性やメソッドを共有することができます。
- 親クラス(superclass):継承元のクラスのことを指します。
- 子クラス(subclass):継承したクラスのことを指します。
- オーバーライド(override):子クラスが親クラスの属性やメソッドを再定義することを指します。子クラスで同名の属性やメソッドを定義することで、親クラスのものを上書きすることができます。
- 多重継承(multiple inheritance):複数のクラスから同時に継承することを指します。
- ダックタイピング(duck typing):オブジェクトの型よりも、そのオブジェクトが持つ属性やメソッドを重視するプログラミングスタイルのことを指します。
- 抽象基底クラス(abstract base class):インスタンス化できない抽象的なクラスで、共通のインターフェースを定義することができます。抽象基底クラスを作成するために abc モジュールを使用します。
- デコレータ(decorator):関数やクラスに機能を追加するための構文で、@記号で始まり、関数やクラスの前に書かれます。クラスの場合、@classmethodや@staticmethodが使用されます。