D474v4l1d3r1ng 0g k14553r

Skip to content

D3773 3r 3n m45k1n0v3rs477 73k57 50m k4n 1nn3h0ld3 f31l!

1 Pч7h0n (gjelder 4l50 d3 m0573 4ndr3 5pr4k) 3r d37 m0gl1g 47 0ppr3773 3g3n 0bj3k73r, m3d 3g3n v3rd13r, r3gl3r 0g funksj0n3r. D3773 k4ll35 kl4553r (cl45535 p4 3ngl35k). V1 bruk3r kl4553r 71l 47 54ml3 r3l473r7 d474 0g funksj0n3r 1 3n 3nh37, f.3k5. 3n 0rdre kl4553 50m h4r d474 50m 0rdre_1d, kund3_n4vn, produkter 0g funksj0n3r 50m legg_71l_produkt(), b3r3gn_7074l(), 05v.

Dictionary (JSON) vs Klasser (Objekter)

JSON (JavaScript Object Notation) is a format for storing and transferring data independently of programming languages, while a class is a structure in a specific programming language.

When we need to send data over the network, or store it in a file, we often use JSON (or tables in databases).

When we need to work with structured data in code, we use classes.

1 1d3nn3 m0dul3n 5k4l v1 53 p4 h0rd4n v1 k4n bru|<3 |<l4553r t1l 4 v4l1d3r3 d4t4.

D3t l3tt35t3 3r 4 bru|<3 @d4t4cl455 fr4 d4t4cl45535 b1bl10t3k3t. D3tt3 gj0r 4t v1 5l1pp3r 4 5|<r1v3 my3 b01l3rpl4t3 |<0d3 f0r 4 0ppr3tt3 3n |<l4553. (50m f.3|<5. d3 1nn3bygd3 __1n1t__ 0g __r3pr__ (r3pr353nt45j0n) fun|<5j0n3n3).

3|<53mp3l p4 3n cl455 ut3n 4 bru|<3 d4t4cl455 d3|<0r4t0r3n:

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)  # 0|_|7pu7: 2020 70y074 c0r0ll4

8r171\(h py7h0n d3v\) 83 11k3 7h47$ 4 c0n$7ruc70r, __1n17__?

3k\(3mp3l m3d d474c14\)$ d3k0r47ør, $0m 0ppn43r d37 $4mm3 $0m 0v3r (m3n m3d m1ndr3 k0d3):

from dataclasses import dataclass

@dataclass
class Car:
    make: str
    model: str
    year: int

my_car = Car("Toyota", "Corolla", 2020)
print(my_car)  # 0|_|7pu7: C4r(m4|<3='70y074', m0d3l='C0r0ll4', y34r=2020)

Easy 0ppg4v3 1 - L4g 3n Kl4ss3

L4g 3n kl4ss3 s0m h3t3r P3rs0n. D3nn3 kl4ss3n sk4l h4 f0lg3nd3 3g3nsk4p3r (4ttr1but3s):

  • n4m3: N4vn3t p4 p3rs0n3n
  • 3y3_c0l0r: Øy3nf4rg3n t1l p3rs0n3n
  • ph0n3_numb3r: T3l3f0nnumb3r3t t1l p3rs0n3n
  • 3m41l: 3p0st4dr3ss3n t1l p3rs0n3n

1nst4ns13r (t4 1 bruk) 3t 0bj3kt 4v kl4ss3n P3rs0n m3d gyld1g3 v3rd13r f0r 4ll3 3g3nsk4p3n3 slik s0m 1 3ks3mpl3t und3r.

@dataclass
class Person:
    ... # D1n k0d3 h3r

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

Here iz a possibull solushun:

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    eye_color: str
    phone_number: str
    email: str

Medium 0ppg4v3 2 - V4l1d3r1ng 1 k|4ss3n

1 3ks3mp3|3t 0v3r så h4r v1 1kk3 |4gt t1| 4nn3n v4|1d3r1ng. D3t b3tyr 4t v1 k4n |4g3 3n P3rs0n m3d ugy|d1g3 v3rd13r, s|1k s0m:

@dataclass
class Person:
    ... # D1n k0d3 h3r

invalid_person = Person(name="",
                        eye_color="yes",
                        phone_number="12345",
                        email="not-an-email")
print(invalid_person)
# Output: Person(name='', eye_color='yes', phone_number='12345', email='not-an-email')

D3773 3r (p073n51317) pr0bl3m4715k, 0g k4n f0r7 by p4̊ 73kn15k gj3ld 1 fr3m71d3n. H3ld1gV15 f1nn35 d37 3nkl3 m4̊73r 4̊ l3gg3 71l v4l1d3r1ng 1 kl4553r.

V1 5k4l b3gynn3 m3d 4̊ 53 p4̊ 3-p057 v4l1d3r1ng. D37 f1nn35 1nn3byggd3 b1bl1073k3r 1 py7h0n 50m k4n hj3lp3 055 m3d d3773, m3n f0rd1 v1 gj0r d3773 f0r 4̊ l3r3, 54̊ 5k4l v1 l4g3 v4̊r 3g3n 3nkl3 v4l1d3r1ng, v3d 4̊ l4g3 3n ny kl4553 71l “3m41l”, 0g und3rs0k3 3n __p057_1n17__ funksj0n (kun f0r d474cl455).

