12: Class & Object

12-4: Object Method

** ถ้าใช้งานบนมือถือหรือ tablet แนะนำให้ใช้ Chrome หรือ Safari เท่านั้น **

แบบฝึกหัด 12-4 ข้อที่ 1

code ข้างล่างนี้มีคลาส Point ที่แทนจุดในระนาบสองมิติ มีบริการ clone เพื่อทำสำเนาจุด และ move_to เพื่อตั้งพิกัดใหม่ให้กับจุด จงเขียนสามคำสั่งตามลำดับดังนี้ (ไม่ต้องแก้ไขคำสั่งใด ๆ ในคลาส Point)

  • สร้างจุดใหม่ให้มีพิกัด (2, 5) เก็บในตัวแปร a
  • สร้างสำเนาของจุด a แล้วไปเก็บในตัวแปร b
  • ย้ายจุด a ไปที่พิกัด (3,10)

class Point: def __init__(self, x, y): self.x = x self.y = y def clone(self): return Point(self.x, self.y) def move_to(self, x, y): self.x = x self.y = y class Point: def __init__(self, x, y): self.x = x self.y = y def clone(self): return Point(self.x, self.y) def move_to(self, x, y): self.x = x self.y = y a = Point(2,5) b = a.clone() a.move_to(3,10) Ex().check_function('Point', missing_msg = "ไม่มีคำสั่งสร้างจุดด้วย Point(...)").multi( check_args('x').has_equal_value(incorrect_msg = "ค่า x ที่ให้ตอนสร้างจุด a ไม่ถูกต้อง"), check_args('y').has_equal_value(incorrect_msg = "ค่า y ที่ให้ตอนสร้างจุด a ไม่ถูกต้อง") ) Ex().has_equal_ast(code = "b = a.clone()", incorrect_msg = "ไม่มีคำสั่งทำสำเนาจุด a ด้วย clone แล้วไปเก็บที่ b") Ex().check_not(has_code(r"=\s*a\s*\.\s*move_to"), msg = "ไม่มีคำสั่งย้ายจุด a ด้วย move_to") Ex().check_function('a.move_to', missing_msg = "ไม่มีคำสั่งย้ายจุด a ด้วย move_to").multi( check_args('x').has_equal_value(incorrect_msg = "ค่า x ที่ให้ตอนย้ายจุด a ไม่ถูกต้อง"), check_args('y').has_equal_value(incorrect_msg = "ค่า y ที่ให้ตอนย้ายจุด a ไม่ถูกต้อง") ) for var in "ab": obj = Ex().check_object(var, missing_msg = "ไม่พบตัวแปร " + var) obj.multi( has_equal_value(expr_code="str(type("+var+"))", incorrect_msg = var + " ต้องเป็นอ็อบเจกต์ของ Point"), has_equal_value(expr_code = var + ".x", incorrect_msg = "พิกัด x ของ " + var + " ไม่ถูกต้อง"), has_equal_value(expr_code = var + ".y", incorrect_msg = "พิกัด y ของ " + var + " ไม่ถูกต้อง") )
แบบฝึกหัด 12-4 ข้อที่ 2

code ข้างล่างนี้มีคลาส Point ที่แทนจุดในระนาบสองมิติ และฟังก์ชัน shift(dx, dy, p) ที่ปรับพิกัด (x,y) ของจุด p ไปเป็น (x+dx, y+dy) หน้าที่ของฟังก์ชันนี้น่าจะเป็นส่วนหนึ่งของคลาส Point จะเหมาะสมกว่า (ทำให้แทนที่เขียน shift(2,4,p) ก็เขียนเป็น p.shift(2,4)) จงย้ายฟังก์ชัน shift ให้กลายเป็นเมท็อด shift ของคลาส Point

class Point: def __init__(self, x, y): self.x = x self.y = y def shift(dx, dy, p): p.x += dx p.y += dy class Point: def __init__(self, x, y): self.x = x self.y = y def shift(self, dx, dy): self.x += dx self.y += dy import types obj = types.SimpleNamespace q = "`" clsname = "Point" qclsname = q+clsname+q mname = "shift" qmname = q+mname+q point = obj(x=57, y=29) Ex().check_class_def(clsname, missing_msg="ไม่พบคลาส " + qclsname).\ check_body().check_function_def(mname, missing_msg="ไม่พบเมท็อด " + qmname).multi( has_equal_part_len('args', qmname + " รับพารามิเตอร์สามตัว"), check_args('self', missing_msg = "ช่วยเขียนพารามิเตอร์ตัวแรกของ "+ qmname + " ให้เป็น `self`"), check_body().set_context(point, 2, -3).multi( has_equal_value(name = 'self.x', incorrect_msg = "shift ปรับค่า x ไม่ถูกต้อง"), has_equal_value(name = 'self.y', incorrect_msg = "shift ปรับค่า y ไม่ถูกต้อง") ) )
แบบฝึกหัด 12-4 ข้อที่ 3

