재귀함수 사용 O

def fibonacci(n, a=0, b=1, fib_list=[]):

    if a >= n:
        return fib_list

    else:
        fib_list.append(a)
        a, b = b, a+b
        return fibonacci(n, a, b, fib_list)

print(fibonacci(2000))

 

재귀함수 사용 X

def fibonacci(n, a=0, b=1, fib_list=[]):

    for i in range(n):
        if a >= n:
            return fib_list
        else:
            fib_list.append(a)
            a,b = b, a+b

fibonacci(2000)

'프로그래밍 > Python' 카테고리의 다른 글

Python - file open 시 오류 처리  (0) 2023.10.21
Python - 파일 입출력  (0) 2023.10.21
Python - 재귀함수  (0) 2023.10.14
Python - 모듈, 예외처리  (1) 2023.10.14
Python - 개수 지정 없이 매개변수 전달  (0) 2023.10.13

함수 안에서 함수 자기자신을 호출하는 방식을 재귀호출이라고 함.

재귀호출은 일반적인 상황에서는 잘 사용하지 않지만 고급 알고리즘을 구현할 때 유용하다고 함.

보통 알고리즘에 따라서 반복문으로 구현한 코드보다 재귀호출로 구현한 코드가 좀 더 직관적이고 이해하기 쉬운 경우가 많음.(많은 내공이 필요하다고 함.)

파이썬에서는 최대 재귀 깊이가 1000으로 정해져 있어 그 이상 호출 시 RecursionError가 발생

재귀호출을 사용하려면 반드시 종료 조건을 만들어줘야함.

 

예시1

def say_hello(depth):
    if depth == 0:
        return

    else:
        print("안녕하세요!", depth)
        depth -= 1
        say_hello(depth) #재귀호출

say_hello(5)

 

예시2 

def factorial(n):
    print(f"factorial({n}) was called")
    if n == 1:
        return 1 #종료조건

    else:
        return n * factorial(n - 1) # 재귀호출

print("final value is", factorial(5))

약간 이런 느낌이라고 생각하면 된다.

함수에 또 함수를 걸어줘서 방이 하나 더 생긴다고 생각하면 

이해하기가 쉬울 것이다. (악필 양해부탁)

'프로그래밍 > Python' 카테고리의 다른 글

Python - 파일 입출력  (0) 2023.10.21
Python - 피보나치 수열  (0) 2023.10.14
Python - 모듈, 예외처리  (1) 2023.10.14
Python - 개수 지정 없이 매개변수 전달  (0) 2023.10.13
Python - Lambda함수  (0) 2023.10.08

모듈 : 함수, 변수, 클래스를 모아 놓은 파일. 즉, 다른 python 프로그램에서 호출하여 사용할 수 있게끔 만든 파이썬 파일.

 

1. from 

2. import

 

모듈 만들기

%%writefile test_module.py

# file name : test_module.py


def add(a, b):
    return a + b

def sub(a, b):
    return a - b

def mul(a, b):
    return a * b

def div(a, b):
    return a / b

 

모듈 불러오기

import test_module

 

모듈 안에 있는 함수만 불러오고 싶을 때

from test_module import add
from test_module import sub
from test_module import mul
from test_module import div

from test_module import add, sub, mul, div

print(add(1,2), sub(3,4), mul(5,6), div(7,8))

 

3. if __name__ == "__main__": 의 의미

 

.py 파일에는 __name__을 변수로 가짐.

이 변수는 모듈의 이름을 가지고 있는 변수. 현재 .py 파일의 이름을 가지고 있는 변수라는 의미

예를 들어, test_module.py라면 test_module 이라는 문자열을 name변수가 가지고 있게 됨.

__name__변수는 파이썬이 내부적으로 사용하는 특별한 변수 이름.

만약 명령창에서 python test_module.py처럼 직접 test_module.py파일을 실행할 경우 __name__ 변수에는 

"__main__"값이 저장됨.

 

__name__이 정확하게 무엇을 의미하는지 알기 위해서 아래와 같이 파일을 만들고 실행을 해봄.

 

모듈 만들기

%%writefile test_module2.py

print('hello 모듈 시작')
print('hello.py __name__:', __name__)    # __name__ 변수 출력
print('hello 모듈 끝')
import test_module2  # test_module 모듈을 가져오고

print('main.py __name__:' , __name__) # __name__ 변수 출력

실행결과

hello 모듈 시작
hello.py __name__: test_module2
hello 모듈 끝
main.py __name__: __main__

