Unit 31. 함수 재귀호출
함수 안에서 함수 자기자신을 호출하는 방식을
재귀호출(recursive call)이라고 한다.
def fib(a):
if a <= 1:
return a
else:
return fib(a-1) + fib(a-2)
n = int(input())
print(fib(n))
피보나치를 구하는 방법은 1보다 작거나 같을때는 그냥 반환하고,
맨 상위의 값을 -1로 쪼갠값과 -2로 쪼갠값을 반환해서
계속해서 밑으로 쪼개가며 더하게 된다.
Unit 32. 람다 표현식
람다 표현식은 식 형태로 되어있어서 람다 표현식이라고 한다.
lambda 매개변수들: 식 같이 사용하면 된다.
<function <lambda> at 0x~~> 처럼 함수 객체가 나오는데 람다 표현식은
이름 없는 함수 즉, 익명 함수를 만들게 된다.
그래서 람다 표현식을 사용할 때에는
plus_ten = lamdba x: x+10 처럼 변수에 할당하면 된다.
변수에 할당하지 않고 바로 호출하기 위해서는
(lambda 매개변수들: 식) (인수들) 처럼 사용하면 되고,
람다 표현식 안에서는 변수를 만들 수 없다는 점을 참고하면 된다.
그리고 조건부 표현식을 사용할 때에는
lambda 매개변수들: 식1 if 조건식 else 식2 처럼 사용해줄 수 있다.
filter 함수는 반복 가능한 객체에서 특정 조건에 맞는 요소를 가져오게 된다.
reduce 함수는 반복 가능한 객체에서 요소를 이전 결과와 누적해서 반환한다.
(from functools import reduce 로 호출)
files = input().split()
print(list(map(lambda a: '{0:03d}.{1}'.format(int(a.split('.')[0]), a.split('.')[1]), files)))
.을 기준으로 나는 인덱스 0번 값을 총 3자리의 인수 포매팅 자리에 넣어주고,
인덱스 1번 값을 확장자명 자리에 넣어준다음 files에서 받은 만큼을 map으로 돌린
각 요소를 list에 집어넣고 list 형태로 출력한다.
Unit 33. 클로저 사용
스크립트 전체에 접근할 수 있는 변수를 전역 변수라고 하고,
전역 변수에 접근할 수 있는 범위를 전역 범위라고 한다.
함수 안에서 전역 변수의 값을 변경하려면 global 키워드를 사용하게 된다.
함수 안에서 함수를 사용할 수 있는데,
지역 변수 범위내에서 사용 가능하다.
이러한 범위 내에서 바깥쪽에 있는 지역 변수를 찾을 때
가장 가까운 함수부터 찾는 함수 nonlocal도 존재한다.
함수를 둘러싼 범위 내를 유지하다가,
함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저라고 한다.
클로저에 반환되는 값에는 람다식 등을 사용할 수 있다.
def countdown(n):
a = n+1
def count():
nonlocal a
a -= 1
return a
return count
n = int(input())
c = countdown(n)
for i in range(n):
print(c(), end=' ')
Unit 34. 클래스 사용
여러가지 데이터를 클래스에 묶어서 사용할 수 있는데,
클래스의 속성과 메서드로 나누어 구분할 수 있다.
해당 내용은 class 클래스이름: def 메서드(self): 코드 처럼 작성할 수 있다.
메서드의 첫 번째 매개변수는 반드시 self로 지정해줘야 하고,
해당 내용은 규칙처럼 생각하면 된다.
인스턴스 = 클래스로 사용가능하고 인스턴스.메서드()로 메서드 호출이 가능하다.
(특정 클래스의 인스턴스인지 확인하는 것은 isinstance(인스턴스, 클래스)로 가능하다.)
클래스에 속성을 만들 때는 __init__ 메서드 안에서
self.속성 = 값으로 할당이 가능하다. 이러한 __init__ 메서드는
인스턴스를 만들 때 호출되는 메서드로 이름 그대로 인스턴스(객체)를 초기화한다.
self는 왜 붙히는걸까 생각할 수 있는데, self는 인스턴스 자기 자신을 의미한다.
외부에서 호출한 함수가 self에 들어가고 자기 자신을 호출하여 결과를 출력한다.
또한, 속성은 비공개 속성으로도 만들 수 있는데 변수 앞에 __를 붙여서 만들 수 있다.
클래스 바깥에서 해당 비공개 속성에 접근하게 되면 에러가 발생한다.
class Annie:
def __init__(self, health, mana, ability_power):
self.health = health
self.mana = mana
self.ability_power = ability_power
def tibbers(self):
return print("티버: 피해량 {0}".format(self.ability_power * 0.65 + 400))
health, mana, ability_power = map(float, input().split())
x = Annie(health=health, mana=mana, ability_power=ability_power)
x.tibbers()
Unit 35. 클래스 속성과 정적, 클래스 메서드
클래스 속성을 사용하는 것은 class 클래스이름: 속성=값 처럼 사용하면된다.
비공개 클래스 속성은 __속성 = 값 처럼 사용하면 된다.
정적 메서드는 @staticmethod를 붙이면 된다.
정적 메서드는 매개변수에 self를 지정하지 않는다.
클래스.메서드로 호출하게 되면 클래스에서 바로 메서드를 호출할 수 있다.
정적 메서드와는 비슷하면서도 약간의 차이점이 있는 클래스 메서드를 사용할때는
class 클래스이름: @classmethod def 메서드(cls, 매개변수1, 매개변수2) 처럼
지정해야 한다. 첫 번째 매개변수에 cls를 지정해야한다.
class Time:
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod
def is_time_valid(time_string):
hour, minute, second = map(int, time_string.split(':'))
return 0 <= hour <= 24 and 0 <= minute <= 59 and 0 <= second <= 60
@classmethod
def from_string(cls, time_string):
hour, minute, second = map(int, time_string.split(':'))
time = cls(hour, minute, second)
return time
time_string = input()
if Time.is_time_valid(time_string):
t = Time.from_string(time_string)
print(t.hour, t.minute, t.second)
else:
print('잘못된 시간 형식입니다.')
위에서 살펴본 정적메소드와 클래스메소드를 사용하여 함수를 만들어준다.
is_time_valid 함수는 받은 인자를 각 시분초의 변수에 int로 :을 기준으로 나누어 저장한다.
그리고 조건을 넘지 않는지 확인해서 True, False를 반환해준다.
form_string 함수는 클래스메소드로 cls 인자를 먼저 받고, 입력된 time_string을
똑같이 :을 기준으로 분리하여 저장해준 뒤, t.hour 처럼 변수에 저장될 수 있도록
각각의 값을 cls로 묶어 반환 시켜준다.
클래스 메소드는 cls를 이용하여 할당된 값들을 클래스의 인스턴스로 만들수 있다.
Unit 36. 클래스 상속
클래스 상속은 물려받은 기능을 유지한 채 다른 기능을 추가할 때 사용한다.
기능을 물려주는 클래스를 기반 클래스, 상속받아 새롭게 만드는 클래스를
파생 클래스라고 한다. 보통 기반 클래스는 부모 클래스 혹은 슈퍼 클래스라 칭하며,
파생 클래스는 자식 클래스 혹은 서브 클래스라고 부른다.
기반 클래스는 똑같이 클래스로 호출하면 되고,
파생 클래스는 class 파생클래스이름(기반클래스이름) 처럼 사용하면 된다.
기반 클래스의 속성을 사용하기 위해 super 함수로 기반 클래스를
파생 클래스에서 초기화한다. super().__init__() 처럼 사용할 수 있다.
만약 파생 클래스에서 해당 메서드를 생략하면 기반 클래스의 __init__이 자동으로
호출되므로 super를 사용하지 않고 간단히 pass만 적어도 된다.
기반 클래스의 메서드를 새로 정의하는 메서드 오버라이딩이 존재하는데,
보통 프로그램에서 어떤 기능이 같은 메서드 이름으로 사용해야할 때 활용한다.
이때는 super()로 기반 클래스의 메서드를 호출하여 중복을 줄일 수 있다.
다중 클래스는 클래스1과 클래스2가 있을때,
파생클래스(클래스1, 클래스2) 처럼 사용할 수 있다.
이러한 다중 상속에 메서드 탐색 순서를 확인할 수 있는데,
클래스.mro()를 사용하면 메서드 탐색 순서를 확인해볼 수 있다.
추상클래스는 메서드의 목록만 가진 클래스로 상속받는 클래스에서
메서드 구현을 강제하기 위해 사용한다고 한다.
import로 abc 모듈을 가져오고 @abstractmethod를 붙여서 추상 메서드로 지정한다.
또한, 추상 클래스는 인스턴스로 만들수가 없어서 빈 메서드로 만들게 된다.
결국 추상 클래스는 인스턴스를 만들지 않기에 오로지 상속에만 사용하고,
파생 클래스에서 반드시 구현해야 할 메서드를 정해 줄 때 사용한다.
class Animal:
def eat(self):
print('먹다')
class Wing:
def flap(self):
print('파닥거리다')
class Bird(Animal, Wing):
def fly(self):
print('날다')
b = Bird()
b.eat()
b.flap()
b.fly()
print(issubclass(Bird, Animal))
print(issubclass(Bird, Wing))
Unit 37. 두 점 사이의 거리
파이썬에서 제곱근은 math.sqrt(값)으로 구할 수 있다.
또한, math.pow(값, 지수)로 거듭제곱 모듈을 사용할 수 있다.
참고로 namedtuple을 collections 모듈로 사용할 수 있는데,
해당 튜플은 자료형 이름과 요소의 이름을 지정하면 클래스를 생성해준다.
import math
class Point2D:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
length = 0.0
p = [Point2D(), Point2D(), Point2D(), Point2D()]
p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y = map(int, input().split())
for i in range(3):
length += math.sqrt(math.pow((p[i+1].x-p[i].x), 2)+math.pow((p[i+1].y-p[i].y), 2))
print(length)
문제에서 주어진 내용은 좌표가 4개라서 range가 3까지 반복했는데,
다음에는 받는 길이만큼을 반복하는 것이 좋을 것 같다.
Unit 38. 예외 처리
코드 실행 중 발생한 에러는 try except 구문으로 처리할 수 있다.
try: 실행할 코드 except: 예외가 발생했을 때 처리하는 코드처럼 사용한다.
또는, try: 실행할 코드 except 예외이름: 예외가 발생했을 때 처리하는 코드처럼
사용하게 되면 특정 예외에 대한 처리가 가능하다.
예외의 에러 메시지를 받고 싶다면,
try: 실행할 코드 except 예외 as 변수: 예외가 발생했을 때 처리하는 코드처럼
사용하여 메시지를 받을 수 있고, 보통 예외의 e를 따서 변수 이름을 e로 짓는다.
(예외 계층도 참고: https://docs.python.org/3/library/exceptions.html#exception-hierarchy)
예외가 발생하지 않았을 때 코드를 실행하는 else를 작성하여 진행할 수도 있다.
예외와는 상관없이 항상 코드를 실행하는 구문은 finally를 작성하여 진행한다.
직접 예외를 발생시킬 때는 raise에 예외를 지정하고 에러 메시지를 넣는다.
사용자가 직접 예외를 만들수도 있는데, class 예외이름(Exception): 을
작성해주어 상속받아서 새로운 클래스로 만든다.
또한, __init(self)__ 메서드에서 super().__init__() 호출하여 에러메시지를 넣는다.
class NotPalindromeError(Exception):
def __init__(self):
super().__init__('회문이 아닙니다.')
def palindrome(word):
if word != word[::-1]:
raise NotPalindromeError
print(word)
try:
word = input()
palindrome(word)
except NotPalindromeError as e:
print(e)
Unit 39. 이터레이터
이터레이터는 값을 차례대로 꺼낼 수 있는 객체이다.
연속된 숫자를 미리 만들면 숫자가 매우 많을 때 메모리 사용량이 늘어나고,
성능에도 좋지 않아서 이터레이터만 생성하고 값이 필요한 시점에
값을 만드는 방식을 사용한다. 이러한 데이터 생성 시점을 뒤로 미루는
지연 평가를 사용하고 이터레이터를 반복자라고도 부른다.
객체가 반복 가능한 객체인지는 객체에 __iter__ 메서드가 있는지
확인하면 되는데 dir함수를 사용하여 객체의 메서드를 확인할 수 있다.
반복 가능한 객체는 __iter__ 메서드로 이터레이터를 얻고,
이터레이터의 __next__ 메서드로 반복한다.
직접 이터레이터를 만들기 위해서는 위에 나온 내용과 같이
class 이터레이터이름: def __iter__(self): 코드 def __next__(self): 코드처럼
작성해주면 된다. 참고로 이터레이터는 언패킹이 가능하고,
자주 사용하는 map도 이터레이터이다.
인덱스로 접근하는 이터레이터는 class 이터레이터이름: def __getitem__(self, 인덱스): 코드
와 같이 작성해준다. iter와 next는 파이썬 내장 함수로 사용가능하다.
class TimeIterator:
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __getitem__(self, index):
if index < self.stop - self.start:
hour = (self.start + index) // 60 // 60
minute = (self.start + index) // 60
second = self.start + index
hour %= 24
minute %= 60
second %= 60
return '{0:02d}:{1:02d}:{2:02d}'.format(hour, minute, second)
else:
raise IndexError
start, stop, index = map(int, input().split())
for i in TimeIterator(start, stop):
print(i)
print('\n', TimeIterator(start, stop)[index], sep='')
연산자의 우선 순위에 주의하면서 괄호를 넣어준
Unit 40. 제너레이터
제너레이터는 이터레이터를 생성해주는 함수이다.
함수 안에서 yield를 사용하면 함수는 제너레이터가 되고,
yield에는 값(변수)을 지정할 수 있다.
yield는 생산하다라는 뜻과 함께 양보하다라는 뜻이 있는데,
yield를 사용하면 값을 함수 바깥으로 전달하면서 코드 실행을
함수 바깥에 양보하게 되어 현재 함수를 잠시 중단하고,
함수 바깥의 코드가 실행되도록 만든다.
yield는 반복문을 사용하지 않고 yield from을 사용하면 된다.
def prime_number_generator(start, stop):
for i in range(start, stop):
isPrime = True
for j in range(2, i-1):
if i % j == 0:
isPrime = False
if isPrime == True:
yield i
start, stop = map(int, input().split())
g = prime_number_generator(start, stop)
print(type(g))
for i in g:
print(i, end=' ')
2, 3, 5, 7 ··· 소수의 배수를 제외한 나머지 값에 대하여
2부터 판별할 값의 -1까지 차례대로 나누어 떨어지지 않는 값을 확인한다.
yield로 함수 바깥에 소수를 전달하여 출력한다.
화이팅!
'Study > python' 카테고리의 다른 글
[Python] 코딩도장 공부 (Unit 41~44) (0) | 2022.09.30 |
---|---|
[Python] 코딩도장 공부 (Unit 21~30) (0) | 2022.09.28 |
[Python] 코딩도장 공부 (Unit 11~20) (0) | 2022.09.27 |
[Python] 코딩도장 공부 (Unit 1~10) (0) | 2022.09.26 |