code ข้างล่างนี้มีคลาส BankAccount ภายในอ็อบเจกต์ของคลาสนี้เก็บเลขบัญชี ชื่อบัญชี ยอดคงเหลือ และยอดขั้นต่ำที่ต้องมี (คือจะไม่ให้ถอน ถ้าถอนแล้วยอดคงเหลือน้อยกว่ายอดขั้นต่ำ) และมีเมท็อด set_minimum ให้บริการตั้งยอดขั้นต่ำใหม่ได้ จงเขียนเมท็อด

  • deposit รับจำนวนเงิน เพื่อฝากเพิ่มให้บัญชี (ถ้าจำนวนเงินติดลบ จะไม่เปลี่ยนค่าใด ๆ)
  • withdraw ลองคิดดูเองว่า ข้อกำหนดของการถอนจะต้องมีอะไรบ้าง
ทั้งสองเมท็อดนี้ ไม่ต้องคืนผลอะไร และถ้าไม่มีการฝาก หรือถอนใด ๆ (เนื่องจากจำนวนที่ฝากหรือถอนผิดกฏเกณฑ์ที่ควรจะเป็น) ก็จะไม่เปลี่ยนแปลงอะไร และไม่คืนผลอะไรเลย

class BankAccount: def __init__ (self, acc_no, acc_name, balance): self.acc_no = acc_no self.acc_name = acc_name self.balance = balance self.minimum = 0 def set_minimum(self, minimum): self.minimum = minimum class BankAccount: def __init__ (self, acc_no, acc_name, balance): self.acc_no = acc_no self.acc_name = acc_name self.balance = balance self.minimum = 0 def set_minimum(self, minimum): self.minimum = minimum def deposit(self, amount): if amount > 0: self.balance += amount def withdraw(self, amount): if 0 < amount <= self.balance - self.minimum: self.balance -= amount import types obj = types.SimpleNamespace q = "`" clsname = "BankAccount" qclsname = q+clsname+q m_deposit = "deposit" qm_deposit = q + m_deposit + q m_withdraw = "withdraw" qm_withdraw = q + m_withdraw + q bacc1 = obj(acc_no='01', acc_name='A', balance=1000, minimum=400) bacc2 = obj(acc_no='01', acc_name='A', balance=1000, minimum=400) def check_id_name_min(stu, sol): return (stu.acc_no, stu.acc_name, stu.minimum) == \ (sol.acc_no, sol.acc_name, sol.minimum) msg1 = ": ต้องไม่เปลี่ยนเลข ชื่อ หรือยอดขั้นต้ำ" Ex().check_class_def(clsname, missing_msg="ไม่พบคลาส " + qclsname).\ check_body().multi( check_function_def(m_deposit, missing_msg="ไม่พบเมท็อด " + qm_deposit).multi( has_equal_part_len('args', qm_deposit + " รับพารามิเตอร์สองตัว"), check_args('self', missing_msg = "ช่วยเขียนพารามิเตอร์ตัวแรกของ "+ qm_deposit + " ให้เป็น `self`"), check_body().multi( set_context(bacc1, -300).multi( has_equal_value(name = 'self.balance', incorrect_msg = qm_deposit + ": ไม่ให้ฝาก ถ้าจำนวนเงินเป็นลบ"), has_equal_value(name = "self", func=check_id_name_min, incorrect_msg = qm_deposit + msg1) ), set_context(bacc1, 300).multi( has_equal_value(name = 'self.balance', incorrect_msg = qm_deposit + ": ปรับค่า balance ไม่ถูกต้อง"), has_equal_value(name = "self", func=check_id_name_min, incorrect_msg = qm_deposit + msg1) ) ) ), check_function_def(m_withdraw, missing_msg="ไม่พบเมท็อด " + qm_withdraw).multi( has_equal_part_len('args', qm_withdraw + " รับพารามิเตอร์สองตัว"), check_args('self', missing_msg = "ช่วยเขียนพารามิเตอร์ตัวแรกของ "+ qm_withdraw + " ให้เป็น `self`"), check_body().multi( set_context(bacc2, -100).multi( has_equal_value(name = 'self.balance', incorrect_msg = qm_withdraw + ": ไม่ให้ถอน ถ้าจำนวนเงินเป็นลบ"), has_equal_value(name = "self", func=check_id_name_min, incorrect_msg = qm_withdraw + msg1) ), set_context(bacc2, 601).multi( has_equal_value(name = 'self.balance', incorrect_msg = qm_withdraw + ": ไม่ให้ถอน ถ้าถอนแล้วยอดต้ำกว่าขั้นต่ำ"), has_equal_value(name = "self", func=check_id_name_min, incorrect_msg = qm_withdraw + msg1) ), set_context(bacc2, 600).multi( has_equal_value(name = 'self.balance', incorrect_msg = qm_withdraw + ": ปรับค่า balance ไม่ถูกต้อง"), has_equal_value(name = "self", func=check_id_name_min, incorrect_msg = qm_withdraw + msg1) ) ) ) )
แบบฝึกหัด 12-4 ข้อที่ 4

