본문 바로가기
코딩 공부/파이썬 (혼공단 11기)

[혼공파] 6주차_07-2 ~ 08

by 루담 2024. 2. 7.

👩🏻‍💻 아쉬움과 뿌듯함이 공존하는 혼공파 스터디의 마지막이다. 많은 감정들이 들지만, 이 이야기들은 활동 회고에서 쓰기로 하고 미뤄두자.

 

설날에도 책 펼쳐서 공부하는 여자 어떤데 ✨

 


07-2. 외부 모듈
▷ 핵심 키워드 - 외부 모듈 / pip install / 제어 역전 / 라이브러리 / 프레임워크

 

 

✍🏻외부 모듈을 설치하고 사용하는 기본적인 방법을 알아보자

 

✏️모듈 설치하기

-프로그램 창을 띄우고 명령 프로프트 창에서 실행한다

pip install 모듈 이름

🌟!! 경로를 Scripts까지 설정해 놓은 다음 !! pip install 로 beautifulsoup4 깔아주기

✏️Beautiful Soup 모듈

-Beautiful Soup를 사용해서 기상청의 날씨 정보를 가져와 출력해보기

 

🖐🏻직접 해보는 손코딩🖐🏻

(bs4 모듈의 BeautifulSoup() 함수의 매개변수로 HTML 문자열과 "html.parser"라는 문자열을 넣으면 BeautifulSoup라는 특수한 객체를 리턴한다)

# 모듈을 읽어 들입니다
from urllib import request
from bs4 import BeautifulSoup

# urlopen() 함수로 기상청의 전국 날씨를 읽습니다

# BeautifulSoup을 사용해 웹 페이지를 분석합니다
soup = BeautifulSoup(target, "html.parser")

# location 태그를 찾습니다
for location in soup.select("location"):
    # 내부의 city, wf, tmn, tmx 태그를 찾아 출력합니다
    print("도시:", location.select_one("city").string)
    print("날씨:", location.select_one("wf").string)
    print("최저기온:", location.select_one("tmn").string)
    print("최고기온:", location.select_one("tmx").string)
    print()

-결과

부산은 맑음 !! (부산만 가져옴)

👉🏻지역이 표시된 location을 찾고, location 내부에 있는 city, wf, tmn, tmx 태그의 내용을 추출했다.

📋 여러 개를 태그할 때는 select() 함수, 하나만 선택할 때는 select_one() 함수

📋RSS(Really Simple Syndication, Rich Site Summary)란 블로그처럼 컨텐츠 업데이트가 자주 일어나는 웹사이트에서, 업데이트된 정보를 쉽게 구독자들에게 제공하기 위해 XML을 기초로 만들어진 데이터 형식 / RSS서비스를 이용하면 업데이트된 정보를 찾기 위해 홈페이지에 일일이 방문하지 않아도 업데이트 될 때마다 빠르고 편리하게 확인할 수 있다.

 

✏️Flask 모듈

-파이썬으로 웹 개발을 할 때는 Django(장고) 또는 Flask(플라스크) 등의 모듈을 사용한다

  • Django - 매우 다양한 기능을 제공하는 웹 개발 프레임워크
  • Flask - 작은 기능만을 제공하는 웹 개발 프레임워크

-Flask 모듈도 앞과 같이 설치하기

🌟 앞과 똑같이 경로를 Scripts까지 설정해 놓은 다음 flask install하기

 

🖐🏻직접 해보는 손코딩🖐🏻

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1>Hello World!</h1>"

app.run()

(책에서는

$env:FLASK_APP="파일 이름"

flask run

👆🏻위 두 명령어를 입력하면 실행이 된다는데, 나는 터미널을 파워셸로 하든 cmd로 하든 실행이 되지 않았다ㅠㅠ 그래서 마지막에 app.run()을 넣고 실행을 하니 무사히(?) 링크가 떴다.)

-결과

(여기에 이 WARNING은 실제 서비스 용도로 사용하지 말라는 경고 문구라고 한다)

가장 작은 웹사이트 ㅋㅋㅋㅋ 귀엽다.

📋@app.route() : 데코레이터

 

🖐🏻직접 해보는 손코딩🖐🏻

-BeautifulSoup 스크레이핑 실행

# 모듈을 읽어들입니다
from flask import Flask
from urllib import request
from bs4 import BeautifulSoup

# 웹 서버를 생성합니다
app = Flask(__name__)
@app.route("/")

def hello():
    # urlopen() 함수로 기상청의 전국 날씨를 읽습니다
   
    # BeautifulSoup를 사용해 웹 페이지를 분석합니다
    soup = BeautifulSoup(target, "html.parser")
   
    # location 태그를 찾습니다
    output = ""
    for location in soup.select("location"):
        # 내부의 city, wf, tmn, tmx 태그를 찾아 출력합니다
        output += "<h3>{}</h3>".format(location.select_one("city").string)
        output += "날씨: {}<br/>".format(location.select_one("wf").string)
        output += "최저/최고 기온: {}/{}"\
            .format(\
                location.select_one("tmn").string,\
                location.select_one("tmx").string\
            )
        output += "<hr/>"
    return output

app.run()

(여기에서도 앞과 마찬가지로 flask 실행 때문에 app.run() 함수를 임의로 추가했다..)

-결과

우왕

 

✏️라이브러리와 프레임워크