파이썬에서 import로 모듈을 가져오면 해당 스크립트 파일이 한 번 실행되고 hello.py의 __name__ 변수에는 "hello"가 들어가고, main.py의 __name__ 변수에는 '__main__'이 들어감.

 

다시 한번 정리하자면,

__name__은 모듈의 이름이 저장되는 변수이며 import로 모듈을 가져왔을 때 모듈의 이름이 들어감.

하지만 파이썬 인터프리터로 스크립트 파일을 직접 실행했을 때는 모듈의 이름이 아니라 '__main__'이 들어감.

 

그리고 어떤 스크립트 파일이든 파이썬 인터프리터가 최초로 실행한 파일의 __name__에는 '__main__'이 들어감.

이것은 프로그램의 시작점(entry point)라는 뜻.

 

 

클래스나 변수 등을 포함한 모듈

 

모듈 만들기

%%writefile sample_module.py
PYTHON_VERSION = "Python 3.10.10"

class Calc:
    def __init__(self, x, y, w):
        self.height = x
        self.base  = y
        self.upper = w
        
    def triangle(self):
        return (self.height * self.base) / 2
    
    def rectangle(self):
        return self.height * self.base

    def trapezoid(self):
        return (self.base + self.upper)*self.height / 2
    
def summation(z):
    return sum(range(z+1))

 

불러오기

from sample_module import PYTHON_VERSION, Calc, summation

print(PYTHON_VERSION)

calc = Calc(10, 20)
print(calc.triangle())
print(calc.rectangle())
print(calc.trapezoid())

print(summation(100))

주의!!

주피터 노트북에서 동일한 모듈 import는 단 한 번만 수행된다는 것을 명심!

(여러 번 해도 항상 첫 import된 내용만 가지고 있어서 필요시 커널 재부팅)

(Select kernel 에서 No kernel로 바꾸기)

 

3. as

from sample_module import summation as s

s(100)

 

파이썬 예외처리 사용하기

예외(exception)란 코드를 실행하는 중에 발생한 오류를 의미함.

(ZeroDivisionError, AttributeError, NameError, TypeError 등등)

try, except을 이용해서 예외가 발생했을 때도 코드 실행을 중단하지 않고 계속 실행하게 해줄 수 있음.

 

4. try

5. except

def div_10_by(x):
	return 10/x
    
try:
	x = int(input())
    y = div_10_by(x)
    print(y)
    
except:
	print("예외 발생")

이렇게 하면 input을 0으로 해버리면 ZeroDivisionError가 발생해야하는데, except을 걸어주었기 때문에 예외가 발생했다고 인식하고 해당 줄에서 코드 실행을 중단하고 바로 except로 가서 코드를 실행해줌.

그러니깐 y = div_10_by(x)를 실행해줄려고 했는데 x가 0이어서 예외가 발생할 거니깐 코드 실행 중단하고 except 쪽으로 가서 코드를 실행함. 

 

특정 예외만 처리하기

a_list = [50, 40, 30, 20, 10]

try:
    index = int(input("리스트의 인덱스를 입력하세요 >>> "))
    value = int(input("해당 원소의 나눌 값을 입력하세요"))
    result = a_list[index] / value
    print("result =", result)

except ZeroDivisionError: #except ZeroDivisionError as e
    print("숫자를 0으로 나눌 순 없습니다.")

except IndexError: #except IndexError as e
    print("잘못된 인덱스입니다.")

 

6. else

7. finaly

try:
	실행할 코드
    
except:
	예외가 발생했을 때 처리하는 코드
    
else:
	예외가 발생하지 않았을 때 실행할 코드
    
finally:
	예외 발생 여부와 상관없이 항상 실행할 코드

else는 except 바로 다음에 와야 하며 except를 생략할 수는 없음.

finally는 except와 else를 생략할 수 있음.

try는 함수가 아니므로 지역변수와 무관함.

따라서 try 안에서 변수를 만들더라도 try 바깥에서 사용가능.

 

else 사용 예시

num_list = [23,145,1551,2451,5121]

try:
    index = int(input("리스트의 인덱스를 입력하시오 >>> "))
    value = int(input("해당 원소의 나눌 값을 입력하세요. >>> "))
    result = num_list[index] / value

except Exception as e:
    print("예외가 발생하였습니다.", e)

else:
    print("result =", result)

 

finally 사용 예시

num_list = [100,90,80,70,60]

try:
    index = int(input("리스트의 인덱스를 입력하세요 >>> "))
    value = int(input("해당 원소의 나눌 값을 입력하세요 >>> "))
    result = num_list[index] / value

except Exception as e:
    print("예외 발생:", e)

else:
    print("result =",result)

finally:
    print("코드의 수행이 종료되었습니다.")

 

 

