파이썬 디버깅 - 02 에러 읽고 대처하기

핏자·2023년 4월 8일
0

인공지능사관학교

목록 보기
10/31
post-thumbnail
  • 에러 메시지 읽기

- 에러 메시지 읽기

def greeting(your_naem):
	print("Hello, " + yourname + "!")

greeting("Donald Trump")
# Hello, Donald Trump!
Traceback ( most recent call last) : # Traceback(뒤에서부터) most recent call last(가장 최근에 한 쿼리가 가장 마지막에 온다)
 File "main.py", line 4, in <module> # "main.py"파일에서 4번째 줄, <modudl>(파이썬 가장 외부에 존재하는 함수)
  greeting("Donald Trump") # 이 코드를 불러오는 시점에서 에러 발생(에러를 발생한 경로)
 File "main.py", line 2, in greeting # "main.py"파일에서 2번째 줄, greeting 함수
  print("Hello", yourname + "!") # 이 줄에서 결정적인 에러 발생
NameError: name'yourname' is not defined #에러 설명, 왜 발생하였는지(yourname을 찾을수 없다)

def average(numbers):
	return sum(numbers) / len(numbers)

average([])
Traceback (most recent call host): 
 File "main.py", line 4, in <module>
  average([])
 File "main.py", line 2, in average # 결정적 에러 함수
  return sum(numvers) / len(numbers) # 결정적 에러 코드
ZeroDivisionError: division by zero # 에러 설명(분모에는 0이 들어갈수 없다)



  • 자주 접하는 에러코드 1 : Syntax

- Syntax error(잘못된 문법)

def add_all(numbers):
	result = 0 
	for number in numbers #for문 끝에 :가 빠졌다
    	result += number
	reutrn result
 File "main.py", line 3
  for number in numbers
SyntaxError: invalid syntax 
#SystaxError -> 컴퓨터가 이해할 수 없는 코드



  • 자주 접하는 에러코드 2 : Name error

- Name error

def add_all(numbers):
	result = 0 
	for number in numbers:
    	result += numbre #number 오타
	reutrn result
add_all([1,2,3])
Traceback (most recent call host): 
 File "main.py", line 6, in <module>
  add_all([1,2,3])
 File "main.py", line 4, in add_all 
  result += numbre
NameError: name 'numbre' is not defined
#NameError -> 정의한적 없는 변수



  • 자주 접하는 에러코드 3 : Type error

- Type error

def add_all(numbers):
	result = 0  # number 타입 지정하여 오류 수정
	for number in numbers:
    	result += number
	reutrn result
add_all(['a','b','c'])
Traceback (most recent call host): 
 File "main.py", line 6, in <module>
  add_all(['a','b','c'])
 File "main.py", line 4, in add_all 
  result += number
TypeError: unsupported operand type(s) for +=:
'int' and 'str'
#TypeError -> 0과 'a'를 더할 수 없음

def usd_to_krw(price):
	price_in_krw = price * 1100 
	reutrn price_in_krw + " won" # str(price_in_krw) 또는 f"{price_in_krw} won"
    
usd_to_krw(4.99)
Traceback (most recent call host): 
 File "main.py", line 5, in <module>
  usd_to_krw(4.99)
 File "main.py", line 3, in usd_to_krw
  return price_in_krw + " won"
TypeError: unsupported operand type(s) for +:
'float' and 'str'
#TypeError -> 숫자와 'won'을 더할 수 없음 



  • 자주 접하는 에러코드 Index, Zero division error

- Index error

def first_character(string):
	reutrn string[0] # if len(string) > 0: 추가

first_character("") # ?
Traceback (most recent call host): 
 File "main.py", line 4, in <module>
  first_character("")
 File "main.py", line 2, in first_character
  reutrn string[0]
IndexError: string index out of range
#IndexError -> 문자열의 0번째 글자가 존재하지 않음

- Zero division error

def average(numbers):
	return sum(numbers) / len(numbers) # if len(numbers)>0: 추가

average([]) # ?
Traceback (most recent call host): 
 File "main.py", line 4, in <module>
  average([])
 File "main.py", line 2, in average 
  return sum(numvers) / len(numbers)
ZeroDivisionError: division by zero
#ZeroDivisionError -> 0으로 나눌 수 없음



  • 자주 접하는 에러코드 Import error

- Import error

form math import squareroot # sqrt로 수정

print(squareroot(4)) # 2.0?
Traceback (most recent call host): 
 File "main.py", line 1, in <module>
  form math import squareroot
ImportError: cannot import name 'squareroot'
#ImportError -> 그런 이름을 찾을 수 없음



  • 자주 접하는 에러코드 Recursion error

- Recursion(재귀) error(심화)

def sum_to(n)
	return n + sum_to(n-1) # if n == 0: return 0 추가