구분 설명
라이브러리(library) 정상적인 제어를 하는 모듈
프레임워크(framework) 제어 역전이 발생하는 모듈

-라이브러리와 프레임워크는 제어 역전(IoC) 여부에 따라서 달라진다

 

👻라이브러리

from math import sin, cos, tan, floor, ceil

print("sin(1):", sin(1))
print("cos(1):", cos(1))
print("tan(1):", tan(1))

print("floor(2.5):", floor(2.5))
print("ceil(2.5):", ceil(2.5))

# floor-내림, ceil-올림

👆🏻위는 math 모듈이다. math 모듈은 모듈 내부의 기능을 '개발자'가 직접 호출했다. / 이처럼 개발자가 모듈의 기능을 호출하는 형태의 모듈을 라이브러리라고 한다

 

👻프레임워크

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1>Hello World!</h1>"

👆🏻위 코드를 보면 내부에 함수만 정의했지 직접적으로 무언가 진행하는 코드는 하나도 없다.

👉🏻Flask 모듈이 제공하는 명령어를 실행하면 Flask가 내부적으로 서버를 실행한 뒤 지정한 파일을 읽어 들여 적절한 상황에 스스로 실행하게 된다. / 이처럼 모듈이 개발자가 작성한 코드를 실행하는 형태의 모듈을 프레임워크라고 한다

 

🌟개발자가 모듈의 함수를 호출하는 것이 일반적인 제어 흐름(라이브러리). 프레임워크는 이와 반대로 개발자가 만든 함수를 모듈이 실행하게 되는 것, 즉 제어 역전!!!!

 


함수 데코레이터

 

-대상 함수의 앞뒤에 꾸밀 부가적인 내용, 혹은 반복할 내용을 데코레이터로 정의해서 손쉽게 사용할 수 있도록 한 것

 

<예제>

# 함수 데코레이터를 생성합니다
def test(function):
    def wrapper():
        print("인사가 시작되었습니다")
        function()
        print("인사가 종료되었습니다")
    return wrapper

# 데코레이터를 붙여 함수를 만듭니다
@test
def hello():
    print("hello")
   
# 함수를 호출합니다
hello()

-결과

👉🏻test() 함수에서 wrapper() 함수를 리턴하므로, 최종적으로 hello에 함수가 들어가 hello() 형태로 호출된 것


7-2 chapter 마무리

 

🔎핵심 포인트

-외부 모듈은 파이썬이 기본적으로 제공하지 않고 다른 사람들이 만들어 제공하는 모듈

-pip install은 외부 모듈을 설치할 때 사용하는 명령어

-제어 역전은 개발자가 만든 함수를 모듈이 실행하는 것

-라이브러리는 개발자가 모듈의 기능을 호출하는 형태와 같이 정상적인 제어를 하는 모듈

-프레임워크는 모듈이 개발자가 작성한 코드를 실행하는 형태의 모듈

 

 

+) 내가 나아고자 하는 분야에서 사용되는 모듈

👉🏻데이터 분석 - 데이터를 분석해 상황을 확인하거나 전략을 세울 때, 데이터 분석+인공지능으로 미래의 데이터를 예측할 때 쓰인다

파이썬으로 데이터를 분석할 때는 pandas, matplotlib 등의 모듈을 활용한다. 

(나중에 pandas, matplotlib에 대해서 알아보기)

 

 


07-3. 모듈 만들기
▷ 핵심 키워드 - 엔트리 포인트 / __name__=="__main__" / 패키지

 

 

✍🏻모듈을 만드는 방법, 모듈 실행과 관련된 안전 장치를 설치하는 방법, 패키지를 만드는 방법에 대해서 알아보기

🌟module_basic 디렉터리 만들어두기!!

 

✏️모듈 만들기

-앞서 만들었던 함수들을 이용해서 모듈 만들어보기

 

🖐🏻직접 해보는 손코딩🖐🏻

-test_module.py 파일

# test_moule.py 파일
PI = 3.141592

def number_input():
    output = input("숫자 입력>")
    return float(output)

def get_circumference(radius):
    return 2 * PI * radius

def get_circle_area(radius):
    return PI * radius * radius

-main.py 파일

# main.py 파일
import test_module as test

radius = test.number_input()
print(test.get_circumference(radius))
print(test.get_circle_area(radius))

 

✏️__name__=="__main__"

👻__name__

-엔트리 포인트 또는 메인 내부에서의 __name__은 "__main__"

 

👻모듈의 __name__

-모듈 내부에서 __name__을 출력하면 모듈의 이름을 나타낸다

 

🖐🏻직접 해보는 손코딩🖐🏻

-test_module.py

# test_module.py 파일
print("# 모듈의 __name__ 파일 출력하기")
print(__name__)
print()

-main.py

# main.py 파일
import test_module

print("# 메인의 __name__ 출력하기")
print(__name__)
print()

-결과

👉🏻엔트리 포인트 파일에서는 "__main__" / 파일에서는 모듈 이름 test_module 출력

 

👻__name__ 활용하기

-이를 활용해 현재 파일이 모듈로 실행되는지, 엔트리 포인트로 실행되는지 확인할 수 있다.

 

🖐🏻직접 해보는 손코딩🖐🏻

-test_module.py

PI = 3.141592

def number_input():
    output = input("숫자 입력>")
    return float(output)

def get_circumference(radius):
    return 2 * PI * radius