8. raise

사용자가 정의한 예외 발생시키기

try:
    even_number = int(input("짝수를 입력하세요 >>> "))
    if even_number % 2 == 0: # 짝수가 아니면 예외 발생
        print(f"{even_number}는 짝수 입니다.")
    else:
        raise Exception("짝수가 아닙니다.")
        
except Exception as e:
    print("예외가 발생하였습니다.", e)

 

raise의 처리과정

def is_even_number():
	even_number = int(input("짝수를 입력하세요 >>> "))
    if even_number % 2 == 0:
    	print(f"{even_number}는 짝수입니다.")
    
    else:
    	raise Exception("짝수가 아닙니다.")
        

try:
	is_even_number()
    
except Exception as e:
	print("예외가 발생하였습니다", e)

is_even_number 함수는 안에 try except이 없는 상태에서 raise로 예외를 발생시켰다.

이렇게 되면 함수 바깥에 있는 except에서 예외가 처리된다.

 

예외가 발생하더라도 현재 코드 블록에서 처리해줄 except가 없다면

except가 나올 때까지 계속 상위 코드 블록으로 올라간다.

 

만약 함수 바깥에도 처리해 줄 except가 없다면 코드 실행은 중지되고 에러가 표시됨. 

 

예외 다시 발생시키기

def is_even_number():
    try: 
        even_number = int(input("짝수를 입력하세요 >>> "))
        if even_number % 2 == 0: # 짝수가 아니면 예외 발생
            print(f"{even_number}는 짝수 입니다.")
        else:
            raise Exception("짝수가 아닙니다.")
            
    except Exception as e:
        print("is_even_number() 함수에서 예외가 발생하였습니다.", e)
        raise # raise로 현재 예외를 다시 발생시켜 상위 코드 블럭으로 넘김
    
try:
    is_even_number()
    
except Exception as e:
    print("하위 코드 블럭에서 예외가 발생하였습니다.", e)
def is_even_number():
    try: 
        even_number = int(input("짝수를 입력하세요 >>> "))
        if even_number % 2 == 0: # 짝수가 아니면 예외 발생
            print(f"{even_number}는 짝수 입니다.")
        else:
            raise Exception("짝수가 아닙니다.")
            
    except Exception as e:
        print("예외가 발생하였습니다.", e)
        raise RuntimeError("is_even_number 함수에서 예외가 발생하였습니다.")
    
try:
    is_even_number()
    
except RuntimeError as e:
    print("하위 코드 블럭에서 예외가 발생하였습니다.", e)

 

9. assert

assert 조건식
assert 조건식, 에러메시지

assert는 지정된 조건식이 거짓일 때 AssertionError 예외를 발생시키며 

조건식이 참이면 그냥 넘어갑니다.

 

try:
	even_number = int(input("짝수 입력: "))
    assert even_number % 2 == 0 
    
except Exception as e:
	print("예외가 발생하였습니다.")

 

 

+ 참고

jupyter 창에서는

!pip install pyfiglet

 

터미널에서

pip install pyfiglet

pip show pyfiglet

 

ctrl_c 로 중단

 

jupyter 에서는 clear라는 명령 불가

 

일반적으로 함수에 이렇게 매개변수를 지정해서 

함수를 호출할 때 매개변수 칸에 자신이 원하는 숫자를 넣으면 결과가 바르게 나온다.

def func_01(x, y, z = 0):
	return x + y + z
    
s = func_01(10,20)
print(s)

 

그런데 매개변수를 정해놓지 않는 방법이 있는데 이건

가변 인수(Arbitrary Argument)방식이라고 한다.

이건 예를 들어, 리스트, 딕셔너리, 세트 등을 매개변수로 사용할 경우 전달 개수를 미리 알 수 없을 경우 자주 사용한다.

def func_01(*args): 
	print(args)
    return sum(args[0])
    
result = func_01([x for x in range(1,11)]) # list argument
print(f"func_01 함수 호출 결과: {s}")

이런 식으로 쓸 수 있는데 

그런데 여기서 한 가지 잘못된 점이 있다. 이걸 출력하면 원소가 리스트인 튜플로 출력이 되는데 이렇게 말고

그냥 튜플로 나오게 하기 위해서는 

def func_01(*args): 
	print(args)
    return sum(args)
    
result = func_01(*[x for x in range(1,11)]) # list argument
print(f"func_01 함수 호출 결과: {s}")

이런식으로 함수를 호출할 때 함수의 괄호 안 매개변수가 되는 리스트나 튜플 앞에 *을 붙여주면 된다.

 

