# # # # # # # # # # #
# # # # # # # # # # # student_name_1 = 'won'
# # # # # # # # # # # student_detail_1 = [
# # # # # # # # # # # {'age': 2},
# # # # # # # # # # # {'major': 'computer'},
# # # # # # # # # # # ]
# # # # # # # # # # #
# # # # # # # # # # # student_name_2 = 'babo'
# # # # # # # # # # # student_detail_1 = [
# # # # # # # # # # # {'age': 3},
# # # # # # # # # # # {'major': 'art'},
# # # # # # # # # # # ]
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # students = ['won', 'babo']
# # # # # # # # # # # student_detail_list = [
# # # # # # # # # # # {'age': 2, 'major': 'computer'},
# # # # # # # # # # # {'age': 3, 'major': 'art'},
# # # # # # # # # # # ]
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # # 클래스
# # # # # # # # # # # # 코드를 짜기 전에 어느정도 설계를 해놓고 짜야 되는 단점
# # # # # # # # # # # # 처음 코드 잘 떄 상대적으로 복잡함. 뭐에 비해서? 절차지향에 비해서
# # # # # # # # # # #
# # # # # # # # # # # """
# # # # # # # # # # # 클래스 선언 3가지 방법
# # # # # # # # # # # """
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # class sample_A(object):
# # # # # # # # # # # pass
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # class sample_B():
# # # # # # # # # # # pass
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # # 부모 클래스인 경우
# # # # # # # # # # # class sample_C:
# # # # # # # # # # # pass
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # # 상속(sample_C)
# # # # # # # # # # # class sample_D(sample_C):
# # # # # # # # # # # pass
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # # 학생 관련 클래스 선언
# # # # # # # # # # # # class Student(object):
# # # # # # # # # # # class Student:
# # # # # # # # # # # # 매직 메소드(스페셜 메소드) 중에 생성자 메소드
# # # # # # # # # # # def __init__(self, name, details):
# # # # # # # # # # # self.name = name
# # # # # # # # # # # self.details = details
# # # # # # # # # # #
# # # # # # # # # # # # def __str__(self):
# # # # # # # # # # # # print('called __str__')
# # # # # # # # # # # # return f'__str__ >>> {self.name} - {self.details}'
# # # # # # # # # # #
# # # # # # # # # # # def __repr__(self):
# # # # # # # # # # # print('called __repr__')
# # # # # # # # # # # return f'__repr__ >>> {self.name} - {self.details}'
# # # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # # # # # student_1 객체 선언
# # # # # # # # # # # student_1 = Student('won', {'age': 4, 'major': 'history'})
# # # # # # # # # # # student_2 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # # # # print(student_1)
# # # # # # # # # # # # <__main__.Student object at 0x10513f250>
# # # # # # # # # # # # print할 때 이쁘게 문자로 출력하고 싶어 어떻게 할 수 있어?
# # # # # # # # # # #
# # # # # # # # # # # # __str__ or __repr__
# # # # # # # # # # # print(student_1)
# # # # # # # # # # #
# # # # # # # # # # # # __dict__, 딕셔너리 형태로 객체의 속성을 보여줌
# # # # # # # # # # # print(f'__dict__ >>> {student_1.__dict__}')
# # # # # # # # # # # print(f'__dict__ >>> {student_2.__dict__}')
# # # # # # # # # # #
# # # # # # # # # # # d1 = student_1.__dict__
# # # # # # # # # # # print(f'dididididi {d1}')
# # # # # # # # # # #
# # # # # # # # # # # # dir() 객체의 네임스페이스 출력
# # # # # # # # # # # print(f'dir() >>>> {dir(student_1)}')
# # # # # # # # # # #
# # # # # # # # # # # # __class__
# # # # # # # # # # # print(student_1.__class__)
# # # # # # # # # # # print(student_2.__class__)
# # # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # class Student(object):
# # # # # # # # # # """
# # # # # # # # # # class name: Student
# # # # # # # # # # name = Student(dklfjdsklfjaklsdjfskldjflksfdjfsdlkdfsjkl)
# # # # # # # # # # date: 2024.04.44
# # # # # # # # # # """
# # # # # # # # # # # 클래스 변수
# # # # # # # # # # # 모든 객체가 동일하게 갖는 변수(값)
# # # # # # # # # # student_count = 0
# # # # # # # # # #
# # # # # # # # # # # 매직 메소드(스페셜 메소드) 중에 생성자 메소드
# # # # # # # # # # # 인스턴스 변수(name, details)
# # # # # # # # # # def __init__(self, name, details):
# # # # # # # # # # """
# # # # # # # # # # :param name: name
# # # # # # # # # # :param details: {sdklfjdslkfjkldsjdsfkldfsj}
# # # # # # # # # # """
# # # # # # # # # # self.name = name
# # # # # # # # # # self.details = details
# # # # # # # # # # Student.student_count += 1
# # # # # # # # # #
# # # # # # # # # # def __del__(self):
# # # # # # # # # # Student.student_count -= 1
# # # # # # # # # #
# # # # # # # # # # # 인스턴스 메소드 무엇을 갖고 있다고? self 갖고 있다고
# # # # # # # # # # def get_detail(self):
# # # # # # # # # # """
# # # # # # # # # #
# # # # # # # # # # :return: name - details
# # # # # # # # # # """
# # # # # # # # # # print(f'details >>> {self.name} - {self.details}')
# # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # student_1 = Student('won', {'age': 4, 'major': 'history'})
# # # # # # # # # # student_2 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # # student_3 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # # student_4 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # # student_4 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # # student_5 = Student('babo', {'age': 3, 'major': 'art'})
# # # # # # # # # #
# # # # # # # # # # # student_1.get_detail()
# # # # # # # # # # # student_2.get_detail()
# # # # # # # # # #
# # # # # # # # # # # 클래스 변수 동일 >>> 증명
# # # # # # # # # # print(student_1.student_count)
# # # # # # # # # # print(student_4.student_count)
# # # # # # # # # # print(student_5.student_count)
# # # # # # # # # #
# # # # # # # # # # # 객체 지움
# # # # # # # # # # """
# # # # # # # # # # 매직 메소드를 정의 안 했을 경우는 기존 파이썬 매직 메소드내용 대로 기능을 사용하는데
# # # # # # # # # # 클래스에서 매직 메소드를 재선언하여 로직을 추가하면 해당 클래스에 매직메소드로 기능 동작
# # # # # # # # # #
# # # # # # # # # # 매직메소드를 내가 다시 재정의했을 때 안 했을 때 차이점을 인지 해야 함
# # # # # # # # # # """
# # # # # # # # # # # 객체 지움
# # # # # # # # # # del student_5
# # # # # # # # # # student_2.__del__()
# # # # # # # # # # # 객체 삭제 확인
# # # # # # # # # # print(student_5)
# # # # # # # # # # # 클라스 변수 유지
# # # # # # # # # # print(f'del >>> {student_4.student_count}')
# # # # # # # # # # # print(dir(student_2))
# # # # # # # # # #
# # # # # # # # # # # doc
# # # # # # # # # # print(Student.__doc__)
# # # # # # # # # # print('__init__ >>> doc')
# # # # # # # # # # print(Student.__init__.__doc__)
# # # # # # # # # # print('get_detail >>> doc')
# # # # # # # # # # print(Student.get_detail.__doc__)
# # # # # # # # # # # ????
# # # # # # # # # # print('????')
# # # # # # # # # # print(student_1.get_detail.__doc__)
# # # # # # # # # # print(dir(student_2))
# # # # # # # # # # print()
# # # # # # # # # # print()
# # # # # # # # # # print()
# # # # # # # # # # print(f'id student_1 >>> {id(student_1)}')
# # # # # # # # # # print(f'id student_2 >>> {id(student_2)}')
# # # # # # # # # # print(f'id student_3 >>> {id(student_3)}')
# # # # # # # # # # print(f'id student_4 >>> {id(student_4)}')
# # # # # # # # # #
# # # # # # # # # # print(f'id student_1 -> Student >>> {id(student_1.__class__)}')
# # # # # # # # # # print(f'id student_2 -> Student >>> {id(student_2.__class__)}')
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # # # 매직 메소드: 파이썬이 개발자 편하게 쓰라고 미리 만들어둔거
# # # # # # # # #
# # # # # # # # # print(dir(int))
# # # # # # # # # print(dir(float))
# # # # # # # # # print('-' * 100)
# # # # # # # # #
# # # # # # # # # x = 44
# # # # # # # # # print(x + 11)
# # # # # # # # # print(x.__add__(11))
# # # # # # # # #
# # # # # # # # # class Calc:
# # # # # # # # # def __init__(self, x):
# # # # # # # # # self.x = x
# # # # # # # # #
# # # # # # # # # def __add__(self, other):
# # # # # # # # # print(f'called __add__')
# # # # # # # # # # return (self.x + other.x) * 1000000
# # # # # # # # # return self.x - other.x
# # # # # # # # #
# # # # # # # # # a = Calc(444)
# # # # # # # # # b = Calc(111)
# # # # # # # # #
# # # # # # # # # print(a+b)
# # # # # # # # #
# # # # # # # # #
# # # # # # # # # class Matrix:
# # # # # # # # # def __init__(self, data):
# # # # # # # # # self.data = data
# # # # # # # # #
# # # # # # # # # def __str__(self):
# # # # # # # # # return '\n'.join(['\t'.join(map(str, row)) for row in self.data])
# # # # # # # # #
# # # # # # # # # def __add__(self, other):
# # # # # # # # # result =[]
# # # # # # # # # for row1, row2 in zip(self.data, other.data):
# # # # # # # # # result.append([x + y for x, y in zip(row1, row2)])
# # # # # # # # # return Matrix(result)
# # # # # # # # #
# # # # # # # # # def __sub__(self, other):
# # # # # # # # # result =[]
# # # # # # # # # for row1, row2 in zip(self.data, other.data):
# # # # # # # # # result.append([x - y for x, y in zip(row1, row2)])
# # # # # # # # # return Matrix(result)
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # # m1 = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# # # # # # # # # m2 = Matrix([[9, 8, 7], [6, 5, 4], [3, 2, 1]])
# # # # # # # # #
# # # # # # # # # print(m1+m2)
# # # # # # # # # print()
# # # # # # # # # print(m2)
# # # # # # # #
# # # # # # # # """
# # # # # # # # OOP 캡슐화
# # # # # # # # 객채의 데이터(속성)와 메소드를 하나의 단위로 묶고, 외부로부터 객체를 세부 로직을 숨기는 것
# # # # # # # # 알약 -> 캡슐
# # # # # # # # 감기 알약에 안에 -> 해열제, 진통제, 등등등
# # # # # # # # 근데 이걸 해열제를 제가 마음대로 빼고, 청산가리 교체를합니다.
# # # # # # # # 이러면 안되겠죠?
# # # # # # # #
# # # # # # # # 캡슐 안에 있는걸 사실 뭐가 뭔지 잘 모른단말이지
# # # # # # # # 은닉화
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # #
# # # # # # # # a = 10
# # # # # # # # name: 퍼블릭(public) 변수 - 어디서든 접근이 가능, 내가 원할 떈 어디서든
# # # # # # # # _name: Protected 변수 - 서브클래스와 클래스 내부에서 접근 권장되며, 외부에서 직접 접근 권장하지 않음
# # # # # # # # __name: Private 변수 - 클래스 내부에서만 접근, 수정 가능
# # # # # # # # """
# # # # # # # #
# # # # # # # # class Private_Var:
# # # # # # # # def __init__(self):
# # # # # # # # self.x = 1
# # # # # # # # self._y = 2
# # # # # # # # self.__z = 3
# # # # # # # #
# # # # # # # # a = Private_Var()
# # # # # # # # print(a.x)
# # # # # # # # print(a._y)
# # # # # # # # # __z 예외 발생
# # # # # # # # # print(a.__z)
# # # # # # # #
# # # # # # # # print(dir(a))
# # # # # # # # print(a.__dict__)
# # # # # # #
# # # # # # #
# # # # # # # # getter, setter 안 쓰고 구현
# # # # # # # class Private_Var_2:
# # # # # # # def __init__(self):
# # # # # # # self.x = 1
# # # # # # # self._y = 2
# # # # # # # self.__z = 3
# # # # # # # self.__a = 0
# # # # # # # self.__b = 0
# # # # # # # self.__c = 0
# # # # # # #
# # # # # # # def get_z(self):
# # # # # # # return self.__z
# # # # # # #
# # # # # # # def set_z(self, value):
# # # # # # # self.__z = value
# # # # # # #
# # # # # # # # 이런식으로하면 너무 가독성 떨어지구요
# # # # # # # # 유지보수 힘들
# # # # # # # # 코드 짜다가 get_ set_ change 기억이 안남
# # # # # # # # 이 코드를 나 혼자가 아닌 팀원분들과 코딩 했을 때 해당 메소드를 알려주어야 함
# # # # # # # def get_a(self):
# # # # # # # return self.__a
# # # # # # #
# # # # # # # def set_b(self, value):
# # # # # # # self.__b = value
# # # # # # #
# # # # # # #
# # # # # # # a = Private_Var_2()
# # # # # # # print(a.x)
# # # # # # # print(a._y)
# # # # # # # # __z 예외 발생
# # # # # # # print(a.get_z)
# # # # # # #
# # # # # # # a.set_z(4444444)
# # # # # # # print(dir(a))
# # # # # #
# # # # # # # @property 사용해서 getter, setter 구현하는 방법
# # # # # # # @oroperty를 사용하면 메소드 사용 가능, 코드가 조금더 가독성이 좋고, 유지보수 좋고, 파이썬 다운 코드를 작성할 수 있음(파이써닉하다)
# # # # # #
# # # # # # class Private_Var_3:
# # # # # # def __init__(self):
# # # # # # self.x = 1
# # # # # # self._y = 2
# # # # # # self.__z = 3
# # # # # # self.__a = 61%%%%%%%
# # # # # #
# # # # # # @property
# # # # # # def z(self):
# # # # # # return self.__z * 10000000 * 62%%%%%
# # # # # #
# # # # # # @z.setter
# # # # # # def z(self, value):
# # # # # # self.__z = value
# # # # # #
# # # # # # a = Private_Var_3
# # # # # # print(a.z)
# # # # # # a.z = 44444444
# # # # # # print(dir(a))
# # # # # # # 위의처럼 a.z 하면 왜 이렇게 어렵게 코딩을해서 바꾸냐?
# # # # # # # 귀찮게시리
# # # # # #
# # # # # # # TODO: 예제 추가, raise 등등
# # # # # #
# # # # # #
# # # # #
# # # # # """
# # # # # 메소드 오버라이딩
# # # # # OOP - 다형성
# # # # #
# # # # # 자식 클라스(서브 클라스) 부모 클라스를 호출도 가능
# # # # # - super()
# # # # # 부모의 메소드 재정의
# # # # # 메소드 추상화
# # # # # 확장도 가능한데 이게 다양하게~ 다형성
# # # # #
# # # # # 가독성, 코드가 유연해짐
# # # # # 메소드 많이 만들 필요가 없어짐
# # # # # 유지보수 좋음
# # # # # """
# # # # #
# # # # # # OOP 상속성
# # # # # class A:
# # # # # def __init__(self):
# # # # # self.value = 4
# # # # #
# # # # # def get_value(self):
# # # # # return self.value
# # # # #
# # # # #
# # # # # class B(A):
# # # # # pass
# # # # #
# # # # # a = A()
# # # # # b = B()
# # # # #
# # # # # print(a.get_value())
# # # # # print(b.get_value())
# # # # # print('-' * 100)
# # # # #
# # # # # print(f'Parent >>> {dir(a)}')
# # # # # print(f'Child >>> {dir(b)}')
# # # # # print('-' * 100)
# # # # #
# # # # # print(f'Parent >>> {a.__dict__}')
# # # # # print(f'Child >>> {b.__dict__}')
# # # # #
# # # # class A_1:
# # # # def __init__(self):
# # # # self.value = 4
# # # #
# # # # def get_value(self):
# # # # return self.value
# # # #
# # # #
# # # # class B_1(A_1):
# # # # def get_value(self):
# # # # return self.value * 1000
# # # #
# # # #
# # # # a = A_1()
# # # # b = B_1()
# # # #
# # # # print(a.get_value())
# # # # print(b.get_value())
# # # # print('-' * 100)
# # # #
# # # # print(f'Parent >>> {dir(a)}')
# # # # print(f'Child >>> {dir(b)}')
# # # # print('-' * 100)
# # # #
# # # # print(f'Parent >>> {a.__dict__}')
# # # # print(f'Child >>> {b.__dict__}')
# # #
# # #
# # # class Animal:
# # # def speak(self):
# # # return 'speak 하하하하하하하'
# # #
# # # class Dog(Animal):
# # # def speak(self):
# # # # super() - 부모클래스의 메소드를 호출(가져옴)
# # # # parent_msg = super(Dog, self).speak()
# # # parent_msg = super().speak()
# # # return f'{parent_msg} - 멍멍멍멍'
# # #
# # #
# # # a = Animal()
# # # d = Dog()
# # #
# # # print(a.speak())
# # # print(d.speak())
# #
# #
# # class Basic:
# # def __int__(self, model, year):
# # self.model = model
# # self.year = year
# #
# #
# # class Car(Basic):
# # def __init__(self, model, year, num_doors):
# # super().__init__(model, year)
# # self.num_doors = num_doors
# #
# #
# # class Truck(Basic):
# # def __int__(self, model, year, horsepower):
# # super().__init__(model, year)
# # self.horsepower = horsepower
# #
# # class Tired(Truck):
# # pass
# #
# # a = Basic()
# # c = Car()
# # t = Truck()
# # tt = Tired()
# #
# #
# # """
# # 레벨 업 하는 게임들???
# # 어느정도 레벨이 올라가면 클라스(기사 마법사) 전직
# #
# # 부모 클래스 인간
# # - 걷기
# # - 싸우기
# # - 뛰기
# #
# # 기사(인간)
# # 걷기 -> 속도 더 빠르게 걷기(메소드 오버라이딩)
# # 싸우기 -> 올려치기 올려치기 칼로 쑤시고
# #
# # 마법사(인간)
# #
# # """
# #
#
# """
# 메소드 오버로딩
# 메소드를 재정의를 하는데 오버라이딩하고 달라
# 동일한 메소드를 가지고 유연하게 처리 "파라미터" 기반
# 유지보수, 코드가 가독성이 뛰어집니다.
#
# """
#
# class Babo_Calc:
# def add(self, x, y, z):
# return x + y + z
#
# def add(self, x, y):
# return x + y
#
# # a = Babo_Calc()
#
# # print(a.add(1, 2))
# # print(a.add(1, 2, 3))
#
#
# class Babo_Calc_1:
# def add(self, *args):
# return sum(args)
#
# a = Babo_Calc_1()
#
# print(a.add(1, 2))
# print(a.add(1, 2, 3))
#
# class Babo_Calc_1:
# def add(self, datatype, *args):
# if datatype == 'int':
# return sum(args)
# elif datatype == 'str':
# return ''.join(args)
# else:
# raise ValueError('babo')
#
# b = Babo_Calc_1()
# print(b.add('int', 3, 4, 5, 6))
# print(b.add('str', 'a', 'b'))
#
#
# print(b.add('int', 5, 6, 7, 8))
from multipledispatch import dispatch
class Babooooooo:
@dispatch(int, int)
def add(self, x, y):
return x + y
@dispatch(int, int, int)
def add(self, x, y, z):
return x + y + z
@dispatch(str, int)
def add(self, s, i):
return s * i
a = Babooooooo
print(a.add(1, 2))
print(a.add(1, 2, 3))
print(a.add('ab', 3))