def get_circle_area(radius):
    return PI * radius * radius

# 활용 예
print("get_circumference(10):", get_circumference(10))
print("get_circle_area(10):", get_circle_area(10))

-main.py

import test_module as test

radius = test.number_input()
print(test.get_circumference(radius))
print(test.get_circle_area(radius))

-결과

👆🏻맨 앞에서 모듈로 사용하고 있는 get_circumference~ 부분이 출력된다.

📋이것을 파일이 엔트리 포인트 일때만 실행하도록 코드를 조금 바꾼다 = 조건문으로 __name__이 "__main__" 인지 확인하면 된다

 

🖐🏻직접 해보는 손코딩🖐🏻

-test_module.py

PI = 3.141592

def number_input():
    output = input("숫자 입력>")
    return float(output)

def get_circumference(radius):
    return 2 * PI * radius

def get_circle_area(radius):
    return PI * radius * radius

# 활용 예
if __name__=="__main__":
    print("get_circumference(10):", get_circumference(10))
    print("get_circle_area(10):", get_circle_area(10))

-main.py

import test_module as test

radius = test.number_input()
print(test.get_circumference(radius))
print(test.get_circle_area(radius))

(그냥 앞의 손코딩에서 if 부분만 수정하면 된다)

-결과

 

✏️패키지

-패키지: 모듈이 모여서 구조를 이룬 것

 

👻패키지 만들기

-test_package 폴더를 만든 다음 module_a.py와 module_b.py 파일 생성

 

🖐🏻직접 해보는 손코딩🖐🏻

-module_a.py와 module_b.py

# ./test_package/module_a.py의 내용
variable_a = "a 모듈의 변수"
# ./test_package/module_b.py의 내용
variable_b = "b 모듈의 변수"

-main.py

# 패키지 내부의 모듈을 읽어 들입니다
import test_package.module_a as a
import test_package.module_b as b

# 모듈 내부의 변수를 출력합니다
print(a.variable_a)
print(b.variable_b)

-결과

 

👻__init__.py 파일

- __init__.py: 해당 폴더가 패키지임을 알려주고, 패키지와 관련된 초기화 처리를 하는 파일

 

🖐🏻직접 해보는 손코딩🖐🏻

-__init__.py

# "from test_package import *"로
# 모듈을 읽어 들일 때 가져올 모듈
__all__ = ["module_a", "module_b"]

# 패키지를 읽어 들일 때 처리를 작성할 수도 있습니다
print("test_package를 읽어 들였습니다.")

-main_1.py

# 패키지 내부의 모듈을 모두 읽어 들입니다
from test_package import *

# 모듈 내부의 변수를 출력합니다
print(module_a.variable_a)
print(module_b.variable_b)

-결과

👉🏻main_1.py 파일로 패키지를 읽어 들일 때 __init__.py를 가장 먼저 실행하게 된다

 


텍스트 데이터와 바이너리 데이터
비교 항목 텍스트 데이터 바이너리 데이터
구분 방법 -텍스트 에디터로 열었을 때 읽을 수 있다 -텍스트 에디터로 열어도 읽을 수 없다
장점 -사람이 쉽게 읽을 수 있다
-텍스트 데이터로 쉽게 편집할 수 있다
-용량이 적다
단점 -용량이 크다 -사람이 쉽게 읽을 수 없다
-일반적으로 덱스트 에디터로 편집할 수 없다

 

🌟인터넷에서 이미지 읽고 저장하기

-웹에서 데이터를 가져올 때, 바이너리 데이터로 저장해야 한다

-"rb"나 "wb"로 적으면 바이너리 형식으로 파일을 읽고 써준다

 

🖐🏻직접 해보는 손코딩🖐🏻

# 모듈을 읽어 들입니다
from urllib import request

# urlopen() 함수로 구글의 메인 페이지를 읽습니다 엥근데 페이지는 한빛미디어 페이지같은디?
output = target.read()
print(output)

# write binary[바이너리 쓰기] 모드로
file = open("output.png", "wb")
file.write(output)
file.close()

-결과

길어서 생략!

👆🏻b'로 감싸져 있으므로 바이너리 데이터!

(코드 실행하면 폴더에 output.png 파일이 저장된다는데,,, 왜 없지?!)

 


7-3 chapter 마무리

 

🔎핵심 포인트

-엔트리 포인트는 python 명령어를 사용해서 첫 진입 파일

-__name__=="__main__"는 현재 파일이 엔트리 포인트인지 확인할 때 사용하는 코드

-패키지는 모듈이 모인 것

 

 


08-1. 클래스의 기본
▷ 핵심 키워드 - 객체 / 객체 지향 프로그래밍 언어 / 추상화 / 클래스 / 인스턴스 / 생성자 / 메소드

 

 

✍🏻C를 제외한 모든 프로그래밍 언어는 객체 지향 프로그래밍 언어(객체를 우선으로 프로그래밍한다)

https://earthly.dev/blog/python-classes-and-objects/

(위 사진이 클래스랑 객체를 잘 보여주는 것 같아서 가져왔다.)

  • 클래스 기반의 객체 지향 프로그래밍 언어 - 클래스를 기반으로 객체를 만들고, 그러한 객체를 우선적으로 생각해서 프로그래밍하는 것
  • 객체 - 속성메소드를 갖는 것

 

✏️객체

