これは機械翻訳されたテキストであり、誤りを含む可能性があります!
Python (およびほとんどの他の言語でも) では、独自のオブジェクトを作成し、独自の値を、ルール、および関数を定義できます。これはクラス (英語では classes) と呼ばれます。クラスを使用して、関連するデータと関数を 1 つの単位にまとめます。たとえば、ordre_id、kunde_navn、produkter などのデータと、legg_til_produkt()、beregn_total() などの関数を持つ Ordre クラスなどです。
Dictionary (JSON) vs Klasser (Objekter)
JSON (JavaScript Object Notation) は、プログラミング言語に依存せずにデータを保存および転送するための形式であり、クラスは特定のプログラミング言語における構造です。
ネットワーク経由でデータを送信したり、ファイルに保存したりする場合は、JSON(またはデータベースのテーブル)をよく使用します。
コード内で構造化されたデータを使用する場合は、クラスを使用します。
このモジュールでは、クラスを使ってデータを検証する方法を見ていきます。
最も簡単な方法は、dataclassesライブラリの@dataclassを使用することです。これにより、クラスを作成するための多くのボイラープレートコードを記述する必要がなくなります。(たとえば、組み込みの__init__と__repr__(表現)関数など)。
dataclassデコレータを使用しないクラスの例:
class Car:
def __init__(self, make: str, model: str, year: int):
self.make = make
self.model = model
self.year = year
def __repr__(self):
return f"{self.year} {self.make} {self.model}"
my_car = Car("Toyota", "Corolla", 2020)
print(my_car) # 出力: 2020 Toyota Corolla
データクラスデコレータを使った例で、上記と同じ結果を得られます(ただし、コード量が少なくなります)。
from dataclasses import dataclass
@dataclass
class Car:
make: str
model: str
year: int
my_car = Car("Toyota", "Corolla", 2020)
print(my_car) # 出力:Car(make='Toyota', model='Corolla', year=2020)
課題 1 - クラスを作成する
Person という名前のクラスを作成してください。このクラスは、以下の属性を持つ必要があります。
name: 人の名前eye_color: 人の目の色phone_number: 人の電話番号email: 人のメールアドレス
以下の例のように、すべての属性に有効な値を持つ Person クラスのインスタンス(オブジェクト)を作成してください。
@dataclass
class Person:
... # ここにあなたのコードを記述してください
bob_kaare = Person(name="Bob Kåre",
eye_color="blue",
phone_number="12345678",
email="bob_kaare@example.com")
print(bob_kaare)
Løsning: En dataclass for Person
ここに可能な解決策を示します:
from dataclasses import dataclass
@dataclass
class Person:
name: str
eye_color: str
phone_number: str
email: str
課題 2 - クラスでの検証
上記の例では、_検証_を追加していません。つまり、次のような無効な値を持つ Person を作成できます。
@dataclass
class Person:
... # ここにあなたのコードを記述してください
invalid_person = Person(name="",
eye_color="yes",
phone_number="12345",
email="not-an-email")
print(invalid_person)
# 出力: Person(name='', eye_color='yes', phone_number='12345', email='not-an-email')
これは(潜在的に)問題があり、将来的に技術的負債につながる可能性があります。幸いなことに、クラスに検証を追加する簡単な方法があります。
まず、電子メールの検証を見てみましょう。Pythonには、これを支援できる組み込みライブラリがありますが、学習のためにこれを行っているため、新しい「Email」クラスを作成し、__post_init__関数(dataclassのみ)を調べて、独自の単純な検証を作成します。
Merk
私たちは、これを Person クラス自体内でも行うことができますが、再利用可能なものの場合は、専用のクラスを作成する方が良いことがよくあります。
post_init 関数の例
from dataclasses import dataclass
@dataclass
class Email:
address: str
def __post_init__(self):
print(f"Validating email: {self.address}")
# ここにコードを記述
単純なメールアドレスの検証を行う場合、例えば、メールアドレスに @ と . の両方の文字が含まれているかどうかを確認できます。必要に応じて、メールアドレスが正規表現パターンに一致するかどうかを確認することもできます。(より高度ですが、ぜひウェブで検索してみてください!)
Løsning: Kode for enkel e-post validering
ここに可能な解決策を示します。メールアドレスが無効な場合に「クラッシュ」させるために例外を使用します。これにより、プログラムがすぐに停止し、エラーメッセージが表示されます。
from dataclasses import dataclass
@dataclass
class Email:
address: str
def __post_init__(self):
if "@" not in self.address:
raise ValueError(f"Mangler @ i epostadressen: {self.address}")
if "." not in self.address.split("@")[1]:
raise ValueError(f"Mangler . i domenet til epostadressen: {self.address}")
if " " in self.address:
raise ValueError(f"Epostadressen kan ikke inneholde mellomrom: {self.address}")
# Test koden
test = Email("hei@example.com") # Gyldig
try:
test = Email("heiexample.com")
except ValueError as e:
print(e) # Ugyldig, mangler @
課題 3 - 電話番号の検証
メールアドレスで行ったのと同じように、電話番号用のクラスを作成してください。
電話番号の検証における課題!
電話番号の検証を修正して、文字(str)と数字(int)の両方を受け入れられるようにできますか? 例えば、12345678と"12345678"の両方が有効である必要があります。
また、国番号を属性(クラスのサブ値)として追加してみてください。例えば、ノルウェーの47、スウェーデンの46など。
課題4 - Personクラスで検証を使用する
これで、メールアドレスと電話番号の検証を作成したので、それらを Person クラスで使用できます。
@dataclass
class Person:
name: str
eye_color: str
phone_number: PhoneNumber # PhoneNumberクラスを使用
email: Email # Emailクラスを使用
新しい課題が発生しました!
これで、PersonクラスがPhoneNumberとEmailクラスを使用するように変更されたので、Personのインスタンス化(作成)方法も変更する必要があります。 まず、PhoneNumberとEmailオブジェクトを作成してから、Personを作成する必要があります。
bob_kaare = Person(name="Bob Kåre",
eye_color="blue",
phone_number=PhoneNumber("12345678"), # 変更点に注意してください
email=Email("bob_kaare@example.com")) # 変更点に注意してください
print(bob_kaare)
# 注意:値の取得方法も変更する必要があります
print(bob_kaare.email.address)
print(bob_kaare.phone_number.number) # .country_code(?)
課題 5 - クラスのプロパティ (任意)
オブジェクトを使ってメールアドレスや電話番号のような値を表現する場合、値を取得するたびにサブ値 (例: メールアドレスの address、電話番号の number) を指定する必要があります。これは長期的には少し面倒になる可能性があります。幸いなことに、これに対する解決策があり、クラスの @property デコレータを使用することで、サブ値を指定することなく、オブジェクトから直接値を取得できます。
ただし、これにより別の課題が生じます。それは、Person クラスの __init__ 関数が必要になることです。これは、データクラスでプロパティと属性に同じ名前を使用できないためです。
from dataclasses import dataclass
@dataclass
class EksempelVerdi:
attributt: str
@dataclass
class Person:
name: str
_verdi: EksempelVerdi # 内部変数(_で始まることで「プライベート」であることを示す)
def __init__(self, name: str, verdi: EksempelVerdi):
self.name = name
self._verdi = verdi
@property
def verdi(self):
return self._verdi.attributt # 下位値を直接取得する
# テストコード
person = Person(name="Alice", verdi=EksempelVerdi("Noe tekst"))
print(person.verdi) # 出力: Noe tekst
Merk
プロパティは、パラメータを必要とせず、実行時に括弧を必要としない点でユニークです。例では、person.verdi を括弧なしで取得しています ( person.verdi() ではありません)。これは、技術的には関数であるにもかかわらずです。
代替例で、str と EksempelVerdi の両方を受け入れる
@dataclass
class Person:
name: str
_verdi: str
def __init__(self, name: str, verdi: str | EksempelVerdi):
self.name = name
if isinstance(verdi, EksempelVerdi):
self._verdi = verdi
elif isinstance(verdi, str):
self._verdi = EksempelVerdi(verdi)
else:
raise TypeError("verdi må være av type str eller EksempelVerdi")
@property
def verdi(self) -> str:
return self._verdi.attributt # Henter ut underverdien direkte
# テストコード
person = Person(name="Alice", verdi="Noe tekst")
print(person.verdi) # 出力: Noe tekst
課題 6 - ロジックを持つプロパティ (オプション)
Person を更新し、birthday (誕生日) という新しい属性を追加します。これは datetime.date 型 ( datetime ライブラリから) である必要があります。
次に、次のプロパティを作成します。
birthdayと現在の日付に基づいて、その人の年齢を計算するageプロパティを作成します。- その人が 18 歳以上の場合に
Trueを返し、それ以外の場合はFalseを返すis_adultプロパティを作成します。
Løsning: Alder og voksen som properties
ここに可能な解決策を示します:
from dataclasses import dataclass
from datetime import date
@dataclass
class Person:
name: str
birthday: date
@property
def age(self) -> int:
"""生年月日と現在の日付に基づいて年齢を計算します"""
today = date.today()
age = today.year - self.birthday.year
# まだ今年の誕生日を迎えていない場合は、1減算します
if (today.month, today.day) < (self.birthday.month, self.birthday.day):
age -= 1
return age
@property
def is_adult(self) -> bool:
"""その人が18歳以上である場合はTrueを返します"""
return self.age >= 18
# コードをテストします
person = Person(name="Alice", birthday=date(2005, 5, 15))
print(person.age) # 例:今日が2023年5月15日以降の場合は18歳
print(person.is_adult) # True
また別の課題です!
Personのインスタンス化が、datetime.dateと、birthdayのフォーマットが "DD-MM-YYYY" の文字列の両方を受け入れるようにできますか?(ヒント:文字列をdatetime.dateに変換するには、datetime.strptimeを使用してください)