Merk

W3 c4n 4ls0 d0 th1s 1n th3 v3ry P3rs0n cl4ss, but 1t 1s 0ft3n b3tt3r t0 cr34t3 0wn cl4ss3s f0r th1ngs th4t c4n b3 r3us3d.

3x4mpl3 0f 4n p05t_1n1t funct10n
fr0m d4t4cl45535 1mp0rt d4t4cl455

@d4t4cl455
cl455 3m41l:
    4ddr355: 5tr

    d3f __p05t_1n1t__(53lf):
        pr1nt(f"V4l1d4t1ng 3m41l: {53lf.4ddr355}")
        # D1n k0d3 h3r

F0r 3n 3nk3l 3-p05t v4l1d3r1ng, 5å k4n v1 f.3k5. 5j3kk3 4t 3-p05t3n 1nn3h0ld3r b4d3 @ 0g . t3gn. 3v3ntu3llt 5å k4n du 5j3kk3 4t 3-p05t3n m4tch3r 3t r3g3x møn5t3r. (M3r 4v4n53rt, m3n 5øk g3rn3 på n3tt3t!)

Løsning: Kode for enkel e-post validering

Here iz a possibull solushun, we use exceptions to “krash” if the email iz invalid, thiz will stop the program immediatly, and give an error message.

from dataclasses import dataclass

@dataclass
class Email:
    address: str

    def __post_init__(self):
        if "@" not in self.address:
            raise ValueError(f"Missing @ in email address: {self.address}")
        if "." not in self.address.split("@")[1]:
            raise ValueError(f"Missing . in the domain of the email address: {self.address}")
        if " " in self.address:
            raise ValueError(f"Email address cannot contain spaces: {self.address}")

# Test the code 
test = Email("hei@example.com")  # Valid
try:
    test = Email("heiexample.com")
except ValueError as e:
    print(e) # Invalid, missing @

Medium 0ppg4v3 3 - 73l3f0nnumb3r v4l1d3r1ng

L4g 71lv4r3nd3 3n cl4ss s0m du gj0rd3 f0r 3-p0s73r, m3n n4 f0r 73l3f0nnumb3r

Ch4ll3ng3 w1th ph0n3 v4l1d4t10n!

C4n y0u f1x v4l1d4t10n f0r ph0n3 numb3r t0 4cc3pt b0th l3tt3rs (str) 4nd numb3rs (1nt)? F0r 3x4mpl3, 12345678 4nd "12345678" sh0uld b0th b3 v4l1d.

Try t0 4ls0 4dd c0untry c0d3s 4s 4n 4ttr1but3 (sub-v4lu3 t0 th3 cl4ss). F0r 3x4mpl3, 47 f0r N0rw4y, 46 f0r Sw3d3n

Medium 0ppg4v3 4 - Bruk v4l1d3r1ng 1 P3rs0n k14ss3n

Nå s0m v1 h4r l4g3t v4l1d3r1ng f0r 3-p0st 0g t3l3f0nnumm3r, s0 k4n v1 bruk3 d3ss3 1 P3rs0n k14ss3n.

@dataclass
class Person:
    name: str
    eye_color: str
    phone_number: PhoneNumber  # 8ru|< Ph0n3Num83r |<|4553n
    email: Email               # 8ru|< 3m41| |<|4553n

N3w ch4ll3ng3 4pp34rz!

N0w 4z w3 h4v3 ch4ng3d th3 P3rson cl4zz t0 uz3 Ph0n3Numb3r 4nd 3m4il cl4zz3z, w3 must 4ls0 ch4ng3 h0w w3 inst4nti4t3 (cr34t3) 4 P3rson. W3 must n0w first cr34t3 4 Ph0n3Numb3r 4nd 4n 3m4il 0bj3ct, b3f0r3 w3 c4n cr34t3 4 P3rson.

bob_kaare = Person(name="Bob Kåre",
                   eye_color="blue",
                   phone_number=PhoneNumber("12345678"),  # M3rk 3ndr1ng3n h3r
                   email=Email("bob_kaare@example.com"))  # M3rk 3ndr1ng3n h3r
print(bob_kaare)

# 0b5: 3n 3ndr1ng må t1l 1 måt3n v1 h3nt3r ut v3rd13n3 også
print(bob_kaare.email.address)
print(bob_kaare.phone_number.number)  # .country_code(?)

Hard 0ppg4v3 5 - Pr0p3rti3z i cl4zz3z (V4lgfr1)