-여러 가지 속성을 가질 수 있는 대상

 

🖐🏻직접 해보는 손코딩1🖐🏻

# 학생 리스트를 선언합니다
students = [
    {"name": "운인성", "korean": 87, "math": 98, "english": 88, "science": 95},
    {"name": "연하진", "korean": 92, "math": 98, "english": 96, "science": 98},
    {"name": "구지연", "korean": 76, "math": 96, "english": 94, "science": 90},
    {"name": "나선주", "korean": 98, "math": 92, "english": 96, "science": 92},
    {"name": "윤아린", "korean": 95, "math": 98, "english": 98, "science": 98},
    {"name": "윤명월", "korean": 64, "math": 88, "english": 92, "science": 92}
]

# 학생을 한 명씩 반복합니다
print("이름", "총점", "평균", sep="\t")
for student in students:
    # 점수의 총합과 평균을 구합니다
    score_sum = student["korean"] + student["math"] + \
        student["english"] + student["science"]
    score_average = score_sum / 4
    # 출력합니다
    print(student["name"], score_sum, score_average, sep="\t")

-결과

👉🏻students도 '여러 학생'이라는 속성을 가진다. 따라서 이것도 객체이다

📋딕셔너리로 개체를 하나하나 만들면 실수할 가능성이 높다.

 

🖐🏻직접 해보는 손코딩2🖐🏻

# # 딕셔너리를 리턴하는 함수를 선언합니다
def create_student(name, korean, math, english, science):
    return {
        "name": name,
        "korean": korean,
        "math": math,
        "english": english,
        "science": science
    }
   
# 학생 리스트를 선언합니다
students = [
    create_student("윤인성", 87, 98, 88, 95),
    create_student("연하진", 92, 98, 96, 98),
    create_student("구지연", 76, 96, 94, 90),
    create_student("나선주", 98, 92, 96, 92),
    create_student("윤아린", 95, 98, 98, 98),
    create_student("윤명월", 64, 88, 92, 92)
]

# 학생을 한 명씩 반복합니다
print("이름", "총점", "평균", sep="\t")
for student in students:
    # 점수의 총합과 평균을 구합니다
    score_sum = student["korean"] + student["math"] +\
        student["english"] + student["science"]
    score_average = score_sum / 4
    # 출력합니다
    print(student["name"], score_sum, score_average, sep="\t")

-결과

 

🖐🏻직접 해보는 손코딩3🖐🏻

# 딕셔너리를 리턴하는 함수를 선언합니다
def create_student(name, korean, math, english, science):
    return {
        "name": name,
        "korean": korean,
        "math": math,
        "english": english,
        "science": science
    }
   
# 학생을 처리하는 함수를 선언합니다
def student_get_sum(student):
    return student["korean"] + student["math"] +\
        student["english"] + student["science"]

def student_get_average(student):
    return student_get_sum(student) / 4

def student_to_string(student):
    return "{}\t{}\t{}".format(
        student["name"],
        student_get_sum(student),
        student_get_average(student)
    )
   
# 학생 리스트를 선언합니다
students = [
    create_student("윤인성", 87, 98, 88, 95),
    create_student("연하진", 92, 98, 96, 98),
    create_student("구지연", 76, 96, 94, 90),
    create_student("나선주", 98, 92, 96, 92),
    create_student("윤아린", 95, 98, 98, 98),
    create_student("윤명월", 64, 88, 92, 92)
]

# 학생을 한 명씩 반복합니다
print("이름", "총점", "평균", sep="\t")
for student in students:
    # 출력합니다
    print(student_to_string(student))

(1~23행: 학생 객체와 관련된 부분, 25~39행: 객체를 활용하는 처리)

-결과

 

✏️클래스 선언하기

-클래스 구문

class 클래스 이름:
    클래스 내용

 

-인스턴스

인스턴스 이름(변수 이름) = 클래스 이름()

 

-클래스와 인스턴스

귀여워서 갖고왔다

👉🏻인스턴스: 클래스를 기반으로 만들어진 객체

 

🌟이를 기반으로 학생 6명을 선언해보자

# 클래스를 선언합니다
class Student:
    pass

# 학생을 선언합니다
student = Student()

# 학생 리스트를 선언합니다
students = [
    Student(),
    Student(),
    Student(),
    Student(),
    Student(),
    Student(),
]

 

✏️생성자

-클래스 이름과 같은 함수

class 클래스 이름:
    def __init__(self, 추가적인 매개변수)
        pass

-클래스 내부의 함수는 첫 번째 매개변수로 반드시 self를 입력해야 한다

📋self: 자기 자신을 나타내는 딕셔너리 / self가 가지고 있는 속성과 기능에 접근할 때는 self.<식별자> 형태

 

🌟Student 인스턴스가 생성될 때 속성이 직접 추가

# 클래스를 선언합니다
class Student:
    def __init__(self, name, korean, math, english, science):
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science

# 학생 리스트를 선언합니다
students = [
    Student("윤인성", 87, 98, 88, 95),
    Student("연하진", 92, 98, 96, 98),
    Student("구지연", 76, 96, 94, 90),
    Student("나선주", 98, 92, 96, 92),
    Student("윤아린", 95, 98, 98, 98),
    Student("윤명월", 64, 88, 92, 92)
]

# Student 인스턴스의 속성에 접근하는 방법
students[0].name
students[0].korean
students[0].math
students[0].english
students[0].science

 