튜플이 아닌 딕셔너리 형태로 전달하기 위해서는 함수의 파라미터 앞에 **을 써주면 된다.

def func_01(**kwargs):
	print(kwargs)
    
func_01(name = "Tom Crise", born = "Syracuse, New York, U.S", age =58)
func_01(my_car = "Pony", type = "used car")

a_dict = {"my_car": "Pony", "type": "used car"}
func_01(**a_dict)

 

함수도 역시 객체가 가능하며, 파라미터로 넘겨주는 게 가능하다.

def hello():
	print("안녕하세요")
    
def say(foo):
	foo()

say(hello)

함수가 객체가 가능하니 당연하게도 리스트 또는 튜플 원소로 함수명 사용이 가능하다.

def plus(x, y):
	return x+y
    
def minus(x,y):
	return x-y
    
f1 = (plus, minus) # tuple
f2 = [plus, minus] # list

print(f1, f2)

'프로그래밍 > Python' 카테고리의 다른 글

Python - 재귀함수  (0) 2023.10.14
Python - 모듈, 예외처리  (1) 2023.10.14
Python - Lambda함수  (0) 2023.10.08
Python 문제 - 학생들 점수 합 및 평균 구하기  (0) 2023.10.08
Python 문자열 정렬, set  (0) 2023.10.08

lambda는 함수를 생성할 때 사용하는 def와 동일한 역할

add = lambda a, b : a+b
result = add(10, 20)
print(result)


def add(a,b):
	return a+b
    
result = add(10, 20)
print(result)

# 모두 같은 결과가 나옴.

 

lambda 사용

items = [
    ("food1", 100),
    ("food2", 90),
    ("food3", 70)
]

# 익명 함수로 item list 내 3개 튜플 쌍 원소 중 두 번째(숫자) 원소로 정렬하는 방법
items.sort(key = lambda item: item[1], reverse = True) 
print(items)

# Map
scores = list(map(lambda item: item[1], items)) # [100, 90, 70]만 추출 
# items 안에 있는 튜플 값을 가져와서 값을 확인할건데 그 튜플 안의 두 번째 값을 item을 가져옴. 그거 한 데 묶어서 리스트화 시켜서 출력
print(scores)

# filter에 lambda 함수 적용하여 값이 80이상만 추출하는 방법
high_scores = list(filter(lambda item: item[1] >= 80, items))
print(high_scores)

간단하게 푼 코드

scores = \
    [[80, 80, 81],
     [84, 92, 63],
     [63, 73, 97],
     [69, 93, 85],
     [83, 84, 93]]

for student_num, ave in enumerate(scores):
    print(f"{student_num + 1} : {round(sum(ave)/len(ave))}")

 

 

더 복잡하게 푼 코드

print("[국, 영, 수]")
print("-"*32)

for row in range(len(scores)):
    s = 0
    for column in range(len(scores[row])):
        s += scores[row][column]
    print(f"{scores[row]}  합: {s}  평균: {round(s/len(scores[row]), 2)}")

 

'프로그래밍 > Python' 카테고리의 다른 글

Python - 개수 지정 없이 매개변수 전달  (0) 2023.10.13
Python - Lambda함수  (0) 2023.10.08
Python 문자열 정렬, set  (0) 2023.10.08
Python zip, enumerate 함수 사용  (2) 2023.10.08
Python 비트 연산자 정리  (0) 2023.10.07
print(say.center(10))     
# 숫자만큼 자릿수를 잡은 후, 문자열을 가운데 배치

print(say.center(10, "#"))
# 숫자만큼 자릿수를 잡은 후, 문자열을 가운데 배치
# 문자열을 제외한 다른 자리에는 #으로 채우기

print(say.ljust(10))
# 숫자만큼 자릿수를 잡은 후, 왼쪽에 붙여 출력
print(say.rjust(10))
# 숫자만큼 자릿수를 잡은 후, 오른쪽에 붙여 출력

print(say.zfill(10))
# 오른쪽으로 붙여쓰고 왼쪽 빈 공간은 0으로 채움.

 

set 자료형

> 중복 허용 X

> 입력된 순서는 중요하지 않음.

> set( ) 생성자 함수를 통해 만듦.

> { } 를 이용해서 만들 수 있음. (딕셔너리와 같은 중괄호 사용, 구분 유의)

> add, update, remove, copy, clear method 사용 가능

> 사용예시

> 집합연산과 세트함수

> 여러 자료형 저장이 가능하지만, 중복은 허용 안함.

> set에는 순서가 없기 때문에 index 사용 못 함. 

> 사용예시 2

 