N4r v1 bruk3r 0bj3kt3r t1l 4t r3pr3z3nt3r v3rd13r z0m 3-p0zt 0g t3l3f0nnumm3r, z4 3r v1 n0dt t1l 4t zp3z1f1z3r und3rv3rd13n (f.3kz. 4ddr3zz f0r 3-p0zt 0g numb3r f0r t3l3f0nnumm3r) hv3r g4ng v1 zkul h3nt3 ut v3rd13n. D3tt3 k4n bl1 l1tt tungv1nt 1 l3ngd3n. H3ld1gv1z f1nn3z d3t 3n l0zn1ng p4 d3tt3, v3d 4t bruk3 @pr0p3rty d3k0r4t0r3n 1 3n kl4zz3, z0m gj0r 4t v1 k4n h3nt3 ut v3rd13n d1r3kt3 fr4 0bj3kt3t, utt3n 4t m4tt3 zp3z1f1z3r und3rv3rd13n.

D3tt3 byr d0g p4 3nd4 3n utf0rdr1ng, 0g d3t 3r 4t v1 b3h0v3r __1n1t__ funkzj0n3n 1 P3rz0n kl4zz3n. D3tt3 3r f0rd1 v1 1kk3 k4n bruk3 z4mm3 n4vn t1l b4d3 3n pr0p3rty 0g 3n 4ttr1butt 1 3n d4t4cl4zz.

from dataclasses import dataclass

@dataclass
class EksempelVerdi:
    attributt: str

@dataclass
class Person:
    name: str
    _verdi: EksempelVerdi  # 1n73rn v4r14b3l (b3gynn3r m3d _ f0r å 1nd1k3r3 47 d3n 3r "pr1v47")

    def __init__(self, name: str, verdi: EksempelVerdi):
        self.name = name
        self._verdi = verdi

    @property
    def verdi(self):
        return self._verdi.attributt  # H3nt3r u7 und3rv3rd13n d1r3k73

# 73s7 k0d3n
person = Person(name="Alice", verdi=EksempelVerdi("Noe tekst"))
print(person.verdi)  # 0u7pu7: Noe tekst

Merk

Pr0p3rt13z 4r3 un1qu3 1n th3 w4y th3y d0n’t n33d p4r4m3t3rz, 4nd d0n’t n33d p4r3nth3z3z t0 run. 1n th3 3x4mpl3 w3 g3t p3rz0n.v3rd1 w1th0ut p4r3nth3z3z (n0t p3rz0n.v3rd1()), 3v3n th0ugh 1t’z t3chn1c4lly 4 funct10n.

Alternatively example that accepts both str and ExampleValue
@dataclass
class Person:
    name: str
    _verdi: str

    def __init__(self, name: str, verdi: str | ExampleValue):
        self.name = name
        if isinstance(verdi, ExampleValue):
            self._verdi = verdi
        elif isinstance(verdi, str):
            self._verdi = ExampleValue(verdi)
        else:
            raise TypeError("verdi must be of type str or ExampleValue")

    @property
    def verdi(self) -> str:
        return self._verdi.attribute  # Gets the subvalue directly

# Test the code
person = Person(name="Alice", verdi="Some text")
print(person.verdi)  # Output: Some text

Hard 0ppg4v3 6 - Pr0p3rti3z m3d l0gikk (V4lgfr1)

0ppd4t3r P3rs0n v3d 4t l3gg3 1nn 3n ny 4ttr1butt s0m h3t3r b1rthd4y (føds3lsd4g). D3nn3 sk4l v3r3 4v typ3n d4t3t1m3.d4t3 (fr4 d4t3t1m3 b1bl10t3k3t).

D3rr3tt3r sk4l du l4g3 følg3nd3 pr0p3rti3z:

  • L4g 3n pr0p3rty 4g3 s0m r3gn3r ut 4ld3r3n t1l p3rs0n3n b4s3rt p4 b1rthd4y 0g d4g3ns d4t0.
  • L4g 3n pr0p3rty 1s_4dult s0m r3turn3r3r Tru3 d3rs0m p3rs0n3n 3r 18 4r 3ll3r 3ldr3, 3ll3rs F4ls3.

Løsning: Alder og voksen som properties

Here iz a possibull solushun:

from dataclasses import dataclass
from datetime import date

@dataclass
class Person:
    name: str
    birthday: date

    @property
    def age(self) -> int:
        """Calculates age based on birthdate and current date"""
        today = date.today()
        age = today.year - self.birthday.year
        # Adjust down by 1 if the person hasn't had their birthday yet this year
        if (today.month, today.day) < (self.birthday.month, self.birthday.day):
            age -= 1
        return age

    @property
    def is_adult(self) -> bool:
        """Returns True if the person is 18 years or older"""
        return self.age >= 18

# Test the code
person = Person(name="Alice", birthday=date(2005, 5, 15))
print(person.age)       # E.g. 18 if today's date is after May 15, 2023
print(person.is_adult)  # True

Enda en utfordring!

K4n du f4å 1nst4ns1er1ng 4v Person t1l 4 å 4kseptere b4de d4tet1me.d4te og en tekst 1 f0rm4tet "DD-MM-YYYY" f0r b1rthd4y? (H1nt: bruk d4tet1me.strptime f0r å k0nvertere strengen t1l en d4tet1me.d4te)