✏️메소드

-클래스를 가지고 있는 함수

class 클래스 이름:
    def 메소드 이름(self, 추가적인 매개변수):
        pass

 

🖐🏻직접 해보는 손코딩🖐🏻

# 클래스를 선언합니다
class Student:
    def __init__(self, name, korean, math, english, science):
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science
   
    def get_sum(self):
        return self.korean + self.math +\
            self.english + self. science
 
    def get_average(self):
            return self.get_sum() / 4
       
    def to_string(self):
        return "{}\t{}\t{}".format(\
            self.name,\
            self.get_sum(),\
            self.get_average())

# 학생 리스트를 선언합니다
students = [
    Student("윤인성", 87, 98, 88, 95),
    Student("연하진", 92, 98, 96, 98),
    Student("구지연", 76, 96, 94, 90),
    Student("나선주", 98, 92, 96, 92),
    Student("윤아린", 95, 98, 98, 98),
    Student("윤명월", 64, 88, 92, 92)
]

# 학생을 한 명씩 반복합니다
print("이름", "총점", "평균", sep="\t")
for student in students:
    # 출력합니다
    print(student.to_string())

-결과

 

 

8-1 chapter 마무리

 

🔎핵심 포인트

-객체 지향 프로그래밍 언어는 객체를 기반으로 프로그램을 만드는 프로그래밍 언어

-추상화는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것

 

 


08-2. 클래스의 추가적인 구문
▷ 핵심 포인트 - isinstance() / 클래스 변수 / 클래스 함수 / 상속

 

 

✍🏻클래스를 사용하는 것 = 작정하고 속성과 기능을 가진 객체를 만들겠다

 

✏️어떤 클래스의 인스턴스인지 확인하기

-isinstance() 함수: 객체(인스턴스)가 어떤 클래스로부터 만들어졌는지 확인

-첫 번째 매개변수에 객체(인스턴스), 두 번째 매개변수에 클래스에 입력한다

isinstance(인스턴스, 클래스)
# 클래스를 선언합니다
class Student:
    def __init__(self):
        pass

# 학생을 선언합니다
student = Student()

# 인스턴스 확인하기
print("isinstance(student, Student):", isinstance(student, Student))

🌟코드를 실행하면 student는 Student 클래스를 기반으로 만들었으므로 True를 출력하게 된다

isinstance(student, Student): True

 

🖐🏻직접 해보는 손코딩🖐🏻

# 학생 클래스를 선언합니다
class Student:
    def study(self):
        print("공부를 합니다.")
       
# 선생님 클래스를 선언합니다
class Teacher:
    def teach(self):
        print("학생을 가르칩니다.")
       
# 교실 내부의 객체 리스트를 생성합니다
classroom = [Student(), Student(), Teacher(), Student(), Student()]

# 반복을 적용해서 적절한 함수를 호출하게 합니다
for person in classroom:
    if isinstance(person, Student):
        person.study()
    elif isinstance(person, Teacher):
        person.teach()

-결과

📋isinstance() 함수의 기능 - 하나의 리스트 내부에 여러 종류의 인스턴스가 들어 있을 때, 인스턴스들을 구분하며 속성과 기능을 사용할 때 사용한다

 

✏️특수한 이름의 메소드

__<이름>__() 형태

 

🖐🏻직접 해보는 손코딩1🖐🏻

# 클래스를 선언합니다
class Student:
    def __init__(self, name, korean, math, english, science):
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science
       
    def get_sum(self):
        return self.korean + self.math +\
            self.english + self.science
           
    def get_average(self):
        return self.get_sum() / 4
   
    def __str__(self):
        return "{}\t{}\t{}".format(
            self.name,
            self.get_sum(),
            self.get_average())

# 학생 리스트를 선언합니다
students = [
    Student("윤인성", 87, 98, 88, 95),
    Student("연하진", 92, 98, 96, 98),
    Student("구지연", 76, 96, 94, 90),
    Student("나선주", 98, 92, 96, 92),
    Student("윤아린", 95, 98, 98, 98),
    Student("윤명월", 64, 88, 92, 92)
]

# 출력합니다
print("이름", "총점", "평균", sep="\t")
for student in students:
    print(str(student))

-결과

👉🏻str() 함수의 매개변수로 넣으면 student의 __str__() 함수가 호출된다

 

-크기를 비교하는 함수들

이름 영어 설명
eq equal 같다
ne not equal 다르다
gt greater than 크다
ge greater than or equal 크거나 같다
lt less than 작다
le less than or equal 작거나 같다

👇🏻이를 활용해 학생들을 성적으로 비교하는 코드를 만들어보자

 

🖐🏻직접 해보는 손코딩2🖐🏻

# 클래스를 선언합니다
class Student:
    def __init__(self, name, korean, math, english, science):
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science
       
    def get_sum(self):
        return self.korean + self.math +\
            self.english + self.science
   
    def get_average(self):
        return self.get_sum() / 4
   
    def __str__(self):
        return "{}\t{}\t{}".format(
            self.name,
            self.get_sum(),
            self.get_average())
   
    def __eq__(self, value):
        return self.get_sum() == value.get_sum()
    def __ne__(self, value):
        return self.get_sum() != value.get_sum()
    def __gt__(self, value):
        return self.get_sum() > value.get_sum()
    def __ge__(self, value):
        return self.get_sum() >= value.get_sum()
    def __lt__(self, value):
        return self.get_sum() < value.get_sum()
    def __le____(self, value):
        return self.get_sum() <= value.get_sum()
   