code ข้างล่างนี้มีคลาส Rational เพื่อผลิตจำนวนตรรกยะ คือ จำนวนที่เขียนในรูปของ เศษ/ส่วน โดยที่เศษ (numerator) และส่วน (denominator) เป็นจำนวนเต็ม ภายในมีเมท็อด __init__ และ add ให้แล้ว โดยถ้า a และ b เป็น Rational คำสั่ง a.add(b) จะคืนอ็อบเจกต์ที่เป็นผลบวกของ a กับ b
จงเขียนเมท็อด neg ที่คืนอ็อบเจกต์ที่มีค่าติดลบของอ็อบเจกต์ที่ได้รับ และเมท็อด sub ที่คืนอ็อบเจกต์ที่เป็นผลลบของอ็อบเจกต์ที่ได้รับ การเขียนคำสั่งในเมท็อด sub ให้เรียกใช้ neg กับ add ให้เป็นประโยชน์

___inp___ = ["7 9 -1 9"] def input(): t = ___inp___.pop(0) ___inp___.append(t) return t class Rational: def __init__(self, n, d): a, b = n, d # หา หรม. ก่อนเพื่อไปหารเศษกับส่วน # ถ้ารับ 20/40 จะได้เก็บ 1/2 while b != 0: a,b = b,a%b self.n = n//a # numerator เศษ self.d = d//a # denominator ส่วน def add(self, x): d = self.d * x.d n = self.n * x.d + x.n * self.d return Rational(n, d) def neg(self): def sub(self, x): #-------------------------- # ไม่ต้องแก้ไขคำสั่งใด ๆ ข้างล่างนี้ n1, d1, n2, d2 = [int(e) for e in input().split()] r1 = Rational(n1, d1) r2 = r1.neg() r3 = Rational(n2, d2) r4 = r3.neg() r5 = r1.sub(r4) class Rational: def __init__(self, n, d): a, b = n, d while b != 0: a,b = b,a%b self.n = n//a # numerator เศษ self.d = d//a # denominator ส่วน def add(self, x): d = self.d * x.d n = self.n * x.d + x.n * self.d return Rational(n, d) def neg(self): return Rational(-self.n, self.d) def sub(self, x): return self.add(x.neg()) n1, d1, n2, d2 = [int(e) for e in input().split()] r1 = Rational(n1, d1) r2 = r1.neg() r3 = Rational(n2, d2) r4 = r3.neg() r5 = r1.sub(r4) def check_nd(stu, sol): return round(stu.n/stu.d, 10) == round(sol.n/sol.d, 10) vars = ["r1", "r2", "r3", "r4", "r5"] msgs = ["ต้องไม่เปลี่ยนแปลง", "ไม่ถูกต้อง", "ต้องไม่เปลี่ยนแปลง", "ไม่ถูกต้อง", "ไม่ถูกต้อง"] for v,msg in zip(vars, msgs): Ex().check_object(v, missing_msg = "ไม่มีตัวแปร " + v). \ has_equal_value(func=check_nd, incorrect_msg = "ค่าของ "+ v + " " + msg) q = "`" clsname = "Rational"; qclsname = q+clsname+q mname_sub = "sub"; mname_neg = q+clsname+q Ex().check_class_def(clsname, missing_msg="ไม่พบคลาส " + qclsname).check_body().\ check_function_def(mname_sub, missing_msg="ไม่พบเมท็อด " + mname_sub).check_body().\ has_code(r"^[^#|\"]+\.\s*add\s*\(", not_typed_msg="โจทย์ให้เมท็อด sub ใช้เมท็อด add")