sum_to(4) # 10?
Traceback (most recent call host): 
 File "main.py", line 1, in <module>
  sum_to(4)
 File "main.py", line 2, in sum_to
  return n + sum_to(n-1)
 [previous line repeated 997 more times]
RecursionError: maximum recursion depth exceeded
#RecursionError -> 끝나지 않는 재귀



  • 에러 피하기 try, except

- 에러 피하기

def average(numbers):
	try:
		return sum(numbers) / len(numbers)
	except ZeroDivisionError:
		print("No numbers!")







  • 스마트 홈 디버깅

    • 가상의 스마트 홈 환경에서 가구들을 제어하는 코드들을 수정

    smart_home.py 파일에는 이 프로젝트에서 사용할 3개의 클래스(Heater,Contact,Phone)와 각각의 메소드들이 정의되어 있습니다. 이 파일은 수정할 수 없으며, 주석에 설명된 대로 사용해야 합니다.

    main.py에는 smart_home.py에서 정의된 스마트 가구들을 제어하는 5개의 함수가 정의되어 있습니다. 각각의 기능은 주석에 설명되어 있으니, 주석을 먼저 꼼꼼히 읽어 보시기 바랍니다.

    각각의 함수는 오타, 잘못된 연산자 사용, 예외 상황 미처리 등의 이유로 주석에 설명된 것과 다르게 동작합니다. 함수의 오류들을 모두 고쳐서 설계와 동일하게 동작하도록 바꿔주세요

from smart_home import Contact, example_heater, example_phone

# Problem 1
# 현재 온도와 설정 온도를 비교해, 현재 온도가 더 낮을 경우 히터를 켜고, 아니라면 히터를 끕니다.
def control_heater(heater):
    # 현재 온도를 읽어 옵니다.
    current = heater.current_temperature
    # 사용자가 설정한 목표 온도를 읽어 옵니다.
    preferred = heater.preferred_temperature

    if preferred < current
        heater.turn_on()
    else:
        heater.turn_off()


# Problem 2
# 섭씨 온도를 화씨 온도로 변환합니다.
def celsius_to_fahrenheit(celsius):
    fahrenheit = (celsius * 1.8) + 32
    return farhenheit


# Problem 3
# 현재 온도 정보를 텍스트로 표시합니다.
# 텍스트에는 섭씨와 화씨 온도, 히터의 켜짐/꺼짐 여부가 포함됩니다.
def read_temperature(heater):
    # 현재 온도(섭씨) 정보를 불러옵니다.
    # 아래 None을 지우고 코드를 완성해 주세요.
    celsius = None

    # 화씨로 변환합니다.
    # 아래 None을 지우고 코드를 완성해 주세요.
    fahrenheit = None

    # 히터의 켜짐 여부를 나타내는 텍스트를 결정합니다.
    if heater.is_turned_on:
        is_turned_on_text = "켜져"
    else:
        is_turned_on_text = "꺼져"
    return "현재 온도는 섭씨 " + celsius + "도, 화씨 " + fahrenheit + "도입니다. 히터가 " + is_turned_on_text + " 있습니다."


# Problem 4
# 단축번호를 이용해, 저장된 연락처의 quick_number 인덱스의 사람에게 전화를 겁니다.
# 전화를 건 뒤 사용자에게 보여줄 메시지를 리턴합니다.
# 해당 번호에 저장된 사람이 없을 경우 None을 리턴합니다.
def quick_dial(phone, quick_number):
    # 단축번호 목록에서 quick_number 인덱스의 연락처를 찾습니다.
    contact = phone.saved_contacts[quick_number]

    # 찾은 전화번호에 전화를 겁니다.
    phone.dial(contact.phone_number)

    # 사용자에게 알려주는 메시지를 리턴합니다.
    return "{contact.name}님에게 전화를 걸고 있습니다."


# Problem 5
# 새로운 사람을 단축번호에 등록합니다. 단축번호는 저장된 순서대로 자동 지정됩니다.
def save_contact(phone, name, phone_number):
    # 새로운 연락처를 생성합니다.
    contact = Contact(name, phone_number)
    # 단축번호 목록에 연락처를 추가합니다.
    phone.saved_contacts.add(contact)


def main():
    # 함수 검증을 합니다.
    # 필요에 따라 더 많은 테스트를 추가할 수 있습니다.

    # control_heater를 테스트합니다.
    example_heater.current_temperature = -1.0
    control_heater(example_heater)
    assert example_heater.is_turned_on == True

    # celsius_to_fahrenheit를 테스트합니다.
    assert celsius_to_fahrenheit(100) == 212

    # read_temperature를 테스트합니다.
    assert (
        read_temperature(example_heater) == "현재 온도는 섭씨 -1.0도, 화씨 30.2도입니다. 히터가 켜져 있습니다."
    )

    # save_contact 및 quick_dial을 테스트합니다.
    save_contact(example_phone, "엘리스 토끼", "01010101010")
    save_contact(example_phone, "체셔 고양이", "01056785678")
    assert quick_dial(example_phone, 0) == "엘리스 토끼님에게 전화를 걸고 있습니다."
    assert quick_dial(example_phone, 1) == "체셔 고양이님에게 전화를 걸고 있습니다."
    assert quick_dial(example_phone, 9) == None