# 학생 리스트를 선언합니다
students = [
    Student("윤인성", 87, 98, 88, 95),
    Student("연하진", 92, 98, 96, 98),
    Student("구지연", 76, 96, 94, 90),
    Student("나선주", 98, 92, 96, 92),
    Student("윤아린", 95, 98, 98, 98),
    Student("윤명월", 64, 88, 92, 92)
]

# 학생을 선언합니다
student_a = Student("윤인성", 87, 98, 88, 95),
student_b = Student("연하진", 92, 98, 96, 98),

# 출력합니다
print("student_a == student_b=", student_a == student_b)
print("student_a !+ student_b=", student_a != student_b)
print("student_a > student_b=", student_a > student_b)
print("student_a >= student_b=", student_a >= student_b)
print("student_a < student_b=", student_a < student_b)
print("student_a <= student_b=", student_a <= student_b)

-결과

 

✏️클래스 변수와 메소드

-클래스가 가지는 속성과 기능은 변수와 함수

 

👻클래스 변수

-클래스 변수는 class 구문 바로 아래 단계에 변수를 선언하면 된다. 사용 방법은 일반 변수와 다르지 않다.

 

🌟클래스 변수 만들기

class 클래스 이름:
    클래스 변수 =

🌟클래스 변수에 접근하기

클래스 이름.변수 이름

 

🖐🏻직접 해보는 손코딩🖐🏻

# 클래스를 선언합니다
class Student:
    count = 0
   
    def __init__(self, name, korean, math, english, science):
        # 인스턴스 변수 초기화
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science
       
        # 클래스 변수 설정
        Student.count += 1
        print("{}번째 학생이 생성되었습니다.".format(Student.count))
       
# 학생 리스트를 선언합니다
student = [
    Student("윤인성", 87, 98, 88, 95),
    Student("연하진", 92, 98, 96, 98),
    Student("구지연", 76, 96, 94, 90),
    Student("나선주", 98, 92, 96, 92),
    Student("윤아린", 95, 98, 98, 98),
    Student("윤명월", 64, 88, 92, 92)
]

# 출력합니다
print()
print("현재 생성된 총 학생 수는 {}명 입니다.".format(Student.count))

-결과

 

👻클래스 함수

-앞의 클래스 변수처럼 그냥 클래스가 가진 함수

👉🏻생성 방법: @classmethod (데코레이터)

 

🌟클래스 함수 만들기

class 클래스 이름:
    @classmethod
    def 클래스 함수(cls, 매개변수):
        pass

👉🏻관례적으로 cls(클래스)라는 이름의 변수로 선언한다

 

🌟클래스 함수 호출하기

클래스 이름.함수 이름(매개변수)

 

🖐🏻직접 해보는 손코딩🖐🏻

#  클래스를 선언합니다
class Student:
    # 클래스 변수
    count = 0
    students = []
   
    # 클래스 함수
    @classmethod
    def print(cls):
        print("----- 학생 목록 -----")
        print("이름\t총점\t평균")
        for student in cls.students:
            print(str(student))
        print("------ ------ ------")
       
    # 인스턴스 함수
    def __init__(self, name, korean, math, english, science):
        # 인스턴스 변수 초기화
        self.name = name
        self.korean = korean
        self.math = math
        self.english = english
        self.science = science
        Student.count += 1
        Student.students.append(self)
       
    def get_sum(self):
        return self.korean + self.math +\
            self.english + self.science
           
    def get_average(self):
        return self.get_sum() / 4
   
    def __str__(self):
        return "{}\t{}\t{}".format(\
            self.name,\
            self.get_sum(),\
            self.get_average())
       
# 학생 리스트를 선언합니다
Student("윤인성", 87, 98, 88, 95)
Student("연하진", 92, 98, 96, 98)
Student("구지연", 76, 96, 94, 90)
Student("나선주", 98, 92, 96, 92)
Student("윤아린", 95, 98, 98, 98)
Student("윤명월", 64, 88, 92, 92)
Student("김미화", 82, 86, 98, 88)
Student("김연화", 88, 74, 78, 92)
Student("박아현", 97, 92, 88, 95)
Student("서준서", 45, 52, 72, 78)

# 현재 생성된 학생들을 모두 출력합니다
Student.print()

-결과

와!

 


가비지 컬렉터

 

-프로그램에서 변수를 계속 만들다 보면 메모리가 가득 차 버린다. 가비지 컬렉터는 더 사용할 가능성이 없는 데이터를 메모리에서 제거하는 역할을 한다

-더 사용할 가능성이 없는 데이터: 변수에 저장되지 않거나, 함수 등에서 나오면서 변수를 활용할 수 없게 되는 경우의 데이터

 

🖐🏻직접 해보는 손코딩🖐🏻

class Test:
    def __init__(self, name):
        self.name = name
        print("{} - 생성되었습니다".format(self.name))
    def __del__(self):
        print("{} - 파괴되었습니다".format(self.name))
       
Test("A")
Test("B")
Test("C")

-결과

