クラスとオブジェクト

これまでに使ってきたあらゆる型(文字列、リスト、辞書)は実はクラスです。"hello".upper()を呼び出すとき、文字列オブジェクトのメソッドを呼び出しています。クラスを使うと、独自の型を定義でき、独自のデータと動作を持たせることができます。Playerクラスは名前、スコア、レベルを保持でき、自分自身の表示方法を知っています。
ブループリントとインスタンス
クラスはブループリント(設計図)です。インスタンスはそのブループリントから作られた具体的なもの(実体)です。必要に応じて何個でもインスタンスを作成できます。各インスタンスは独自のデータを持ちながら、クラスで定義されているメソッドを共有します。
class Dog:
def bark(self):
print("Woof!")
rex = Dog()
luna = Dog()
rex.bark() # "Woof!"
luna.bark() # "Woof!"Dogはクラスです。rexとlunaはインスタンスです:2つの異なる犬で、クラスで定義されている同じ動作を共有しています。
Dog()、新しいインスタンスが返されます。すべてのインスタンスはクラスのメソッドを共有しながら、独自のデータを保つため、レックスとルナは同じように動作しながら別の犬になります。 __init__とself
__init__は、新しいインスタンスを作成するときにPythonが自動的に呼び出すメソッドです。オブジェクトの開始データを設定する場所です。selfは、メソッドが操作している特定のインスタンスを参照する方法で、常に最初のパラメーターです。
class Player:
def __init__(self, name, score=0):
self.name = name
self.score = score
def add_points(self, points):
self.score += points
def display(self):
print(f"{self.name}: {self.score} points")
alice = Player("太郎")
bob = Player("花子", score=50)
alice.add_points(30)
alice.display() # "太郎: 30 points"
bob.display() # "花子: 50 points"self.nameとself.scoreはインスタンス属性です:特定のオブジェクトに属し、クラス自体ではなく。各Playerインスタンスは独自のnameとscoreを持ちます。
__init__はインスタンスを作成する瞬間に実行されるため、self.name = valueで開始データを設定する場所です。selfはPythonが作業しているインスタンスで、常にメソッドの最初のパラメーターで、自動的に渡されます。alice.display()を呼び出すときに、self自体を渡すことはありません。 メソッド
クラス内で定義される任意の関数はメソッドです。インスタンスメソッドは常に最初のパラメーターとしてselfを持ちます;Pythonはそれを自動的に渡します。メソッドはself経由でインスタンスのデータを読取および変更できます。
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def scale(self, factor):
self.radius *= factor
return self # self を返すことでチェーニングが可能になります: c.scale(2).scale(0.5)
c = Circle(5)
print(c.area()) # 78.53975
c.scale(2)
print(c.area()) # 314.159selfで、それが作用しているインスタンスです。Pythonはselfを渡すため、追加なしでc.area()を呼び出します。selfを通じて、メソッドはそのオブジェクト独自のデータを読取および変更します。 クラス変数とインスタンス変数
クラスに直接定義された変数(__init__内ではなく)はクラス変数です。すべてのインスタンスは同じクラス変数を共有します。__init__内のselfに設定された変数はインスタンス変数で、各オブジェクトに固有です。
class Player:
max_lives = 3 # クラス変数、すべての Player に同じ
def __init__(self, name):
self.name = name # インスタンス変数、各 Player に固有
self.lives = Player.max_lives
def die(self):
self.lives -= 1
alice = Player("太郎")
bob = Player("花子")
Player.max_lives = 5 # 現在および将来のすべてのインスタンスのために変更クラス変数をすべてのインスタンスで共有される値に使用します:定数、カウンター、デフォルト。インスタンス変数をオブジェクトごとに異なるデータに使用します。
__init__のselfに設定された変数はそのオブジェクトに属します。self.attr = valueを書き込むことは常にインスタンス独自のコピーを作成または更新します。そのため、値がすべての人で同じときはクラス変数に到達し、オブジェクトごとに異なるときはインスタンス変数に到達します。 __str__と__repr__
__str__は、print()と f-strings がオブジェクトに対して表示するものを制御します。__repr__は、コンソールで表示され、デバッグするための開発者ビューを制御します。常に__repr__を定義してください。__str__を定義して、デバッグビューとは別の清潔なユーザー向けディスプレイが必要なときに。
class Player:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"{self.name} ({self.score} pts)"
def __repr__(self):
return f"Player(name={self.name!r}, score={self.score})"
alice = Player("太郎", 87)
print(alice) # "太郎 (87 pts)" (__str__ を使用)
repr(alice) # "Player(name='太郎', score=87)" (__repr__ を使用)常に__repr__を定義します。デバッグビューとは別に清潔なユーザー向け表現が必要なときは__str__を定義します。__repr__のみが定義されている場合、Pythonはそれを両方に使用します。
__str__はprint()と f-strings が表示するもの、フレンドリー版です。__repr__は開発者ビューで、コンソールで見えるものです。常に__repr__を書いてください;`__str__`を忘れた場合でも仕事を持つ1つです。ユーザー向けテキストが異なるように読むべきときのみ__str__を追加します。 プライベート規約
Pythonには本当のプライベート変数がありませんが、名前の開始時に1つのアンダースコア(_balance)は「これは内部で、クラスの外から直接使用しないでください」を合図する規約です。言語によって強制されません;これは他の開発者へのコミュニケーションです。
class BankAccount:
def __init__(self, balance):
self._balance = balance # _ は「触らないでください」を意味します
def deposit(self, amount):
if amount > 0:
self._balance += amount
def balance(self):
return self._balanceダブルアンダースコア(__name)はトリガー名前マングリング;Pythonは属性を_ClassName__nameに名前変更して、サブクラス内の衝突を回避します。これはめったに必要ありません。シングルアンダースコアはほとんどのコードの規約です。
_balance)は「内部、外から放っておいてください」の合意された合図です。何も止めません。これは他の開発者、将来あなたへのメッセージです。ダブルアンダースコアはサブクラス内で名前の衝突を回避するためのまれなツール;シングルアンダースコアは日々使うものです。 継承
クラスは別のクラスから継承でき、自動的にすべての属性とメソッドを取得します。その後、サブクラスで特定のメソッドをオーバーライドして、それらの動作を変更できます。これにより、一般的なベースを再利用し、必要に応じて特殊化できます。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
pets = [Dog("レックス"), Cat("ルナ"), Dog("マックス")]
for pet in pets:
print(pet.speak())DogとCatはAnimalから__init__を継承するため、それら独自が必要ありません。それらspeak()をその特定の動作でオーバーライドします。
DogとCatはAnimalの__init__を再利用し、speak()のみを再定義します。 super()
super()は親クラスからメソッドを呼び出します。全く置き換えるのではなく、親の動作を拡張したいときはそれを使用します:親の__init__を呼び出して、そのセットアップを実行し、その後、サブクラスが必要なあらゆるものの上に追加します。
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
class Dog(Animal):
def __init__(self, name):
super().__init__(name, "Woof") # Animal.__init__ を呼び出し
self.tricks = [] # 追加なにかを追加
def learn(self, trick):
self.tricks.append(trick)
rex = Dog("レックス")
rex.learn("sit")
print(rex.tricks) # ["sit"]サブクラスが独自の__init__を持ち、親もそうであるときはいつもsuper().__init__()を呼び出します。
super()は親クラスに到達するため、super().__init__()は自分の追加する前に親のセットアップを実行します。サブクラスが独自の__init__を書き、親も持つときはそれを使用します。スキップすることは親のセットアップが実行されず、オブジェクトを半構築のままにする可能性があることを意味します。 クラスメソッドと静的メソッド
@classmethodはインスタンスの代わりにクラス自体を受け取るメソッドを作成します。文字列、ファイル、または別の形式からインスタンスを作成する代替コンストラクターに有用です。@staticmethodは組織的な理由でクラス内に住んでいるプレーンな関数です;インスタンスもクラスも受け取りません。
class Player:
def __init__(self, name, score):
self.name = name
self.score = score
@classmethod
def from_string(cls, data):
name, score = data.split(",")
return cls(name, int(score))
alice = Player.from_string("太郎,87")class Player:
@staticmethod
def is_valid_name(name):
return name.isalpha() and len(name) >= 2
Player.is_valid_name("太郎") # True
Player.is_valid_name("太郎1") # False代替コンストラクターのために@classmethodを使用します。クラスに論理的に属するがインスタンスまたはクラスデータを必要としないユーティリティ関数のために@staticmethodを使用します。
@classmethodはインスタンスではなくクラスを手渡し、代替コンストラクターで行きます:文字列、ファイル、あらゆる形式のプレーヤーを構築します。@staticmethodは清潔さのためにクラスの中に詰め込まれたオーディナリー関数です;クラスもインスタンスも取りません。プレーンメソッドは1つのオブジェクトのデータに触れ、これら2つは接触しません。 @property
@propertyはメソッドを属性のようにアクセスでき、括弧は必要なしで。他の属性から計算されたている値で、シンプルな属性アクセスのような読む自然に感じるためにそれを使用します。
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius ** 2
@property
def diameter(self):
return self.radius * 2
c = Circle(5)
print(c.area) # 78.53975 (属性のように見える、メソッドのように実行する)
print(c.diameter) # 10属性は計算値に有用です:他の属性から派生するものは、()なしで属性として読む自然に感じるもの。
@propertyはメソッドを属性のような読みできます、括弧なし:c.area()ではなくc.area。他の属性から働かされた値に合い、プレーンなデータとして読む自然に感じます。舞台裏、それはそれにアクセスするたびにあなたのメソッドを実行します。 実践
インスタンス属性、メソッド、@property、__str__を持つPlayerクラス:
class Player:
max_lives = 3
def __init__(self, name: str):
self.name = name
self.score = 0
self.lives = Player.max_lives
def earn_points(self, amount: int) -> None:
self.score += amount
def take_hit(self) -> bool:
self.lives -= 1
return self.lives > 0
@property
def is_alive(self) -> bool:
return self.lives > 0
def __str__(self) -> str:
return f"{self.name} | Score: {self.score} | Lives: {self.lives}"
alice = Player("太郎")
alice.earn_points(50)
alice.take_hit()
print(alice) # "太郎 | Score: 50 | Lives: 2"
print(alice.is_alive) # True
