Загружаем каталог…
Загружаем каталог…
Python_Day.5 클래스 상속과 super() , 오버라이딩, 자주 쓰는 내장 함수, 표준 모듈( time , random , pickle ), 모듈 직접 만들기. Day.4에서 클래스의 기본 틀( __init__ , self , 인스턴스 메소드)을 배웠다. 오늘은 그 위에 상속 을 얹고, 파이썬이 기본으로 제공하는 내장 함수와 모듈 , 그리고 내가 만든 파일을 모듈로 가져다 쓰는 방법 까지 정리했다. 1. 클래스 복습 class Car: def __init__(self, make, model, year): # 객체를 만들 때 자동으로 호출되는 생성자 self.make = make self.model = model self.year = year self.speed = 0 # 속성을 선언하면서 초기화 # 인스턴스 메소드는 첫 번째 매개변수가 항상 self def name(self): return str(self.year) + " " + self.make + " " + self.model def speed1(self): print(str(self.speed) + '이다') c1 = Car('테슬라', 'models', 2018) # 객체명 = 클래스명(__init__의 매개변수) print(c1.name()) # 2018 테슬라 models c1.speed = 15 c1.speed1() # 15이다 c1.name() 처럼 인스턴스를 통해 호출하면 파이썬이 c1 을 자동으로 self 에 넣어 준다. 그래서 호출할 때는 인자를 안 넘기는데 정의에는 self 가 있는 것이다. self 는 이름일 뿐이다 class Fruit: price = 20000 # 클래스 변수 def __init__(a, title, color): # self 대신 a를 써도 동작한다 a.title = title a.color = color def info(a): return "{} 과일은 {}색".format(a.title, a.color) def buy1(a, buy1): # buy1은 매개변수로 바로 쓰는 값이라 a.buy1처럼 속성에 붙일 필요가 없다 return '{} 과일 {}에서 사야지~'.format(a.title, buy1) a = Fruit('사과', '빨간') b = Fruit('포도', '검은') print(a.info()) # 사과 과일은 빨간색 print(b.info()) # 포도 과일은 검은색 print(a.buy1('코스트코')) # 사과 과일 코스트코에서 사야지~ print(b.buy1('이마트')) # 포도 과일 이마트에서 사야지~ 첫 번째 매개변수 이름이 꼭 self 일 필요는 없다. 위치 가 중요하고, 관례상 self 를 쓴다. 메소드 안에서만 쓰고 끝나는 값은 self. 를 붙여 속성으로 만들 필요 없이 매개변수 그대로 쓰면 된다. 파이썬의 모든 클래스는 최상위 클래스인 object 를 상속받는다. self가 없는 메소드 class A: def add(a, b): print(a + b) A.add(3, 4) # 7 (클래스 이름으로 호출) A().add(3, 4) # TypeError: A.add() takes 2 positional arguments but 3 were given A.add(3, 4) 는 일반 함수처럼 동작해서 7이 나온다. 반면 인스턴스로 호출하면 A() 가 첫 번째 인자( a )로 자동 전달되어, 인자가 3개가 되어 버리기 때문에 에러가 난다. 필기에는 이 형태를 "클래스 메소드(정적 메소드)"로 적어 두었는데, 정확하게는 아니다. 정적 메소드는 @staticmethod 를 붙여서 만드는 것 이고, 그러면 인스턴스로 호출해도 에러가 나지 않는다. 위처럼 데코레이터 없이 self 만 뺀 메소드는 "클래스 이름으로 부를 때만 우연히 동작하는" 형태다. class B: @staticmethod def add(a, b): print(a + b) B.add(3, 4) # 7 B().add(3, 4) # 7 (인스턴스로 호출해도 된다) 2. 클래스 안에 클래스 (객체를 속성으로 쓰기) 학생 객체를 만들고, 계산기 클래스가 학생들을 리스트로 갖고 있다가 평균을 구하는 예제다. class Student: def __init__(self, name, id, score=0): # 매개변수의 초기값(기본값) 설정 self.name = name self.id = id self.score = score def getId(self): return self.id def getName(self): return self.name def setScore(self, score): self.score = score def getScore(self): return self.score class Cal: def __init__(self): self.stu = [] # 학생 객체를 담을 리스트 def add(self, student): self.stu.append(student) def avg(self): total = 0 for i in self.stu: total += i.score # i.getScore()로 써도 같다 average = total / len(self.stu) return average, len(self.stu) # 값 두 개를 튜플로 반환 a = Student('Tom', 'qwe12') # score는 기본값 0 a.setScore(70) a2 = Student('Amy', 'NTE', 60) a3 = Student('Bob', 'B01', 90) a4 = Student('Cat', 'C01', 10) c = Cal() c.add(a) c.add(a2) c.add(a3) c.add(a4) p, s = c.avg() # 반환된 두 값을 각각 p, s에 받는다 print('{1}명의 평균은 {0}'.format(p, s)) # 4명의 평균은 57.5 score=0 처럼 기본값이 있는 매개변수 는 생략할 수 있다. a 는 점수를 안 넘겨서 0으로 만들어졌고, 나중에 setScore(70) 으로 바꿨다. return average, len(self.stu) 는 값을 두 개 돌려주는 것처럼 보이지만 사실 튜플 하나 를 반환한다. 받는 쪽에서 p, s = ... 로 언패킹했다. (Day.2의 패킹/언패킹) Cal 은 내부에 Student 객체들을 갖고 있다. 이렇게 객체를 다른 객체의 속성으로 담는 구조 는 이후에도 자주 나온다. 함수 안에서 sum 을 변수 이름으로 쓰면 내장 함수 sum() 을 가려 버린다. 위 코드에서는 total 로 바꿨다. 3. 상속 상속 은 부모 클래스의 속성과 메소드를 자식 클래스가 그대로 물려받는 것이다. class 자식클래스(부모클래스): ... 3-1. super() 로 부모의 __init__ 호출하기 class Person: def __init__(self): print('안녕') class Student(Person): def __init__(self): print('학생은 공부를 해야지') super().__init__() # 부모(Person)의 __init__을 호출 a = Student() # 학생은 공부를 해야지 # 안녕 자식 클래스에서 __init__ 을 다시 정의하면, 부모의 __init__ 은 자동으로 호출되지 않는다. 부모의 초기화가 필요하면 super().__init__() 으로 직접 불러야 한다. 필기에는 "덮어쓰기 되는 식"이라고 적어 뒀는데, 이게 맞는 이해다. 호출하지 않으면 어떻게 되는지 확인해 보자. class P2: def __init__(self): self.x = 1 class S2(P2): def __init__(self): # super().__init__()을 빼먹음 self.y = 2 s = S2() print(s.y) # 2 print(s.x) # AttributeError: 'S2' object has no attribute 'x' 부모의 __init__ 이 실행되지 않았으니 x 라는 속성이 만들어지지 않았다. 3-2. 부모의 __init__ 에 값 넘기기 class Camping(Car): # 위에서 만든 Car 상속 def __init__(self, make, model, year, bed): super().__init__(make, model, year) # 공통 속성은 부모에게 맡김 self.bed = bed # 자식만의 속성 추가 camp1 = Camping('벤츠', '스프린터', 2024, 2) print(camp1.name()) # 2024 벤츠 스프린터 (부모의 메소드를 그대로 사용) camp1.speed1() # 0이다 (speed도 부모가 초기화해 줬다) print(camp1.bed) # 2 c1 = Car('현대', '아반떼', 1998) print(c1.name()) # 1998 현대 아반떼 c1.speed = 60 c1.speed1() # 60이다 Camping 은 name() 과 speed1() 을 새로 만들지 않았는데도 쓸 수 있다. 부모에게 있는 것은 물려받고, 자식에만 필요한 bed 만 추가 한 것이다. 코드 중복이 줄어드는 게 상속의 장점이다. 3-3. 오버라이딩 (메소드 재정의) 부모에 있는 메소드를 자식이 같은 이름으로 다시 정의 하는 것을 오버라이딩이라고 한다. class Super: def a(self): print('super') class Sub(Super): def a(self): # 오버라이딩: 부모의 a()를 재정의 print('자식 클래스') def b(self): # 자식에만 있는 메소드 print('sub') a = Super() b = Sub() a.a() # super b.a() # 자식 클래스 (자식 버전이 우선) b.b() # sub a.b() # AttributeError: 'Super' object has no attribute 'b' 같은 이름의 메소드가 있으면 자식 쪽이 우선 한다. 상속은 한 방향이다. 자식은 부모의 것을 쓸 수 있지만, 부모는 자식에만 있는 메소드를 쓸 수 없다. 3-4. 오버라이딩 + super() 로 부모 기능 재활용 class Cal: def __init__(self, num1, num2): self.num1 = num1 self.num2 = num2 def div(self): return self.num1 / self.num2 class NewCal(Cal): def div(self): if self.num2 == 0: return 0 # 0으로 나누는 경우만 새로 처리 else: return super().div() # 나머지는 부모의 div()를 그대로 사용 a = NewCal(6, 0) b = NewCal(6, 3) print(a.div(), b.div()) # 0 2.0 else 에서 부모의 계산식을 다시 쓰지 않고 super().div() 로 가져왔다. 부모 기능은 그대로 쓰고, 예외 상황만 자식에서 덧붙이는 방식이다. 필기 코드의 부모 div() 는 num1 + num2 를 반환하고 있었다. 이름이 div 니까 나누기( / )로 고쳤다. 나누기로 고쳐야 num2 == 0 을 따로 막는 이유( ZeroDivisionError )도 설명이 된다. 4. 클래스 문제 풀이 Q1. 클래스를 상속받고 메소드 추가하기 Calculator 를 상속하는 UpgradeCal 을 만들고, 값을 빼는 minus 메소드를 추가한다. class Calculator: def __init__(self): self.value = 0 def add(self, val): self.value += val class UpgradeCal(Calculator): def minus(self, val): self.value -= val cal = UpgradeCal() cal.add(10) cal.minus(7) print(cal.value) # 3 Q2. 값이 100을 넘지 않는 계산기 Calculator 를 상속해서, add 로 값을 더할 때 100이 넘으면 100으로 고정 하는 MaxLimitCal 을 만든다. 필기에서는 이 문제를 풀다가 add 의 첫 매개변수를 self 가 아닌 n 이나 val 로 쓰고, 메소드 안에서 value = 0 처럼 지역 변수를 만들어 버려서 결과가 이상했다. 포인트는 두 가지다. 첫 매개변수가 꼭 self 여야 하는 것은 아니지만, 인스턴스가 들어오는 자리 이므로 인스턴스 속성에 접근하려면 그 이름으로 n.value 처럼 써야 한다. 매개변수 없이 def add(val): 만 쓰면 인스턴스가 들어올 자리가 없다. 이 상태에서 value = 0 을 쓰면 인스턴스 속성이 아니라 함수 안에서만 쓰이는 지역 변수 가 된다. 그래서 self.value 를 쓰는 형태로 고치면 이렇게 된다. class MaxLimitCal(Calculator): def add(self, val): super().add(val) # 부모의 add로 먼저 더하고 if self.value >= 100: # 100 이상이면 self.value = 100 # 100으로 고정 m = MaxLimitCal() m.add(50) m.add(70) print(m.value) # 100 Q6. 리스트 항목마다 3을 곱해서 반환하기 a = [1, 2, 3, 4] print(list(map(lambda x: x * 3, a))) # [3, 6, 9, 12] 5. 내장 함수 Day.4에 이어 자주 쓰는 내장 함수를 정리했다. print(abs(-3)) # 3 (절댓값) all , any iterable의 요소를 검사해서 참/거짓을 돌려준다. print(all([1, 2, 3])) # True 모두 참 print(all([1, 2, 0])) # False 0이 하나 있으니까 print(any([1, 2, 0])) # True 하나라도 참이면 print(any([0, 0])) # False 전부 거짓일 때만 함수 True가 되는 조건 all 모든 요소가 참 any 하나라도 참 조건식과 조합하면 더 유용하다. a = [1, 60, 4, 10, 50] print(all(i < 20 for i in a)) # False (60, 50이 20 이상) print(any(i > 30 for i in a)) # True (60, 50이 30 초과) 필기에는 any([1,2,0]) 이 True인 이유를 "하나라도 False(1,2)이기 때문"이라고 적어 뒀는데, 정확히는 하나라도 참(1, 2)이 있기 때문 이다. 참고로 빈 리스트는 all([]) 이 True , any([]) 가 False 다. chr , ord print(chr(65)) # A (아스키 코드 → 문자) print(ord('A')) # 65 (문자 → 아스키 코드) enumerate 인덱스와 요소를 함께 돌려준다. for i, name in enumerate(['body', 'foo', 'bar']): print(i, name) # 0 body # 1 foo # 2 bar 필기에서는 {'body','foo','bar'} 라는 set 에 enumerate 를 썼는데, set은 순서가 없어서 매번 출력 순서가 달라질 수 있다. 인덱스가 의미가 있으려면 리스트처럼 순서가 있는 자료형에 쓰는 게 좋다. filter , map a = [1, 60, 4, 10, 50] def num(x): return abs(x) > 3 print(list(filter(num, a))) # [60, 4, 10, 50] print(list(filter(lambda x: x > 3, a))) # [60, 4, 10, 50] print(list(map(lambda x: x + 2, range(1, 7)))) # [3, 4, 5, 6, 7, 8] filter(함수, iterable) : 함수가 참 을 돌려주는 요소만 추출한다. map(함수, iterable) : 모든 요소 에 함수를 적용한 결과를 돌려준다. 반복 가능한 객체는 리스트, 튜플, 문자열, 딕셔너리, range , 파일 객체 등이다. 결과를 보려면 list() 로 감싸야 한다. (Day.4에서 정리한 대로 map / filter 는 지연 평가라서 그대로 출력하면 객체 주소만 나온다.) id , len , type print(id(10)) # 객체의 주소값 (실행 환경마다 다름) print(len('파이썬')) # 3 print(len([1, 2, 3, 4, 5])) # 5 print(type(3)) # <class 'int'> print(type({})) # <class 'dict'> print(type(())) # <class 'tuple'> print(type([])) # <class 'list'> range print(range(5)) # range(0, 5) (리스트가 아니라 range 객체) print(range(1, 10, 2)) # range(1, 10, 2) print(list(range(1, 10, 2))) # [1, 3, 5, 7, 9] (시작, 끝(미포함), 증감) # 9부터 0까지 1씩 감소 print(list(range(9, -1, -1))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] max , min print(max([1, 2, 3])) # 3 print(max('ABCD')) # D (사전순으로 가장 뒤) print(min('ABCD')) # A (사전순으로 가장 앞) print(max(1, 2, 3)) # 3 (리스트 없이 값을 바로 나열해도 된다) round print(round(4.6)) # 5 print(round(3.6432, 2)) # 3.64 (소수점 둘째 자리까지) 주의할 점이 있다. 파이썬의 round 는 우리가 학교에서 배운 사사오입(반올림)이 아니라 가장 가까운 짝수로 보내는 방식 이다. print(round(2.5)) # 2 print(round(3.5)) # 4 print(round(0.5)) # 0 딱 .5인 경우에는 결과가 짝수 쪽으로 가기 때문에, 평균 점수처럼 정확한 반올림이 필요한 곳에서는 헷갈릴 수 있다. sorted , sum , zip print(sorted([5, 4, 3, 2, 1, 6])) # [1, 2, 3, 4, 5, 6] print(sorted([5, 4, 3, 2, 1, 6], reverse=True)) # [6, 5, 4, 3, 2, 1] print(sorted(['p', 'y', 't', 'h', 'o', 'n'])) # ['h', 'n', 'o', 'p', 't', 'y'] print(sum([1, 2, 3, 4, 5])) # 15 print(sum(range(1, 11))) # 55 print(list(zip([10, 20, 30], [40, 50, 60]))) # [(10, 40), (20, 50), (30, 60)] (같은 인덱스끼리 튜플로 묶는다) sorted 는 새 리스트를 반환 하고 원본은 바뀌지 않는다. 필기에서는 list(reversed(sorted(...))) 로 내림차순을 만들었는데, reverse=True 옵션을 쓰면 더 간단하다. zip 은 여러 iterable의 같은 위치 요소를 묶어 주는 함수다. 6. 표준 모듈: time , random , pickle 내장 함수와 달리 import 로 불러와서 쓰는 모듈들이다. time import time print(time.time()) # 1970-01-01부터 지금까지의 초 (실수) print(time.localtime(time.time())) # 연/월/일/시/분/초 등을 담은 구조체 print(time.ctime()) # 사람이 읽는 형태의 현재 시간 문자열 # 가장 많이 쓰는 형식 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) # 예) 2026-09-11 17:30:05 코드 의미 %Y 연도(4자리) %m 월 %d 일 %H 시(24시간) %M 분 %S 초 random import random print(random.random()) # 0.0 이상 1.0 미만의 실수 print(random.randint(1, 45)) # 1 이상 45 이하의 정수 (둘 다 포함) 필기에는 random.random() 이 "1.0까지"라고 되어 있는데, 1.0은 포함하지 않는다. randint(1, 45) 는 두 번째 인자도 포함 이다. 필기에 "미만이 아니라 포함임!"이라고 적어 둔 부분이 이 점이다. d =
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
Python_Day.5. Python_Day.5 클래스 상속과 super() , 오버라이딩, 자주 쓰는 내장 함수, 표준 모듈( time , random , pickle ), 모듈 직접 만들기. Day.4에서 클래스의 기본 틀( __init__ , self , 인스턴스 메소드)을 배웠다. 오늘은 그 위에 상속 을 얹고, 파이썬이 기본으로 제공하는 내장 함수와 모듈 , 그리고 내가 만든 파일을 모듈로 가져다 쓰는 방법 까지 정리했다. 1. 클래스 복습 class Car: def __init__(self, make, model, year): # 객체를 만들 때 자동으로 호출되는 생성자 self.make = make self.model = model self.year = year self.speed = 0 #…
Открыть источник