👉🏻A가 생성되고 다음 줄로 넘어갈 때 이것을 변수에 저장하지 않으면 가비지 컬렉터는 이후에 활용하지 않겠다는 의미로 이해하고 메모리를 아끼기 위해 지워버린다. 이러한 과정의 반복으로 A 생성, A 파괴, B 생성, B 파괴, C 생성, C 파괴 과정이 진행된다

그렇다면 이제 변수에 데이터를 넣어보자

 

🖐🏻직접 해보는 손코딩🖐🏻

class Test:
    def __init__(self, name):
        self.name = name
        print("{} - 생성되었습니다.".format(self.name))
    def __del__(self):
        print("{} - 파괴되었습니다.".format(self.name))
       
a = Test("A")
b = Test("B")
c = Test("C")

-결과

👉🏻변수에 저장했으면 나중에 활용하겠다는 의미로 받아들이고 프로그램이 종료되는 순간까지 데이터를 메모리에서 제거하지 않는다. 따라서 A 생성, B 생성, C 생성, A 파괴, B 파괴, C 파괴 과정이 진행된다

 

 

프라이빗 변수와 게터/세터

 

🖐🏻직접 해보는 손코딩🖐🏻

-원의 둘레와 넓이를 구하는 객체 지향 프로그램

# 모듈을 가져옵니다
import math

# 클래스를 선언합니다
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def get_circumference(self):
        return 2 * math.pi * self.radius
    def get_area(self):
        return math.pi * (self.radius ** 2)
   
# 원의 둘레와 넓이를 구합니다
circle = Circle(10)
print("원의 둘레:", circle.get_circumference())
print("원의 넓이:", circle.get_area())

-결과

 

만약 Circle 클래스의 radius 속성에

Circle.radius = -2

와 같이 음수가 들어가면 어떻게 될까?

넓이는 제곱이라 괜찮지만 둘레는 음수가 나온다. 따라서 길이를 음수로 넣는 것을 막는 방법이 필요하다

 

🌟프라이빗 변수

-클래스 내부의 변수를 외부에서 사용하는 것을 막고 싶을 때는 인스턴스 변수 이름을 다음과 같은 형태로 선언한다

__<변수 이름>

 

🖐🏻직접 해보는 손코딩🖐🏻

# 모듈을 가져옵니다
import math

# 클래스를 선언합니다
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def get_circumference(self):
        return 2 * math.pi * self.radius
    def get_area(self):
        return math.pi * (self.radius ** 2)
   
# 원의 둘레와 넓이를 구합니다
circle = Circle(10)
print("# 원의 둘레와 넓이를 구합니다")
print("원의 둘레:", circle.get_circumference())
print("원의 넓이:", circle.get_area())
print()

# __raidus에 접근합니다
print("# __radius에 접근합니다")
print(circle.__radius)

-결과

👉🏻클래스 내부에서 __radius를 사용하는 것은 괜찮지만, 외부에서 사용하려고 할 때는 그런 속성이 없다는 오류를 출력한다

📋이처럼 속성을 선언할 때 앞에 __를 붙이면 외부에서 사용할 수 없는 변수가 된다

 

🌟게터와 세터

-중간에 원의 둘레를 변경하고 싶을 때, 클래스 외부에서 직접 __radius 속성에 접근할 수 없기 때문에 간접적으로 접근해야 한다

-게터와 세터: 이 때 게터와 세터는 프라이빗 변수의 값을 추출하거나 변경할 목적으로, 간접적을 속성에 접근하도록 해주는 함수

 

🖐🏻직접 해보는 손코딩🖐🏻

# 모듈을 가져옵니다
import math

# 클래스를 선언합니다
class Circle:
    def __init__(self, radius):
        self.__radius = radius
    def get_circumference(self):
        return 2 * math.pi * self.__radius
    def get_area(self):
        return math.pi * (self.__radius ** 2)
   
    # 게터와 세터를 선언합니다
    def get_radius(self):
        return self.__radius
    def set_radius(self, value):
        self.__radius = value
   
# 원의 둘레와 넓이를 구합니다
circle = Circle(10)
print("# 원의 둘레와 넓이를 구합니다")
print("원의 둘레:", circle.get_circumference())
print("원의 넓이:", circle.get_area())
print()

# 간접적으로 __raidus에 접근합니다
print("# __radius에 접근합니다")
print(circle.get_radius())
print()

# 원의 둘레와 넓이를 구합니다
circle = Circle(2)
print("# 원의 둘레와 넓이를 구합니다")
print("원의 둘레:", circle.get_circumference())
print("원의 넓이:", circle.get_area())

-결과

 

<게터와 세터로 변수를 안전하게 사용하기>

def set_radius(self, value):
    if value <= 0:
        raise TypeError("길이는 양의 숫자여야 합니다.")
    self.__radius = value

 

🌟데코레이터를 사용한 게터와 세터

-게터와 세터를 쉽게 만드는 방법

-변수 이름과 같은 함수를 정의하고 위에 @property와 @<게터 함수 이름>.setter 데코레이터 붙이기

 

🖐🏻직접 해보는 손코딩🖐🏻

# 모듈을 가져옵니다
import math

# 클래스를 선언합니다
class Circle:
    def __init__(self, radius):
        self.__radius = radius
    def get_circumference(self):
        return 2 * math.pi * self.__radius
    def get_area(self):
        return math.pi * (self.__radius ** 2)
   
    # 게터와 세터를 선언합니다
    @property
    def radius(self):
        return self.__radius
    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise TypeError("길이는 양의 숫자여야 합니다.")
        self.__radius = value
       