a_list = ["A", "B", "C", "D", "E"]
a_list = list("ABCDE")              # 둘 다 똑같은 리스트

n_list = [65, 66, 67, 68, 69, 70]
n_list = [ascii for ascii in range(65,71)] # 이 방법 중요 

z_list = list(zip(a_list, n_list))
print(z_list)

# zip함수 : 동일한 개수로 이루어진 자료형을 튜플로 묶어줌.

## 결과: [('A', 65), ('B', 66), ('C', 67), ('D', 68), ('E', 69)]

 

 

enumerate 사용 X

x_list = [54, 50, 71, 58, 59]
index = 0

for item in x_list:
    print(f"[{index: 2d}] {item} ", end ='')
    index += 1

 

enumerate 사용 O

for index, item in enumerate(x_list):
    print(f"[{index: 2d}] {item} ", end = '')
# 인덱스 시작 번호 지정 가능

for index, item in enumerate(x_list, start = 1):
    print(f"[{index: 2d}] {item} ", end = '')

 

# 비트 논리곱(&) 연산자

# A B    A&B
# 0 0    0
# 0 1    0
# 1 0    0
# 1 1    1      >>> 0011 => 3  / 0101 => 5
5 & 3  ##결과 : 1

 

# 비트 논리합(|) 연산자

# A B    A&B
# 0 0    0
# 0 1    1
# 1 0    1
# 1 1    1
3 | 5  ## 7

 

# 비트 배타적 논리합(^) 연산자

# A B    A&B
# 0 0    0
# 0 1    1
# 1 0    1
# 1 1    0     >>> 두 값이 같으면 0, 다르면 1
5 ^ 3 ## 6

 

# 왼쪽 시프트(<<) 연산자

# 00011010 = 26
# 01101000 = 104  앞의 두 비트(00)는 사라짐. 뒤의 두 비트는 0으로 채움.
# 왼쪽으로 시프트할 때마다 2^n을 곱한 효과가 나타남.
ex = 10
expr = f"{ex << 1} {ex << 2} {ex << 3} {ex << 4}"
print(expr)

 

# 오른쪽 시프트(>>) 연산자

# 00011010 = 26
# 00000110 = 6   앞의 두 비트는 부호 비트(0)으로 채우고 뒤의 두 비트는 사라짐.
# 오른쪽으로 시프트할 때마다 2^n으로 나눈 효과
# 시프트 연산은 정수만 연산하므로 몫만 남음. (26/2^2 = 6)
ex2 = 10
expr2 = f"{ex >> 1} {ex >> 2} {ex >> 3} {ex >> 4}" 
print(expr2)

 

# 보수(~) 연산자

# 두 수에 대해 연산하는 것이 아니라, 각 비트를 반대로 만드는 연산자

# 1의 보수
# 0 >> 1 
# 1 >> 0
# 0111 1000 >> (1의 보수) = 1000 0111
a = 12345
~a   # -12346


# 2의 보수
# 1의 보수 + 1 = 2의 보수
# 0111 1000 >> 2의 보수
# = 1의 보수 + 1
# = 1000 0111 + 1
# = 1000 1000
a = 12345
~a + 1 # -12345

'프로그래밍 > Python' 카테고리의 다른 글

Python 문자열 정렬, set  (0) 2023.10.08
Python zip, enumerate 함수 사용  (2) 2023.10.08
파이썬 매개변수 기본값 설정  (0) 2023.10.06
Anaconda 기반의 Python 개발환경 구축  (0) 2023.04.25
파이썬 (~while)  (0) 2023.04.25
def f_01(x, y, z = 0):   
# 기본값 설정은 항상 기본값이 설정되지 않은 매개변수 뒤에 와야함. (위반 시 오류 발생)
	return x + y + z 
    
s = f_01(20, 30)
print("func_01(10,20) 호출 후 반환 값:", s) #이러면 50이 출력됨.

s = func_01(20, 30, 50)
print("func_01(10, 20, 30) 호출 후 반환 값:", s) #이러면 100이 출력됨.

함수 선언 시 매개변수의 기본값을 설정해두면, 

함수 사용 시 해당 매개변수 생략 가능 

기본값이 정해져 있지 않은 매개변수는 반드시 값을 전달해줘야 함. 

'프로그래밍 > Python' 카테고리의 다른 글

Python 문자열 정렬, set  (0) 2023.10.08
Python zip, enumerate 함수 사용  (2) 2023.10.08
Python 비트 연산자 정리  (0) 2023.10.07
Anaconda 기반의 Python 개발환경 구축  (0) 2023.04.25
파이썬 (~while)  (0) 2023.04.25

+ Recent posts