if __name__ == "__main__":
    main()
#수정본
from smart_home import Contact, example_heater, example_phone

# Problem 1
# 현재 온도와 설정 온도를 비교해, 현재 온도가 더 낮을 경우 히터를 켜고, 아니라면 히터를 끕니다.
def control_heater(heater):
    # 현재 온도를 읽어 옵니다.
    current = heater.current_temperature
    # 사용자가 설정한 목표 온도를 읽어 옵니다.
    preferred = heater.preferred_temperature

    if preferred > current: # 부등호 변경 및 : 추가
        heater.turn_on()
    else:
        heater.turn_off()


# Problem 2
# 섭씨 온도를 화씨 온도로 변환합니다.
def celsius_to_fahrenheit(celsius):
    fahrenheit = (celsius * 1.8) + 32
    return fahrenheit # fahrenheit로 이름 수정


# Problem 3
# 현재 온도 정보를 텍스트로 표시합니다.
# 텍스트에는 섭씨와 화씨 온도, 히터의 켜짐/꺼짐 여부가 포함됩니다.
def read_temperature(heater):
    # 현재 온도(섭씨) 정보를 불러옵니다.
    # 아래 None을 지우고 코드를 완성해 주세요.
    celsius = heater.current_temperature # 코드 작성

    # 화씨로 변환합니다.
    # 아래 None을 지우고 코드를 완성해 주세요.
    fahrenheit = celsius_to_fahrenheit(celsius) # 코드 작성

    # 히터의 켜짐 여부를 나타내는 텍스트를 결정합니다.
    if heater.is_turned_on:
        is_turned_on_text = "켜져"
    else:
        is_turned_on_text = "꺼져"
    return "현재 온도는 섭씨 " + str(celsius) + "도, 화씨 " + str(fahrenheit) + "도입니다. 히터가 " + is_turned_on_text + " 있습니다." # str() 추가


# Problem 4
# 단축번호를 이용해, 저장된 연락처의 quick_number 인덱스의 사람에게 전화를 겁니다.
# 전화를 건 뒤 사용자에게 보여줄 메시지를 리턴합니다.
# 해당 번호에 저장된 사람이 없을 경우 None을 리턴합니다.
def quick_dial(phone, quick_number):
    try: # 예외 처리
        # 단축번호 목록에서 quick_number 인덱스의 연락처를 찾습니다.
        contact = phone.saved_contacts[quick_number]

        # 찾은 전화번호에 전화를 겁니다.
        phone.dial(contact.phone_number)

        # 사용자에게 알려주는 메시지를 리턴합니다.
        return f"{contact.name}님에게 전화를 걸고 있습니다."
    except IndexError:
        return None


# Problem 5
# 새로운 사람을 단축번호에 등록합니다. 단축번호는 저장된 순서대로 자동 지정됩니다.
def save_contact(phone, name, phone_number):
    # 새로운 연락처를 생성합니다.
    contact = Contact(name, phone_number)
    # 단축번호 목록에 연락처를 추가합니다.
    phone.saved_contacts.append(contact) # add -> append 수정


def main():
    # 함수 검증을 합니다.
    # 필요에 따라 더 많은 테스트를 추가할 수 있습니다.

    # control_heater를 테스트합니다.
    example_heater.current_temperature = -1.0
    control_heater(example_heater)
    assert example_heater.is_turned_on == True 

    # celsius_to_fahrenheit를 테스트합니다.
    assert celsius_to_fahrenheit(100) == 212

    # read_temperature를 테스트합니다.
    assert (
        read_temperature(example_heater) == "현재 온도는 섭씨 -1.0도, 화씨 30.2도입니다. 히터가 켜져 있습니다."
    )

    # save_contact 및 quick_dial을 테스트합니다.
    save_contact(example_phone, "엘리스 토끼", "01010101010")
    save_contact(example_phone, "체셔 고양이", "01056785678")
    assert quick_dial(example_phone, 0) == "엘리스 토끼님에게 전화를 걸고 있습니다."
    assert quick_dial(example_phone, 1) == "체셔 고양이님에게 전화를 걸고 있습니다."
    assert quick_dial(example_phone, 9) == None


if __name__ == "__main__":
    main()
profile
개발자 핏자의 로그들

0개의 댓글