# 원의 둘레와 넓이를 구합니다
print("# 데코레이터를 사용한 getter와 setter")
circle = Circle(10)
print("원래 원의 반지름:", circle.radius)
circle.radius = 2
print("변경된 원의 반지름:", circle.radius)
print()

# 강제로 예외를 발생시킵니다
print("# 강제로 예외를 발생시킵니다")
circle.radius = -10

-결과

 

 

상속

 

  • 상속: 누군가가 만들어놓은 기본 형태에 내가 원하는 것만 추가하거나 교체하는 것
  • 다중 상속: 다른 누군가가 만들어 놓은 형태들을 조립해서 내가 원하는 것을 만드는 것

 

상속은 다음과 같이 한다

 

🖐🏻직접 해보는 손코딩🖐🏻

# 부모 클래스를 선언합니다
class Parent:
    def __init__(self):
        self.value = "테스트"
        print("Parent 클래스의 __init()__ 메소드가 호출되었습니다.")
    def test(self):
        print("Parent 클래스의 test() 메소드입니다.")
       
# 자식 클래스를 선언합니다
class Child(Parent):
    def __init__(self):
        super().__init__() # 부모의 __init__() 함수를 호출합니다
        print("Child 클래스의 __init()__ 메소드가 호출되었습니다.")
       
# 자식 클래스의 인스턴스를 생성하고 부모의 메소드를 호출합니다.
child = Child()
child.test()
print(child.value)

(전체가 상속하는 구문이므로 상속을 활용하고자 한다면 모두 외워야 한다)

-결과

 

🌟예외 클래스 만들기

-사용자 정의 예외 클래스 만들기

class CustomException(Exception):
    def __init__(self):
        super().__init__()
       
raise CustomException

 

여기에 __init__() 내부에서 간단한 출력을 해보게 하고 __str__() 함수를 만들어 원하는 형태로 수정한다

 

class CustomException(Exception):
    def __init__(self):
        super().__init__()
        print("##### 내가 만든 오류가 생성되었어요! #####")
    def __str__(self):
        return "오류가 발생했어요"
       
raise CustomException

 

+) 기존에 있던 함수/변수 이외의 것을 완전히 새로 정의하는 것도 가능하다

class CustomException(Exception):
    def __init__(self, message, value):
        super().__init__()
        self.message = message
        self.value = value
       
    def __str__(self):
        return self.message
   
    def print(self):
        print("##### 오류정보 #####")
        print("메시지:", self.message)
        print("값:", self.value)
       
# 예외를 발생시켜 봅니다
try:
    raise CustomException("딱히 이유 없음", 273)
except CustomException as e:
    e.print()

 


 

8-2 chapter 마무리

 

🔎핵심 포인트

-isinstance() 함수는 어떤 클래스의 인스턴스인지 확인할 때 사용하는 함수

-클래스 변수 클래스 함수는 클래스 이름 뒤에 .(마침표)를 찍고 바로 사용할 수 있는 클래스가 갖고 있는 변수와 함수

-상속은 어떤 클래스를 기반으로 그 속성과 기능을 물려받아 새로운 클래스를 만드는 것

 

 


기본미션

Q) BeautifulSoup 스크레이핑 예제 실행 후 결과

# 모듈을 읽어들입니다
from flask import Flask
from urllib import request
from bs4 import BeautifulSoup

# 웹 서버를 생성합니다
app = Flask(__name__)
@app.route("/")

def hello():
    # urlopen() 함수로 기상청의 전국 날씨를 읽습니다
   
    # BeautifulSoup를 사용해 웹 페이지를 분석합니다
    soup = BeautifulSoup(target, "html.parser")
   
    # location 태그를 찾습니다
    output = ""
    for location in soup.select("location"):
        # 내부의 city, wf, tmn, tmx 태그를 찾아 출력합니다
        output += "<h3>{}</h3>".format(location.select_one("city").string)
        output += "날씨: {}<br/>".format(location.select_one("wf").string)
        output += "최저/최고 기온: {}/{}"\
            .format(\
                location.select_one("tmn").string,\
                location.select_one("tmx").string\
            )
        output += "<hr/>"
    return output

app.run()

 

선택미션

Q) 객체, 클래스, 인스턴스, 생성자, 메소드 정리

객체 속성을 가질 수 있는 모든 것
클래스 객체를 쉽고 편리하게 생성하기 위해 만들어진 구문
인스턴스 클래스를 기반으로 생성한 객체
생성자 클래스 이름과 같은 인스턴스를 생성할 때 사용하는 함수
메소드 클래스가 가진 함수

 


+) 마지막까지 공부 클리어 !!!! 6주동안 달려온 나 수고 많았숴 😋

이제 혼공단 11기 회고록 쓰러 가야겠다 희희 💨💨💨

 

 

'코딩 공부 > 파이썬 (혼공단 11기)' 카테고리의 다른 글

혼공단 11기 활동 회고록🚩  (0) 2024.02.16
[혼공파] 5주차_06 ~ 07-1  (0) 2024.02.01
[혼공파] 4주차_05  (0) 2024.01.24
[혼공파] 3주차_04  (0) 2024.01.21
[혼공파] 2주차_02-3 ~ 03  (0) 2024.01.12