no image
Day10. REST API
1. 웹 서비스를 구현하는 방식 서버 사이드 랜더링 클라이언트(웹 브라우저)의 요청을 서버가 받아서 처리한 후 서버가 출력하는 코드를 만들어서 클라이언트에게 전송을 하고 클라이언트는 이 코드를 받아서 파싱해서 출력하는 방식 서버 코드 와 클라이언트 코드를 하나의 프로젝트에 전부 작성 서버 코드를 수정할 때 클라이언트 코드가 영향을 받을 수 있고 클라이언트 코드를 수정할 때 서버 코드가 영향을 받을 수 있습니다. 이 방식으로 서비스를 만들려면 템플릿 언어라는 것을 학습을 해야 합니다. 최근에는 이 방식을 선호하지 않습니다. 클라이언트 사이드 랜더링 서버는 클라이언트 요청을 받아서 데이터(XML -> JSON)를 응답으로 전송하고 클라이언트는 응답을 받아서 직접 데이터를 해석해서 출력하는 코드를 만들고 화면..
2024.01.26
no image
Day9. 웹 서버 만들기
전송 방식 GET: 데이터를 가져올 때 사용하는 방식으로 파라미터가 URL에 노출 POST: 데이터를 삽입할 때 사용하는 방식으로 파라미터가 URL에 노출되지 않음 PUT: 데이터 수정 - 데이터 전체를 수정 PATCH: 데이터 수정 - 데이터의 일부 속성을 수정, 멱등성이 없다고 권장하지 않음 DELETE: 데이터 삭제 상태 코드: 서버가 클라이언트에게 응답을 전송할 때 응답에 대한 상태를 나타내는 코드로 3자리 1XX: 요청이 수신되었으며 프로세스 진행 중 2XX: 성공적으로 처리 됨 3XX: 리다이렉션 중 4XX: 클라이언트 오류, 404 - URL이 잘못됨 5XX: 서버 오류 Python의 Web Framework Flask: 자유도가 높음, 구현해주는 것이 거의 없음, 적은 코드로 웹 서버를 만..
2024.01.24
no image
Day8. 가상환경 만들기
파이썬 애플리케이션 작성 가상 환경을 만들어서 작성 가상 환경: 별도의 파이썬 환경을 생성 외부 라이브러리를 설치해서 만든 애플리케이션은 다른곳에서 실행하려면 개발한 환경과 동일한 환경을 만들어야 하고, 컴퓨터에 있는 외부 라이브러리도 전부 설치를 해줘야 한다. 그런데 가상환경을 만들면 필요한 라이브러리만 별도로 다운로드 받아서 가져갈 수 있다. 파이썬 A 라이브러리 B 라이브러리 C 라이브러리 추가 D 라이브러리 추가 1번 프로그램을 만들 때 C를 추가: A, B, C 2번 프로그램을 만들 때 D를 추가: A, B, D 3번 프로그램을 만들 때 나만의 환경을 생성: A, B, X X 라이브러리 사용 가상환경 만들기 #가상환경 생성 python -m venv #디렉토리가 만들어짐 #디렉토리 가상환경으로 ..
2024.01.19
no image
Day7. 웹프로그래밍 개요
개요 Application - Program - Service All Same. 복잡하거나 반복되는 일을 컴퓨터가 할 수 있도록 만든 것 1) 컴퓨터 하드웨어: 실제 장비 하드웨어는 기계어만 인식 소프트웨어: 실제 장비를 코드로 사용할 수 있도록 추상화한 것 운영체제: 하드웨어와 소프트웨어 사이의 인터페이스(통역) 대부분 어셈블러(어셈블리어를 기계어로 번역)와 C언어로 만든다. 그러나 C언어는 플랫폼에서 독립적이지 못하다. 맥용 윈도우용 두개씩 만들어야 함. 플랫폼에서 독립적인 고급언어가 나와서 Python, Java. Python은 C로 다시 바꿔줘야 해서 느리다. (우리가 쓰는 건 C-Python) 컴퓨터와 운영체제를 같이 쓰는게 아니라, 내가 운영체제를 선택하고 싶어져서 Unix 대신 만든게 Lin..
2024.01.18
no image
Day6. 객체지향 프로그래밍
함수형 프로그래밍 기능 단위로 작성 유사한 동작을 하는 함수들은 파일로 묶어서 구분 일반적으로 속도가 빠르고 불필요한 내용을 포함하지 않는 것이 장점 빅데이터 처리 분야에서 많이 사용 객체 지향 프로그래밍 유사한 동작을 하는 함수나 데이터를 하나로 묶어서 프로그래밍 하는 방식 유사한 동작을 하는 함수와 데이터를 클래스라는 템플릿으로 묶고 템플릿을 이용해서 인스턴스를 생성해서 사용하는 방식으로 클래스도 하나의 인스턴스로 취급 클래스와 인스턴스 인스턴스 만들기: 메모리에 인스턴스를 생성하고 인스턴스의 참조(id)를 리턴 한번만 쓸거면 클래스이름(매개변수 나열...) 여러번 쓸거면 obj = 클래스이름(매개변수 나열...) 인스턴스를 생성하고 참조하는 데이터가 없다면 언제인지는 알 수 없지만 자동으로 메모리가..
2024.01.16
no image
Day5. 함수
A. 함수의 정의와 호출 함수는 한마디로 호출의 집합이다. def 함수 이름(): 문장 def print_n_times(value, n): for i in range(n): print(value) print_n_times("안녕하세요", 5) 안녕하세요 안녕하세요 안녕하세요 안녕하세요 안녕하세요 가변 매개변수 매개변수를 원하는 만큼 입력할 수 있는 함수 (매개변수의 개수가 변할 수 있다.) 가변 매개변수 뒤에는 일반 매개변수가 올 수 없다. 가변 매개변수는 하나만 사용할 수 있다. def print_n_times(n, *values): #n번 반복합니다. for i in range(n): #values는 리스트처럼 활용합니다. for value in values: print(value) print() p..
2024.01.08
no image
Day4. 딕셔너리와 반복문
A. 딕셔너리 리스트가 '인덱스'를 기반으로 값을 저장하는 것이라면, 딕셔너리는 '키(Key)'를 기반으로 값을 저장하는 것이다. 대괄호[ ]를 입력하고 내부에 인덱스처럼 키를 입력한다. 참조할 때 리스트와 딕셔너리 차이 리스트 list_a = [] list_a[1] 딕셔너리 dict_a = {} dict_a["key"] 모든 연속형 자료형의 중추는 리스트, 딕셔너리는 편집 가능한 리스트다. in 키워드 딕셔너리 내부에 키가 있는지 없는지 확인한다. dictionary = { "name": "야채", "age": 24, "character": "활달함", "nation": "한국" } #입력 key = input("접근하려는 키: ") if key in dictionary: print(dictionary..
2024.01.05
no image
Day3. 조건문과 리스트
* 새롭게 배운 내용만 적었습니다. 교재는 '혼자 공부하는 파이썬 A. If 조건문 끝자리로 짝수와 홀수 구분 number = input("정수 입력> ") last_character = number[-1] last_number = int(last_character) if last_number == 0 \ or last_number == 2 \ or last_number == 4 \ or last_number == 6 \ or last_number == 8: print("짝수입니다") if last_number == 1 \ or last_number == 3 \ or last_number == 5 \ or last_number == 7 \ or last_number == 9: print("홀수입니다") ..
2024.01.04

Day10. REST API

0ㅑ채
|2024. 1. 26. 17:42

1. 웹 서비스를 구현하는 방식

서버 사이드 랜더링

  • 클라이언트(웹 브라우저)의 요청을 서버가 받아서 처리한 후 서버가 출력하는 코드를 만들어서 클라이언트에게 전송을 하고 클라이언트는 이 코드를 받아서 파싱해서 출력하는 방식
  • 서버 코드 와 클라이언트 코드를 하나의 프로젝트에 전부 작성
  • 서버 코드를 수정할 때 클라이언트 코드가 영향을 받을 수 있고 클라이언트 코드를 수정할 때 서버 코드가 영향을 받을 수 있습니다.
  • 이 방식으로 서비스를 만들려면 템플릿 언어라는 것을 학습을 해야 합니다.
  • 최근에는 이 방식을 선호하지 않습니다.

 

클라이언트 사이드 랜더링

  • 서버는 클라이언트 요청을 받아서 데이터(XML -> JSON)를 응답으로 전송하고 클라이언트는 응답을 받아서 직접 데이터를 해석해서 출력하는 코드를 만들고 화면에 랜더링하는 방식입니다.
  • 이 방식에서는 서버 프로그램(Python의 Django, Java의 Spring, JavaScript의 express.js 등) 과 클라이언트 프로그램(vue.js, react.js->next.js, android-java 나 kotlin, ios-swift, 플로터-dart 등) 을 별도로 작성합니다.
  • 서버 코드 가 클라이언트 코드에 영향을 주지 않고 클라이언트 코드가 서버 코드에 영향을 주지 않습니다.
  • 이렇게 통신만으로 서로 연동되는 경우를 느슨한 결합(loosly coupling)이라고 합니다.
  • 최근에는 프로그램에 유지보수가 자주 발생하므로 이러한 느슨한 결합의 형태로 프로그램을 만들기를 권장합니다.


    프로그래밍 언어에서의 객체
 {name:"아담", age:53} - dict
 
 person = Person()
 person.name = "아담"
 person.age = 53

 

일반 테스트

  • 아담 53
  • 군계일학 47

tsv - 탭으로 구분

  • 아담  53
  • 군계일학  47

csv - 콤마로 구분

  • 이름,나이
  • 아담,53
  • 군계일학,47



XML(eXtensible Markup Language)

  • 데이터를 태그로 표현, 현재는 일부 RSS 서비스에서 사용이되고 설정 파일에서 많이 이용
	<persons>	
		<person>
			<name>아담</name>
			<age v="53" />
		</person>
		<person>
			<name>군계</name>
			<age v="52"></age>
		</person>
	</persons>



JSON(JavaScript Object Notation)

  • 자바스크립트 객체 표현법: 파이썬 과 동일): 최근에 데이터 교환에 가장 많이 사용, 모바일은 거의 대부분 이 방식
#객체:{ }
#배열:[ ]

[{"name":"아담", "age":53}, {"name":"군계", "age":52}]



YAML

  • 이메일 표현 방식을 이용해서 데이터를 표현, 최근에 설정에 많이 이용
person:
name: 아담
age: 53
person:
name: 군계
age: 52



 

 

2. REST 6가지 제약 조건

Representational State Transfer의 약자로 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식

별도의 전송 계층 없이 간단한 인터페이스로 자원을 정의하는 방식

 

1) Client-Server 구조

 

2) Stateless

  • 무상태, 이전에 했던 작업에 대한 내역을 가지고 있지 않다. 
  • 무상태란,
더보기
서버 <----------------> 클라이어트
<- 요청에 대한 응답이 가능한지 요청을 전송
응답 여부를 전송(메타 데이터를 전송) ->
<- 요청 처리
응답 전송 ->
<- 응답에 대한 결과 전송

 

기본적인 통신 방법으로는 한번 로그인한 정보를 계속 기억할 수가 없다. 

그래서 

서버 쪽에는 Session을 두고, 클라이언트 쪽에는 Cookie를 둔다. 

Sesion: 클라이언트의 정보를 서버에 저장, 연결이 끊어지면 자동 소멸

Cookie: 클라이언트의 정보를 클라이언트에 저장한 후 서버에 요청할 때마다 전송 (토큰이라고도 한다.), 연결이 끊어져도 계속 있어서 클라이언트 혹은 서버가 지울 때까지 있음. 

 

무상태란, 이런 Session과 Cookie를 저장하지 않겠다는 뜻!

 

장점: 번거로운 절차가 없다. 

단점: 똑같은 일을 매번 할 때 귀찮다. 그럴 때는 임시 패찰을 준다. 그걸 캐싱이라고 함!

 

3) Cacheable Data

 

4) Layered System

  • 여러 개의 계층으로 나누어서 서비스가 가능
더보기

 

* A/B테스트: 목적은 같지만 구현 방식이 다른 두개를 테스트하여 더 좋은 것을 결정

 

5) A Uniform Interface

  • 인터페이스가 일관성이 있어야 한다.

- 아이템을 가져오는 URL -  http://www,adamsoft.co.kr/item/get

- 아이템을 추가하는 URL -  http://www,adamsoft.co.kr/item/insert

- 아이템을 수정하는 URL -  http://www,adamsoft.co.kr/update    #이런 식이면 안돼욧!

 

6) Code-On-Demand

  • 선택적 사항으로 클라이언트는 서버에 코드를 요청할 수 있고, 서버가 리턴한 코드를 클라이언트에서 실행할 수 있다. 

 

제약조건을 지켜서 만든 서버, RESTful 하네!

 

 

3. django에서 REST API Server를 구현하기 위한 방법

- views에서 JsonResponse를 리턴하는 방식

  • 테스트를 하고자 하면 클라이언트를 구현하거나 테스트 도구를 사용해야 한다.

- djangorestframework라는 패키지를 이용하는 방식: 자체 테스트가 가능

  • 일관성이 없다.

 

1) 프로젝트와 앱을 생성하고 기본 설정 후 테스트

가상환경 생성

python -m venv myvenv
myvenv\Scripts\activate
pip install django djangorestframework, mysqlclient
  • 만약 안되면 앞에 python -m을 붙여보자

 

프로젝트 생성

django-admin startproject apiproject

 

애플리케이션 생성

python manage.py startapp apiapp

 

기본 설정 변경: 프로젝트의 settings.py

INSTALLED_APPS = [
    ...
    "apiapp", #나의 애플리케이션 이름
    "rest_framework", 
]

 

데이터베이스 접속 정보 수정

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
        "USER": "root",
        "PASSWORD":"0000",
        "HOST":"127.0.0.1",
        "PORT":"3306"        
    }
}

 

시간 대역 수정

TIME_ZONE = "Asia/Seoul"

 

변경 내용 데이터베이스에 저장

python manage.py makemigrations
python manage.py migrate

  • 이전에 적용한 내용과 차이가 없다. 오류 아님!!

 

 

 

2) 요청 처리

- 요청을 분할해서 처리

지금까지는 모든 요청 처리를 프로젝트의 urls.py에 작성해서 사용했다.

요청이 많아지면 프로젝트의 urls.py 파일의 내용이 많아지고 한 곳에 내용이 많아지면 소스 코드를 읽기가 어려워지고, 읽기가 어려워지면 유지보수가 어렵고, 여러 명이 동시에 작업하기 어렵다.

 

URL 요청을 분할해서 처리할 때는 프로젝트의 urls.py 파일에 django.urls.include를 import하고 

path("공통url", include("처리할 모듈 이름"))를 추가해주면 된다.

 

 

3) ret api 작업 ㅡ프로젝트 가져오기

레포지토리 주소

myvenv\Scripts\activate
pip install -r requirements.txt 
#혹은 python -m pip install -r requirements.txt
from django.urls import include
  • url의 처리를 다른 모듈에게 위임하고자 할 때 사용하는 패키지를 import
urlpatterns = [
    path("admin/", admin.site.urls),
    path("example/", include("apiapp.urls")),
]
  • example로 시작하는 요청이 오면 apiapp 애플리케이션의 urls.py 파일에 처리를 위임

 

example/hello 라는 요청이 오면 메세지를 출력하는 처리 작성

- apiapp.views.py 파일에 요청이 오면 처리하는 함수를 작성

#화면 안만들어서 render 필요 없음
from rest_framework.response import Response
from rest_framework.decorators import api_view

#GET 요청이 오면 함수를 호출
@api_view(['GET'])
def hello(request):
    return Response("Hello REST API")
  • python에서 @으로 시작하는 단어는 decorator라고 하는데 
  • 실제 함수를 호출하기 전에 특정 내용을 삽입해서 함수를 실행한다. 
  • 그래서 반복적으로 사용하는 내용이나 직접 작성하기 번거로운 내용을 decorator로 만든다.

 

앱(apiapp) 디렉토리에 urls.py 파일을 생성하고 url을 연결하는 코드를 작성

from django.urls import path
from .views import hello

urlpatterns = [
    path("hello/", hello),
]

 

서버를 구동하고 127.0.0.1/example/hello 요청 전송하고 결과 확인

 

 

 

5) 데이터베이스에 테이블을 생성

models.py 파일에 Model 클래스로부터 상속받는 클래스를 생성

 

변경 내용 데이터베이스에 반영

python manage.py makemigrations
python manage.py migrate

 

데이터베이스에서 apiapp_book 테이블 만들어졌는지 확인

show tables;

 

 

 

6) 삽입과 조회

삽입하는 방법

  • 클라이언트가 삽입할 데이터를 매개변수로 전송하면
  • 서버는 매개변수를 각각 읽어서 모델 클래스로 변환한 후
  • save 메서드를 호출
  • rest_framework 에서는 serializer를 정의하면 클라이언트가 전송한 매개변수를 가지고 모델 클래스로 자동 변환이 가능

 

apiapp 디렉토리에 serializers.py 파일을 만들고 클라이언트의 매개변수를 Book

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        #클라이언트에서 입력할 데이터만 나열
        #아래 나열한 데이터를 입력하면 Book 클래스의 인스턴스를 자동 생성
        fields = ['bid', 'title', 'author', 'publisheddate']

 

데이터 삽입(POST) 처리와 전체 조회(GET)하는 처리를 views.py 파일에 작성

from rest_framework import status
from rest_framework.generics import get_object_or_404
from .models import Book
from .serializers import BookSerializer

@api_view(['GET', 'POST'])
def booksAPI(request):
    #GET 방식의 처리 - 조회를 요청하는 경우
    if request.method == 'GET':
        #테이블의 데이터를 전부 가져오기
        books = Book.objects.all()
        #출력하기 위해서 브라우저의 형식으로 데이터를 변환
        serializer = BookSerializer(books, many=True)
        #출력
        return Response(serializer.data)
        
    #POST 방식의 처리 - 삽입하는 경우
    elif request.method == 'POST':
        serializer = BookSerializer(data = request.data)
        serializer.save()
        return Response(serializer.data)

 

apiapp 디렉토리의 urls.py 파일에 url과 이전에 만든 함수를 연결

from django.urls import path
from .views import hello, booksAPI

urlpatterns = [
    path("hello/", hello),
    path("books/", booksAPI),
]

 

서버를 구동하고 브라우저에 127.0.0.1

 

데이터를 삽입할 때 에러가 발생

rest_framework를 사용할 때는 데이터를 save할 때 is_valid()를 호출해서 유효성 검사에 통과했을 때만 삽입되도록 해야 함. 

 

...
    elif request.method == 'POST':
    
        #클라이언트에서 전송된 데이터를 가지고 Model 인스턴스 생성
        serializer = BookSerializer(data = request.data)
        
        #유효성 검사를 수행해서 통과하면 삽입, 실패하면 이유 출력
        if serializer.is_vallid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors)

  • bid는 프라이머리 키기 떄문에, bid에 똑같은 정보를 입력하면

 

 

 

7) 데이터 1개 가져오기

데이터 1개를 가져오려면 클라이언트에서 기본키 값을 서버에 제공해야 하고 

서버는 이 값을 읽어서 하나의 데이터를 찾아 넘겨줘야 한다.

 

views.py 

@api_view(['GET'])
def oneBookAPI(request, bid):
    #Book 테이블에서 bid 컬럼의 값이 bid인 값을 찾아온다. 
    book = get_object_or_404(Book, bid=bid)
    #출력할 수 있도록 변환
    serializer = BookSerializer(book)
    return Response(serializer.data)

 

 

urls.py

from django.urls import path
from .views import hello, booksAPI, oneBookAPI

urlpatterns = [
    ...
    path("onebook/<int:bid>", oneBookAPI),
]

 

🔍 http://127.0.0.1/example/onebook/1

  • 만약 없는 데이터를 찾으면

 

 

 

 

복습!!

더보기

git url: https://github.com/ggangpae1/djangofirst 

 

1. 프로젝트 clone

2. 가상환경 들어가기

3. 패키지 설치

4. setting 변경

5. 수정한 데이터베이스 내용 변경

6. 서버 실행

7. 내 깃에 업로드

'Python' 카테고리의 다른 글

[Python] Pandas  (1) 2024.02.08
[Python] Numpy  (0) 2024.02.06
Day9. 웹 서버 만들기  (1) 2024.01.24
Day8. 가상환경 만들기  (1) 2024.01.19
Day7. 웹프로그래밍 개요  (1) 2024.01.18

Day9. 웹 서버 만들기

0ㅑ채
|2024. 1. 24. 19:18

 

전송 방식

  • GET: 데이터를 가져올 때 사용하는 방식으로 파라미터가 URL에 노출
  • POST: 데이터를 삽입할 때 사용하는 방식으로 파라미터가 URL에 노출되지 않음
  • PUT: 데이터 수정 - 데이터 전체를 수정
  • PATCH: 데이터 수정 - 데이터의 일부 속성을 수정, 멱등성이 없다고 권장하지 않음
  • DELETE: 데이터 삭제

 

상태 코드: 서버가 클라이언트에게 응답을 전송할 때 응답에 대한 상태를 나타내는 코드로 3자리

  • 1XX: 요청이 수신되었으며 프로세스 진행 중
  • 2XX: 성공적으로 처리 됨
  • 3XX: 리다이렉션 중
  • 4XX: 클라이언트 오류, 404 - URL이 잘못됨
  • 5XX: 서버 오류

 

Python의 Web Framework

  • Flask: 자유도가 높음, 구현해주는 것이 거의 없음, 적은 코드로 웹 서버를 만들 수 있음, 복잡한 애플리케이션을 만들 대 구현할 내용이 많음
  • Fast API: REST API를 빠르게 만들기 위해서 등장한 프레임워크
  • Django: 자유도가 낮음, 구현해주는 것이 많음, 복잡한 애플리케이션이더라도 구현해야 할 코드가 적음, 학습을 많이해야 하고 자유도가 낮음

 

 

1. Django 개요

1) 패키지 이름: django

pip install django
  • 가상환경에서 설치하면 가상환경에서만 사용할 수 있고 가상환경이 아닌 곳에서 설치하면 가상환경에서는 사용할 수 없습니다.

 

2) 개발 방식 -MTV

  • Model: 데이터 처리 관련 부분
  • Template: 출력 관련 부분
    • 최근에는 이 영역은 거의 사용하지 않음
    • 요즈음은 서버가 아니라 클라이언트 사이드에서 랜더링함
    • 서버 애플리케이션과 클라이언트 애플리케이션 별도로 제작
    • 서버가 처리한 후 결과를 만들어서 클라이언트에게 전송하고 클라이언트가 이 데이터를 이용해서 출력 코드를 만들어 출력
  • View: 클라이언트의 요청을 처리하는 부분
  • Controller: 사용자의 요청 과 처리하는 부분(Business Logic 과 Common Concern)을 연결해주는 것


3) 가상환경을 이용해서 django 프로젝트를 만들고 실행

가상 환경 생성

python -m venv 가상환경이름

*python3이라고 쳐야할 수도!

  • 가상환경 디렉토리가 만들어지고, 그 안에 3개의 디렉토리가 만들어진다.

가상 환경 활성화

가상환경이름\Scripts\activate

가상환경에 들어온 것이다.

 

가상 환경에 django 설치

pip install django

 

프로젝트 생성: django 작업의 기본 단위로 1개를 생성

django-admin startproject 프로젝트이름 생성할디렉토리경로
#생성할 디렉토리경로 (.)를 입력하면 현재 디렉토리

django-admin startproject myproject .
  • 성공을 하면 현재 디렉토리에 프로젝트 이름으로 디렉토리가 생성되고 디렉토리 안에 몇 개의 파일이 자동으로 만들어진다.

애플리케이션 생성: django 의 실행 코드를 작성 하는 단위로 1개 이상 생성

python manage.py startapp 앱이름

python manage.py startapp myapp
  • 성공을 하면 앱이름의 디렉토리가 생성되고 몇 개의 파일이 생성됩니다.

실행

python manage.py runserver [IP주소:포트번호]

python manage.py runserver 127.0.0.1:80
  • IP주소 와 포트번호를 생략하면 127.0.0.1:8000 으로 실행
  • IP주소는 외부에서 접속하도록 하고자 하면 0.0.0.0 이나 컴퓨터의 실제 IP를 적어야 한다.

브라우저에 127.0.0.1 입력하면

아무런 요청도 작성하지 않은 페이지를 welcome-file이라고도 한다.

 

 

4) 기본 구조

프로젝트 디렉토리/settings.py

  • 프로젝트 설정에 관련된 파일
  • ALLOWED_HOSTS = []: 실제 배포할 컴퓨터의 IP를 등록하는 부분으로 '*' 으로 하면 아무데서나 배포가 가능하고 실제 IP를 작성하면 그 IP를 가진 컴퓨터에서만 배포가 가능
  • INSTALLED_APPS 부분을 실행할 애플리케이션을 등록하는 영역입니다.
    애플리케이션 생성한 경우 애플리케이션 이름을 등록해주어야 합니다.
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "myapp",
]
  • MIDDLEWARE 부분은 장고 애플리케이션이 요청을 처리하기 전에 수행하고자 하는 작업이 있을 때 작업을 기재하는 곳입니다. 필터의 역할을 수행하는 것입니다.
  • DATABASES 부분은 사용할 데이터베이스를 설정하는 부분인데 기본 코드는 python 안에 있는 sqlite3에 접속하도록 설정되어 있습니다.
  • TIME_ZONE은 시간 대역을 설정하는 부분인데 우리는 'Asia/Seoul' 로 변경해야 합니다.
TIME_ZONE = "Asia/Seoul"

 

urls.py

  • 사용자의 요청(url)을 처리할 함수나 클래스를 설정하는 파일

views.py

  • 실제로 요청을 처리할 함수나 클래스를 작성하는 곳

models.py

  • 사용할 데이터베이스 모델을 만드는 곳

 

5) 프로젝트의 모델 변경 내용을 데이터베이스에 반영

python manage.py migrate
  • 이 명령을 맨 처음 실행시키면 유저 정보나 로그인에 관련된 테이블을 자동으로 생성합니다.
  • admin, auth, session 관련 테이블을 생성
    • authentication(인증): 로그인
      authorization(인가): 권한
    • session: 클라이언트의 정보를 서버에 저장하는 것
      대부분의 경우 session에 로그인한 유저 정보를 저장해두는 경우가 많습니다.
      세션은 브라우저 창을 닫으면 자동으로 소멸됩니다.
  • 서버가 구동중이면 Ctrl + C로 서버 중지하고 수행!

 

6) 관리자 계정 생성 및 접속

python manage.py createsuperuser
  • 수행하고 필요한 정보(username, email, password)를 입력

127.0.0.1/admin으로 접속하면

로그인 회원가입은

 

 

7) 메인 페이지 작성

myapp > views.py 파일에 작성

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse('<h1>야채입니당</h1>') #HTML
  •  index 나 request는 사용자 설정!

myproject > urls.py 파일에 작성

from django.contrib import admin
from django.urls import path

#myapp 디렉토리에 있는 views 파일의 내용을 가져오기
from myapp import views

urlpatterns = [
    path("admin/", admin.site.urls),
    path("user/", admin.site.urls),
    path("", views.index)
]
  • "" 를 입력하면 myapp/views.py 파일의 index 함수를 호출해서 처리

브라우저에 IP를 입력하면 이제

 

8) 요청이 오면 HTML 파일을 출력  (별로 안 중요)

def menu(request):
    #menu.html 파일을 출력하는데 파일에 message 라는 이름으로 data를 전달
    return render(request, 'menu.html', {'message':'data'})

 

  • 출력할 HTML 파일을 저장하기 위한 templates 디렉토리를 애플리케이션 디렉토리(myapp)에 생성

  • templates 디렉토리에 menu.html 파일을 만들고 출력 내용을 작성
  • 서버 애플리케이션에 html 파일을 만들어서 출력하는 방식을 서버 사이드 랜더링이라고 하고 최근에는 잘 사용하지 않음
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>메뉴</title>
</head>
<body>
    <h3>템플릿을 이용한 출력</h3>
    <h4>데이터 출력</h4>
    <div>{{message}}</div>
</body>
</html>
  • urls.py 파일에 url과 views의 함수 연결하는 코드 추가서버를 구동하고 127.0.0.1/menu/ 라고 브라우저 주소 창에 입력하면 HTML 파일이 출력되어야 합니다.

 

9) 파라미터 읽기

parameter: 웹에서는 클라이언트가 서버에게 전송하는 데이터

 

https://yachae4910.tistory.com/16

 

NoSQL

1. 데이터베이스 분류 1) RDBMS 테이블 기반, SQL 이용해서 작업 트리구조라서 깊이에 따라 조회 속도가 다름 2)NoSQL Not only SQL RDBMS 시스템의 주요 특성을 보장하는 ACID(Atomicity, Consistency, Isolation, Durabi

yachae4910.tistory.com

  • 여기서 16은 게시글 번호다.

querystring

  • GET 방식 요청에서 URL 뒤에 ?를 추가하고 key=value&key=value 형태로 데이터를 전송하는 방식
  • 파라미터가 URL에 노출되고 데이터의 길이에 제한이 있어서 비밀번호 나 파일 등은 전달이 불가능
  • POST 나 PUT, DELETE 방식은 데이터를 header에 숨겨서 전송합니다.

 

 

10) URL 파라미터 읽기

path('url/<자료형:변수이름>", 요청 처리 함수)

#urls.py 파일 요청 연결 코드 추가
path('url/<자료형:변수이름>", 요청 처리 함수)

urlpatterns = [
	...
    path('article/<int:no>', views.detail),
    ...
]
  • 요청 처리 함수를 만들 때 def 함수이름(request, 변수이름) 으로 만들면 url의 변수 값이 변수에 형 변환되서 대입
#view.py 요청 처리 함수
def detail(request, no):
	return HttpResponse(str(no))

 

  • 브라우저에 127.0.0.1/article/숫자 입력하면

  • 이 방식은 대부분의 경우 하나의 데이터를 가져오고자 할 때 기본키값을 데이터로 전송하는 형식에서 주로 이용

 

 

11) GET 이나 POST 방식으로 전송된 파라미터를 읽기

요청 처리 메서드의 매개변수에 GET 이나 POST 라는 딕셔너리로 데이터가 전달

  • query라는 파라미터를 GET 방식으로 전송했을 때 읽는 함수를 views.py 파일에 작성
#views.py 파일 - query라는 파라미터를 GET 방식으로 전송했을 때 읽는 함수
def search(request):
    keyword = request.GET["query"]
    return HttpResponse(keyword)
#urls.py 파일- search?query=검색어 를 처리하는 url 과 함수를 연결

urlpatterns = [
	...
    path('search', views.search),
    ...
]
  • 127.0.0.1/search?query=문자열

 

MultiValueDictKeyError at /search

query를 제대로 입력하지 않으면 생기는 오류

 

 

 

 

4. 데이터베이스 연동

Docker 나 운영체제에 관계형 데이터베이스가 실행 중 인지 확인

 

1) 관계형 데이터베이스 연동 방식

SQL을 이용하는 방식

  • 프로그래밍 언어의 코드에 SQL을 직접 입력하거나 SQL을 별도의 파일에 만들어두고 사용하는 방식
  • 이 방식은 관계형 데이터베이스가 변경되면 SQL을 수정해야 한다.

Object Relation Mapper 방식

  • 하나의 객체 와 하나의 레코드를 매핑시키는 방식
  • 실제 구현할 때는 클래스 와 테이블을 매핑시킵니다.
  • CRUD 작업을 할 때 SQL을 사용하지 않고 함수를 이용합니다.
  • 함수를 호출하면 연결된 데이터베이스의 맞게 SQL을 만들어서 작업을 수행합니다.
  • 관계형 데이터베이스가 변경되더라도 파이썬 코드를 수정할 필요가 없어집니다.
  • 작업이 어렵고 잘못하면 성능 저하를 가져올 수 있습니다.
  • SI 업체에는 SQL을 직접 사용하는 방식을 선호하고 솔루션 업체(플랫폼 기업)에서는 ORM 방식을 선호합니다.
  • Django를 이용하는 경우 자체적인 ORM 엔진이 내장되어 있습니다.
  • Flask를 이용할 때는 ORM을 사용하고자 하면 별도의 패키지를 설치해서 사용해야 합니다.

 

2) 데이터베이스 연결

기본설정

# 기본적으로 로컬의 sqlite3에 접속
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

 

mysql

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "데이터베이스이름",,
        "USER": "접속할 계정",
        "PASSWORD": "비밀번호",
        "HOST": "데이터베이스접속위치",
        "PORT": "접속할 포트번호",
    }
}

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myDB",
        "USER": "root",
        "PASSWORD": "password",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    }
}

 

데이터베이스 관련 작업이 수정된 경우 수행할 내용

python manage.py makemigrations

python manage.py migrate

 

 

 

'Python' 카테고리의 다른 글

[Python] Numpy  (0) 2024.02.06
Day10. REST API  (0) 2024.01.26
Day8. 가상환경 만들기  (1) 2024.01.19
Day7. 웹프로그래밍 개요  (1) 2024.01.18
Day6. 객체지향 프로그래밍  (0) 2024.01.16

Day8. 가상환경 만들기

0ㅑ채
|2024. 1. 19. 10:16

 

 

 

파이썬 애플리케이션 작성

  • 가상 환경을 만들어서 작성
  • 가상 환경: 별도의 파이썬 환경을 생성
    • 외부 라이브러리를 설치해서 만든 애플리케이션은 다른곳에서 실행하려면 개발한 환경과 동일한 환경을 만들어야 하고, 컴퓨터에 있는 외부 라이브러리도 전부 설치를 해줘야 한다.
    • 그런데 가상환경을 만들면 필요한 라이브러리만 별도로 다운로드 받아서 가져갈 수 있다.
파이썬
    A 라이브러리
    B 라이브러리
    C 라이브러리 추가
    D 라이브러리 추가

1번 프로그램을 만들 때 C를 추가: A, B, C
2번 프로그램을 만들 때 D를 추가: A, B, D
3번 프로그램을 만들 때 나만의 환경을 생성: A, B, X
    X 라이브러리 사용

 

가상환경 만들기

#가상환경 생성
python -m venv #디렉토리가 만들어짐

#디렉토리 가상환경으로 이동
cd 가상환경이름

 

*cd: change directory

 

가상환경 활성화

#Windows
가상환경이름/Scripts/activate

#Windows 이외
source 가상환경이름/bin/activate

*가상환경 나가려면 deactivate

 

이제부터 pip로 설치하는 패키지는 가상환경 안에 설치돼서 가상환경 안에서만 사용 가능

# 설치한 패키지 목록을 텍스트 파일로 내보내기
pip freeze > 파일명(requirements.txt)

# 다른 곳에서 패키지를 전부 설치 
pip install 파일명

 

 

 

 

 

'Python' 카테고리의 다른 글

Day10. REST API  (0) 2024.01.26
Day9. 웹 서버 만들기  (1) 2024.01.24
Day7. 웹프로그래밍 개요  (1) 2024.01.18
Day6. 객체지향 프로그래밍  (0) 2024.01.16
Day5. 함수  (1) 2024.01.08

 

개요 Application - Program - Service

  • All Same. 복잡하거나 반복되는 일을 컴퓨터가 할 수 있도록 만든 것

 

1) 컴퓨터

  • 하드웨어: 실제 장비
    • 하드웨어는 기계어만 인식
  • 소프트웨어: 실제 장비를 코드로 사용할 수 있도록 추상화한 것
  • 운영체제: 하드웨어와 소프트웨어 사이의 인터페이스(통역)
    •  대부분 어셈블러(어셈블리어를 기계어로 번역)와 C언어로 만든다.
    • 그러나 C언어는 플랫폼에서 독립적이지 못하다. 맥용 윈도우용 두개씩 만들어야 함. 
    • 플랫폼에서 독립적인 고급언어가 나와서 Python, Java. 
    • Python은 C로 다시 바꿔줘야 해서 느리다. (우리가 쓰는 건 C-Python) 
컴퓨터와 운영체제를 같이 쓰는게 아니라, 내가 운영체제를 선택하고 싶어져서 Unix 대신 만든게 Linux.
리눅스는 초반에 서버라서 텍스트 기반이었다. 그런데 컴퓨터를 일반인한테 팔려면 쓰기가 쉬워야 하니까,
Linux위에 그림을 입힌게 Mac OS 10. 이때까지는 운영체제를 번들로 줬지만, 따로 운영체제를 만들고 싶어서 빌게이츠가 코드를 받아가서 만든게 MS C언어. 이로 인해 윈도우즈 탄생. 
클라우드 플랫폼은 GO언어 사용!

 

 

2) Web Browser에서 동작하는 언어

 

HTML은 구조

  • 앞에서부터 순서대로 읽어서 트리를 만들고 공간을 확보한 후 콘텐츠를 나중에 주입하는 구조
  • 외부 자원을 가져올 때는 캐싱을 이용
    • 캐싱: 빨리 쓰기 위하여 경로를 기반으로 저장해두는 것
    • 인터넷이 끊겨도 불러올 수 있도록 경로를 저장해야 한다.

CSS는 디자인

  • HTML 구조를 전부 읽고 난 후 출력할 때 적용

JavaScript, TypeScript는 동작

  • 태그와 함께 위에서부터 순서대로 읽으면서 동작(저장)

Type Script

def 이름 (매개변수이름: int) -> None
	내용

 

 

3) Framework, Library, Solution

  • SDK(Software Evelopment Kit): 프로그램을 만들 수 있도록 도와주는 도구
    • API(Application Programming Interface), 데이터의 의미를 포함한 같은 말
  • Library: 프로그램을 만드는 데 도와주는 별도의 코드 모임 
    • 파이썬에서는 주로 패키지라고 부름
  • Framework: 라이브러리와 같은데 프로그램 제작도 함 
  • Solution: 특정 목적이 있음

 

4) JavaScript Framework

  • node.js: 자바스크립트가 브라우저 이외의 환경에서 동작하도록 해주는 플랫폼
  • jquery  크로스 브라우징(서로 다른브라우저에서 동일한 콘텐츠를 제공하는 기술)을 가능하게 하지만 최근엔 사용 금기
  • bootstrap  : 반응형 웹(하나의 코드로 브라우저의 크기에 상관없이 동일한 컨텐츠를 사용할 수 있도록 하는 기술)을 쉽게 만들어주는 라이브러리
  • D3.js : 그래프를 만들어주는 라이브러리
  • express.js, nest.js : 서버를 만들기 위한 프레임워크
    • 클라이언트에서 서버를 만들 수 있어서 보안이 되는데 핵이 가능
  • SAP(Single Page Application): 하나의 페이지를 가지고 모든 콘텐츠 제공 
    • 구글 angular.js 진행 종료
    • 중국에서 많이 쓰는 vue.js
    • 국내에서 많이 쓰는 react.js
    • 최근에 핫해진 next.js
  • ajax, fetch API: 외부에서 비동기적으로 데이터를 가져오는 기술
    • axios 라이브러리 
  • progressive web: 웹과 앱의 경계가 무너지면서 웹이나 앱의 디자인을 유사하게 만드는 기술
    • 구글의 머터리얼  디자인

'Python' 카테고리의 다른 글

Day9. 웹 서버 만들기  (1) 2024.01.24
Day8. 가상환경 만들기  (1) 2024.01.19
Day6. 객체지향 프로그래밍  (0) 2024.01.16
Day5. 함수  (1) 2024.01.08
Day4. 딕셔너리와 반복문  (1) 2024.01.05

 

 

함수형 프로그래밍

  • 기능 단위로 작성
  • 유사한 동작을 하는 함수들은 파일로 묶어서 구분
  • 일반적으로 속도가 빠르고 불필요한 내용을 포함하지 않는 것이 장점
  • 빅데이터 처리 분야에서 많이 사용

 

객체 지향 프로그래밍

  • 유사한 동작을 하는 함수나 데이터를 하나로 묶어서 프로그래밍 하는 방식
  • 유사한 동작을 하는 함수와 데이터를 클래스라는 템플릿으로 묶고 템플릿을 이용해서 인스턴스를 생성해서 사용하는 방식으로 클래스도 하나의 인스턴스로 취급

 

 

 

클래스와 인스턴스

  • 인스턴스 만들기: 메모리에 인스턴스를 생성하고 인스턴스의 참조(id)를 리턴
  • 한번만 쓸거면  클래스이름(매개변수 나열...)
  • 여러번 쓸거면 obj = 클래스이름(매개변수 나열...)
  • 인스턴스를 생성하고 참조하는 데이터가 없다면 언제인지는 알 수 없지만 자동으로 메모리가 정리된다.
  • 일반적으로 클래스 이름은 대문자로 시작하고 Camel 표기법을 사용한다. 

 

 

1) 데이터(속성 - attribute)

클래스 속성: 클래스 안에 데이터를 만들고 클래스와 인스턴스가 공동으로 사용

  • 클래스 안에 변수를 만들면 이것은 클래스 속성이 된다. 

인스턴스 속성: 인스턴스 안에 만들어서 인스턴스만 사용할 수 있는 것

  • 메서드 안에서 메서드의 첫번째 매개변수이름.속성으로 만들면 이는 인스턴스 속성이 된다.

속성에 접근할 때는

  • 내부에서는 이름만으로 가능하지만
  • 외부에서는 클래스/인스턴스이름.속성으로 접근
#자동차를 표현하는 클래스
class Car:
    #클래스 속성 (클래스, 인스턴스 모두 접근, 공유)
    maker = "KIA"

#Car 클래스의 인스턴스를 생성
car = Car()

print(car.maker)
print(Car.maker)

 

 

 

2) 기능(메소드)

  • 클래스 안에 있는 함수: 메소드(Method)

 종류

  • 초기화 메소드(init): 인스턴스를 만들 때 호출되는 메소드로, 만들지 않아도 기본적으로 아무일도 하지 않는 초기화 메소드가 존재하며 다른초기화 메소드를 만들면 제거된다. 다른 언어에서는 생성자(Constructor)라고 한다.
  • 클래스 메소드, 스태틱 메소드: 클래스 안에 특별한 decorator와 함께 사용, 클래스와 인스턴스 모두 호출 가능한 메소드
    • 인스턴스 속성을 만들거나 소유할 수 없다.
    • 인스턴스 속성이 필요없는 동작을 하고자 할 때 사용
  • 인스턴스 메소드: 클래스 안에 만들어지는 함수로, 무조건 1개의 매개변수(객체 자신의 참조)를 가지고 만들어지는 함수로 인스턴스만 호출할 수 있고 인스턴스 속성 생성이 가능하다. 
    • 호출방법 
    • Bound 호출: 인스턴스.메소드(매개변수를 나열 - self 값을 대입하지 않음) - a1.add(a2)
    • Unbound 호출: 클래스.메소드(인스턴스, self를 제외한 매개변수를 나열) - Math.add(a1, a2)
  • 인스턴스 메소드 안에서 첫번째매개변수.속성이름 = 값의 형태로 만들면 인스턴스 속성이 만들어진다.
  • 이 속성은 인스턴스 이름으로 접근하고 인스턴스마다 별도로 만들어진다.
#바운드 호출
car.method()
#언바운드 호출
Car.method(car)

print(help(str.capitalize))
x = "hello"
print(x.capitalize())
print(str.capitalize(x))
  • 리턴이 없으면 원본 데이터 자체를 변경해주는 것이다. 
  • 리턴이 있으면 바꾼 데이터를 주는 것이다. 

 

class Singer:
    className = "가수"

#인스턴스 생성
singer1 = Singer()
singer2 = Singer()

#데이터 비교
print(singer1 == singer2)

#id 비교
print(singer1 is singer2)

#클래스 변수 확인
print(singer1.className)
print(singer1.className)

#동일한 데이터인지 비교
print(singer1.className is singer2.className)
print(id(singer1.className))
print(id(singer2.className))
  • 인스턴스는 자기 안에 값이 없으면 클래스를 쫓아감!
  • 그래서 인스턴스는 다르지만 데이터의 id는 같다. 같은 클래스 변수를 가르키고 있음.
class Singer:
    className = "가수"

    #인스턴수 변수를 생성하기 위한 인스턴스 메서드를 생성
    def create(self, name:str) -> None:
        #매개변수로 받은 데이터를 self.name에 대입
        self.name = name
        groupName = "에스파" #self 붙이지 않으면 함수 안에서 쓰는 지역변수기 때문에 밖에서 호출 불가능
 
    #좋은 예
    def setHometown(self, hometown):
        self.homtown = hometown
        
    #나쁜 예
    def setAttr(self, name, hometown):
        self.name = name
        self.homtown = hometown

#인스턴스 생성
singer1 = Singer()
singer2 = Singer()

#인스턴스 메서드 호출
singer1.create("조이") #바운드 호출
Singer.create(singer2, "아이린") #언바운드 호출

print(singer1.name) 
print(singer2.name)

조이

아이린

  • 매개변수 데이터가 많아지는 것은 나쁜 예

 

3) Accessor(getter와 setter, 접근자 메소드)

  • 수정 가능mutable한 변수를 동시작업할 때 제어하는 메소드
  • 인스턴스가 소유한 속성의 값을 수정하거나 읽기 위한 메소드

getter

  • 속성의 값을 읽는 메소드
  • 동시에 접근이 가능하다.
get속성이름(self):
    속성의 값을 리턴
  • 속성의 자료형이 bool인 경우 is속성이름(self)
  • 메소드 이름에서 [속성이름]의 첫글자는 대문자.

setter

  • 속성의 값을 수정하는 메소드
  • 동시에 접근하면 안된다.
set속성이름(self, 매개변수):
    매개변수로 받은 데이터를 속성에 대입
    (리턴 None)
  • 메소드 이름에서 [속성이름]의 첫글자는 대문자.
class Singer:
    
    #name이라는 속성의 accessor
    def setName(self, name):
        self.name = name
    
    #name의 getter
    def getName(self):
        return self.name

 

참고로 요즘에는 아래와 같이 짜야 한다!

class Singer:
    
    #name이라는 속성의 accessor
    def setName(self, name:str) -> None:
        self.name = name
    
    #name의 getter
    def getName(self) -> str:
        return self.name
        
#인스턴스 생성
singer1 = Singer()

#name 설정
singer1.setName(name = "민지")
print(singer1.getName())

민지

singer2 = Singer() #에러
print(singer2.getName())

AttributeError: 'Singer' object has no attribute 'name'

  • setter를 호출하지 않고 getter를 호출해서 에러
  • setter를 항상 먼저 불러야 한다. 변수를 먼저 생성해야 하니까!
  • 혹은 인스턴스가 만들어질 때부터 변수가 있도록 하는 방법이 있다. 그게 __init__ !

 

파이썬의 메소드 이름 관습

  • 첫글자를 대문자로 사용해야 하는 경우 _로 시작
    • 소문자로 시작하기도 한다.
  • _ _뭐시기: 직접 접근 불가 메소드 (private)
  • _ _뭐시기 _ _: 직접 호출 불가, 다른 방법으로 호출해야 함.
...
    def __str__(self): #출력하는 메소드에 인스턴트를 넣으면 자동으로 출력한다.
        print("나의 이름은 ", self.name) #나의 이름은 민지
        return self.name
...

#name 설정
singer1.setName(name = "민지")
print(singer1) #민지

나의 이름은  민지

민지

 

 

4) 초기화 메서드와 소멸될 때 호출되는 메서드

생성자

  • 객체가 생성될 때 자동으로 실행, 메모리를 할당한다.
  • 그리고 멤버변수 값을 초기화하는 역할을 한다. 
  • 만약 초기화 작업이 필요 없다면 클래스 설계 시 생성자를 생략할 수 있다. (파이썬은 기본생성자를 자동 제공)
더보기

예문

#(1) 생성자 이용 멤버변수 초기화
class Multiply :
    #멤버 변수
    x = y = 0
    
    #생성자 : 초기화
    def __init__(self, x, y): #객체만 생성
        self.x = x
        self.y = y
    
    #메서드
    def mul(self):
        return self.x * self.y
    
obj = Multiply(10, 20) #생성자
print('곱셈=', obj.mul()) #곱셈=200

 

#(2) 메서드 이용 멤버변수 초기화
class multiply2 :
    #멤버 변수
    x = y = 0
    
    #생성자 없음 : 기본 생성자 제공
    def __init__(self):
        pass
    
    #메서드: 멤버변수 초기화
    def data(self, x, y):
        self.x = x
        self.y = y
    
    #메서드: 곱셈
    def mul(self):
        return self.x * self.y

obj = Multiply() #기본 생성자
obj.data(10, 20) #동적 멤버변수 생성
print('곱셈=', obj.mul()) #곱셈=200

 

더보기

self가 뭐야?

  • 클래스의 생성자와 메서드는 기본적으로 self라는 매개변수를 갖는다.
  • 클래스를 구성하는 멤버들 즉 멤버변수와 메서드를 호출하는 역할을 한다.
  • 예를 들어 생성자 안에서 멤버변수 값을 초기화하거나 메서드 안에서 멤버변수를 참조하거나 또는 다른 메서드를 호출할 경우 이용한다.
class multiply3:
    #멤버변수 없음
    #생성자 없음
    
    #동적 멤버변수 생성/초기화
    def data(self, x, y):
        self.x = x #동적으로 멤버변수가 만들어지고 매개변수에 의해서 값이 초기화된다.
        self.y = y
        
#곱셈연산
def mul(self):
    result = self.x * self.y
    self.display(result) #메서드 호출

#결과 출력
def display(self, result):
    print("곱셈= %d" %(result) ) #곱셈 = 200
    
obj = multiply3() #기본 생성자
obj.data(10, 20)
obj.mul()

 

 

초기화 메소드 __init__

  • 인스턴스를 만들 때 호출하는 메소드
  • 생성자와 다른 점, 메모리 할당을 하지 않는다!
  • 기본적으로 매개변수가 self 1개인 메소드가 제공된다. 
    • 기본적으로 제공되는 __init__은 아무일도 하지 않는다.
    • 무엇인가를 하도록 하려면 __init__을 재정의(overriding) 해야 한다. 
    • 직접 재정의를 하면 기본 제공되는 메소드는 없어진다. 
  • 인스턴스가 생성될 때 인스턴스 속성(attribute)을 초기화할 때 주로 사용
  • 외부에서 만든 데이터를 인스턴스 속성에 대입하는 작업을 Injection(주입)이라고 한다.
    ex. singer1.setName(name = "민지")
class Singer:
    
    def setName(self, name:str) -> None:
        self.name = name
    
    def getName(self) -> str:
        return self.name
    
    #초기화 메소드
    def __init__(self, name):
        self.name = name
        
 
singer1 = Singer() #에러발생
print(singer1.getName())

TypeError: Singer.__init__() missing 1 required positional argument: 'name'

  • name에 초기값을 줘야 함!
class Singer:
    
    def __init__(self, name = "noname"):
        self.name = name
  
 ...
  • 이제 초기값이 정의됐기 때문에 값을 주든 안주든 에러가 안난다.

 

소멸 메소드 __del__

  • 인스턴스가 소멸될 때 호출되는 메소드
  • 객체 사용이 완료되면 자동으로 실행되어 객체를 메모리에서 소멸시키는 역할을 한다.
__del__(self):
    내용
class Singer:
    
    #name이라는 속성의 accessor
    def setName(self, name):
        self.name = name
    
    #name의 getter
    def getName(self):
        return self.name
    
    #초기화 메소드
    def __init__(self, name = "noname"):
        self.name = name
    
    def __del__(self):
        print(self, "메모리 해제")        
 
singer1 = Singer() 
print(singer1) #<id>
singer1 = None 
#<id> 메모리 해제
singer1 = Singer() 
singer3 = singer1
singer1 = None
  • singer1이 가리키던 인스턴스를 해제(None을 가리키도록 설정 → 메모리 해제 대상)
  • 그러나 singer3도 이제 Singer()를 가리키기 떄문에 사실은 reference count = 1인 상태!
  • python은 reference count = 0이 될 때 메모리가 해제

인스턴스의 reference count = 0 이 되면 호출

  • 외부의 데이터를 사용하는 경우 무조건 정리를 하고자 할때 주로 사용
  • 생성자의 반대역할 
  • 하지만 파이썬 자체에서 메모리 관리를 자동으로 해주기 때문에 많이 사용되지는 않는다.

 

5) 클래스가 인스턴스 없이 호출할 수 있는 메소드 

static 메소드

  • self 없이 클래스 안에 만들 수 있는 메소드
  • 이 메소드는 클래스가 인스턴스 없이 호출할 수 있고 인스턴스를 이용해서 호출할 수도 있다.
@staticmethod
def 이름(self제외 매개변수):
    내용
  • 파이썬에서 @로 시작하는 단어는 decorator라고 하는데 코드를 하나의 단어로 작성하고자 할 때 사용
  • 이 코드는 메소드의 내용이 수행되기 전이나 수행된 후에 하고자 하는 작업에 대한 코드(Filter, AoP)

        *AoP 관점지향적 프로그래밍

        *JAVA에서는 Class method만 사용한다. (@Classmethod)

 

Heap 자료구조 Stack 자료구조
영구적 할당
Static: Class, Function, Literal


반영구적 할당
Dynamic: Instance
Function Call, 임시 영역
- LIFO구조 (Last In First Out)

 

  • 사용자는 Class에 접근하거나, stack을 통해서 Instance에 접근할 수 있다. 
  • Class에 있는 instance method를 사용하려면 singer = Singer()의 과정이 필요하지만
  • Class에 있는 static method를 사용하려면 바로 Class에 접근해서 사용하면 속도와 메모리 효율이 좋다.
  • 따라서 self가 없는 애들은 static으로 만드는게 좋다. 

@staticmethod

class Singer():
    #인스턴스 없이 클래스가 호출할 수 있는 메서드
    @staticmethod
    def staticMethodExam():
        print("static method")
    
    #클래스에 대한 정보를 갖는 매개변수 1개가 필수    
    @classmethod
    def classMethodExam(cls):
        print("class method")
            
#instance = Singer()
#instance.staticMethodExam()

Singer.staticMethodExam()
Singer.classMethodExam()

 

 

 

6) Inheritance(상속)

상속

  • 하위 클래스가 상위 클래스의 모든 것을 물려받는 것

        * 객체지향언어에서는 is a로 사용하기도 함

  • 여러 개의 클래스들에 공통된 내용이 있는 경우 공통 내용을 상위 클래스에 만들고 상속을 받는 방법으로 대체한다.
    • a = 10 변수를 설정해서 나중에 값을 수정할 때 변수만 수정하면 되는 맥락과 같음!
  • 객체지향 프로그래밍의 기본 원칙에서는 여러 하위 클래스에 공통으로 존재하는 기능을 상위 클래스로 올려보내는 것으로 간주한다.
상위 클래스
        ↑
하위 클래스

*그러니 부모클래스, 자식클래스라는 말은 절대 쓰지 말자!

 

단일 상속: 하나의 클래스로부터 상속받는다.

다중 상속: 여러 개의 클래스로부터 상속받는다. 파이썬은 다중 상속을 지원

 

목적

  • 여러 클래스의 공통된 내용이 존재해서 - 일반 프로그래밍
  • 제공되는 클래스의 기능이 부족해서 - 프레임워크
    • 프로그램을 여러개 만들면 공통적으로 사용하는 기능이 있다. 이런 공통 기능을 미리 만들어서 제공하기도 한다.
    • 이 경우는 클래스의 기능이 부족할 때 확장하기 위해서 상속을 하는 것
  • 공통된 인터페이스를 사용하기 위해서 - 다형성 구현

구현

class 클래스이름(상위클래스 이름 나열)
class Phone:
    def superMethod(self):
        print("phone 클래스의 메소드")

#다중상속받은 클래스
class Camera:
    def superMethod(self):
        print("Camera 클래스의 메소드")

#상속받은 클래스
class SmartPhone(Phone, Camera): #Camera가 Phone보다 먼저 오면 Camera superMethod 호출
    def subMethod(self):
        print("Smartphone 클래스의 메서드")


subOnj = SmartPhone()
subOnj.subMethod()
#SmartPhone 클래스는 phone 클래스를 상속받았으므로 phone 클래스의 멤버를 사용 가능
subOnj.superMethod()

Smartphone 클래스의 메서드
Camera 클래스의 메소드

 

상위 클래스의 __init__ 호출

  • 파이썬에서 하위 클래스의 __init__ 메소드에서 상위 클래스의 __init__를 자동으로 호출하지 않는다.
  • 대다수의 객체 지향 언어에서 상속을 받으면 하위 클래스의 생성자에서 상위 클래스의 생성자를 자동으로 호출한다.
  • 하위 클래스의 __init__ 안에서 상위 클래스의 초기화 메소드를 호출하고자 하는 경우는 super().__init__()를 호출
class Phone:
    def __init__(self):
        self.name = "전화기"
    
    def superMethod(self):
        print("phone 클래스의 메소드")

#상속받은 클래스
class SmartPhone(Phone):
    def __init__(self):
        #상위 클래스의 속성을 자동으로 호출하지 않기 떄문에 생성자라고 할 수 없음
        #상위 클래스의 __init__을 호출해줘야 한다.
        super().__init__()
        print(self.name)
    
    def subMethod(self):
        print("Smartphone 클래스의 메서드")

subOnj = SmartPhone()
subOnj.subMethod()
subOnj.superMethod()

 

 

 

7) Method Overriding

method overloading(중복 정의)

하나의 클래스에 동일한 이름이지만 매개변수의 개수나 자료형이 다르게 만들어진 메소드가 존재하는 경우

method overriding(재정의)

상위 클래스(내용이 있음)에 존재하는 메소드를 하위 클래스에서 다시 정의하는 것

 

목적

기능 확장 ★

  • 기능을 10개 주는데, 클래스가 확장이 되는게 아니라 메소드가 확장이 됐으면 좋겠다. 새로 만들면 이름이 바뀐다. 기존의 이름을 쓰되 다른 기능을 추가해주는 것을 오버라이딩이라고 한다. 
  • 오버라이딩을 하면 상황에 따라서 같은 이름이 다른 일을 한다. 
    • 똑같은 클릭인데 탐색기에서는 선택, 버튼에서는 하이퍼링크 따라가기. 
    • 어차피 같은 동작인데 여기서는 클릭, 여기서는 프레스라고 하면 스트레스니까..!

언어에서는 상위 클래스의 메서드를 호출하지 않는 것이 에러가 아니지만 프레임워크에서는 에러가 발생한다.

class Phone:
    def __init__(self):
        self.name = "전화기"
    
    def superMethod(self):
        print("phone 클래스의 메소드")

#상속받은 클래스
class SmartPhone(Phone):
    def __init__(self):
        super().__init__()
        print(self.name)
    
    #상위클래스에 존재하는 메소드를 하위 클래스에서 다시 구현
    #메소드 오버라이딩
    def superMethod(self):
        super().superMethod() #기능 확장, 순서 중요
        print("SmartPhone 클래스의 메소드")
    
    def subMethod(self):
        print("Smartphone 클래스의 메서드")

subOnj = SmartPhone()
subOnj.subMethod()
subOnj.superMethod()
  • 만들 때는 상위클래스부터, 지울 때(destroy, close)는 하위클래스부터! 
  • 대부분은 super()를 먼저 쓰지만, 파괴할 때는 super()가 뒤에 온다. 

 

 

8) Abstract(추상)

Abstract Class(추상 클래스)

  • 인스턴스를 만들 수 없는 클래스
  • 상속을 통해서만 사용하는 클래스

만드는 방법

import abc 
class 클래스이름(metaclass=abc.ABCMeta)
  • import는 파이썬 기본 모듈이 아닌 파일의 내용을 현재 프로그램에 가져올 때 사용하는 명령어
  • import abc는 abc.py라는 파일의 내용을 abc라는 이름으로 묶어서 가져오는 것이다. 
  • import abc as X: abc.py라는 파일의 내용을 X라는 이름으로 묶어서 가져오는 것이다. 

 

Abstract method (추상 메소드)

  • 내용이 없는 메소드
  • 반드시 추상 클래스에 존재
  • 하위 클래스에서 반드시 구현해야 하는 메소드

        *자바에서는 이것도 오버라이딩이라고 한다. 하지만 오버라이딩의 목적은 기능확장이니까, 정확히는 implements(구현)이라고 해야 한다.

 

생성 방법

@abc.abstractmethod
def 이름(매개변수):
    pass

 

사용 이유

  • 동일한 인터페이스를 제공하기 위해서!
  • 인터페이스는 프로토콜이라고도 한다. (규칙, 약속)
    • 음식점의 키오스크에는 내용물은 없고 이름하고 그림만 있다. 하지만 반드시 이 음식점에서 해줄 수 있어야 한다. 이 키오스크가 음식점과 대화하기 위한 인터페이스. 
    • 인터페이스를 만드는 이유는 고객과 소통하는 템플릿을 만들기 위해서다.
#추상 클래스를 만들기 위한 모듈
import abc

class Phone(metaclass=abc.ABCMeta):
    #추상 메소드
    @abc.abstractmethod
    def call(self):
        pass    

#추상 클래스를 상속받은 클래스
#추상 메소드를 반드시 구현
class SmartPhone(Phone):
    pass

smartPhone = SmartPhone()

TypeError: Can't instantiate abstract class SmartPhone with abstract method call

class SmartPhone(Phone):
    def call(self):
        print("성공")

SmartPhone = SmartPhone()
print(smartPhone.call())

성공

None

 

템플릿 메서드 패턴

  • 추상 메서드를 소유한 추상 클래스(인터페이스, 프로토콜)를 만들고 이를 구현한 클래스를 만들어서 
  • 고객의 요구를 처리하는 클래스 생성
#추상 클래스를 만들기 위한 모듈

import abc

class InsertService(metaclass=abc.ABCMeta):
    #추상 메소드
    @abc.abstractmethod
    def insert(self, data) -> bool:
        pass    

class InsertServiceImpl(InsertService):
    #대략적인 동작하는 코드를 작성하고 테스트 한 후 실제 코드를 구현하는 방식이 TDD
    def insert(self, data) -> bool:
        print("데이터 추가")
        return True

service = InsertServiceImpl()
print(service.insert("데이터"))

데이터 추가

True

 

 

 

9) Polymorphism(다형성)

  • 동일한 메시지에 대하여 다르게 반응하는 성질
  • 동일한 코드가 호출하는 인스턴스에 따라 다른 메소드를 호출하는 것
  • 상속과 오버라이딩을 이용해서 구현
import abc

class Starcraft(metaclass=abc.ABCMeta):
    #추상 메소드
    @abc.abstractclassmethod
    def attack(self, data) -> None:
        pass
    
class Protoss(Starcraft):
    def attack(self, data) -> None:
        print("프로토스 ", data, " 공격")
    
class Terran(Starcraft):
    def attack(self, data) -> None:
        print("테란 ", data, " 공격")
        
star = Protoss()
star.attack("드래군")
star = Terran()
star.attack("종이비행기")

프로토스  드래군  공격
테란  종이비행기  공격

  • 유사한 동작은 하나의 인터페이스로 동작이 되어야 한다.
  • 프로토스든 테란이든 단축키를 하나로! 

        * 프로그레시브 웹앱: 스마트폰과 웹에서 동일한 UI로 만들자. 그럼 배울 동작이 하나라 간편 (유튜브)

 

 

 

 

 

 

 

더보기

클래스와 객체 추가

 

클래스와 객체

클래스(Class)

  • 변수와 함수들을 하나로 묶어놓은 논리적 집합체
  • 속성(Attribute)와 행위(Action)로 구성된다. 
  • 클래스의 구성요소를 UML 표기법으로 도식화하면
  • 설계 도면은 필요한 속성만 정의해두지만, 클래스에는 자동차가 할 수 있는 동작도 정의해야 한다. 
  • 클래스의 속성은 자료(data)를 나타낸다. (변수, 필드의 개념)
  • 클래스의 행위는 자료를 연산하거나 조작하는 역할을 한다. (메소드, 함수의 개념) 
    • 함수(Function): 독립된 기능을 수행하는 코드(명령문)들의 집합
    • 메서드(Method): 클래스에 포함되어 있는 함수

* 클래스 변수는 객체를 생성하지 않아도 쓸 수 있는 광역변수

 

객체(Object)

  • 클래스에 의해서 만들어지는 결과물(instance)
  • 클래스를 선언해야 객채를 생성할 수 있다. 
    • 함수: 정의 → 호출
    • 클래스: 클래스 정의 → 객체 생성 → 멤버 호출
  • 클래스를 만들었으나 객체를 생성하지 않으면 클래스의 멤버(변수, 메소드)를 쓸 수 없다.
    • 멤버변수 = (클래스변수, 객체변수, 종단변수)
    • 클래스변수는 정적변수/전역변수, 객체변수는 동적변수
    • 클래스 변수가 객체변수보다 우선순위에 있기 때문에 클래스 변수는 객체 생성 없이도 사용할 수 있다.
  • 각 객체는 서로 독립적인 메모리 주소를 가지고 있으며, 메시지(Message)를 이용해서 상호작용도 가능하다.

 

# 함수 형식
def 외부함수(매개변수) :
    변수선언
    def 내부함수() :
        명령문
        return 값
    return 내부함수
    
# 클래스 형식
class 클래스명:
	변수 선언
    def 생성자() :
    	명령문
    def 함수명() :
    	명령문

* 생성자도 메서드의 일부로 보는게 편하다. 

# (1)함수 정의
def calc_func(a, b) : #외부함수
    #변수 선언: 자료저장
    x = a #10
    y = b #20
    
    def plus(): #내부함수
        p = x + y
        return p
    
    def minus(): #내부함수
        m = x - y
        return m
    
    return plus, minus #내부함수는 괄호 없이 호출

# (2)함수 호출
p, m = calc_func(10, 20)
print('plus =', p())
print('minus=', m())


# (3)클래스 정의
class Calc_class :
    #클래스 변수: 자료저장
    x = y = 0
    
    # 생성자: 객체 생성 + 멤버변수 초기화 (__생성자__)
    def __init__(self, a, b): #self는 26번의 x, y를 의미한다.
        self.x = a #10
        self.y = b #20
        
    #클래스 함수
    def plus(self):
        p = self.x + self.y #변수선언
        return p
    
    #클래스 함수
    def minus(self):
        m = self.x - self.y
        return m
    
# (4)객체 생성
obj = calc_class(10, 20) #객체를 만드는 문장이 실행될 때, 생성자는 자동으로 실행된다.

# (5)멤버 호출
print('plus=', obj.plus()) #plus = 30
print('minus=', obj.minus()) #minus = -10

 

객체와 인스턴스의 차이

인스턴스는 개념적으로 객체와  비교했을 때, 현재 가장 최근에 만들어진 객체를 의미한다.

 

 

클래스의 구성요소

클래스 구성요소: 멤버(Member) + 생성자(Constructor)

               멤버번수(자료) + 메서드(기능)

 

class Car:
    #(1) 멤버변수
    cc = 0 #엔진 cc
    door = 0 #문짝 개수
    carType = None #null
    
    #(2) 생성자
    def __init__(self, cc, door, carType):
        #멤버 변수 초기화
        self.cc = cc
        self.door = door
        self.carType = carType #승용차, SUV
    
    #(3) 메서드
    def display(self):
        print("자동차는 %d cc이고, 문짝은 %d개, 타입은 %s"
              %(self.cc, self.door, self.carType))
    
#(4) 객체 생성
car1 = Car(2000, 4, "승용차") #객체 생성 + 초기화
car2 = Car(3000, 5, "SUV")
    
#(5) 멤버 호출 : object.member()
car1.display() #car1 멤버 호출
car2.display() #car2 멤버 호출

 

(1) 멤버변수

Car 클래스의 선언부에 3개의 멤버변수(cc, door, carType)를 선언한다. 

 

(2) 생성자

생성자는 함수의 선언과 유사하지만 차이점은 이름이 정해져 있고 self라는 매개변수를 사용한다는 점이다.

예문에서 생성자는 def 명령어 다음에 '__init__'이라는 이름과 self라는 매개변수를 이용하여 선언된다.

self 매개변수는 생성자 내에서 클래스의 멤버를 호출하는 데 이용된다.

self 매개변수 다음에 오는 3개의 매개변수는 3개의 멤버변수 (cc, door, carType)에 값을 초기화하기 위한 매개변수다.

매개변수는 객체가 생성 시의 인수를 받아서 멤버변수에 초기화하는 역할을 한다.

 

(3) 메서드

메서드는 함수 선언과 동일하다. 차이점은 생성자와 마찬가지로 self라는 정해진 매개변수를 포함하고 있다는 점이다.

예문에서 display() 메서드는 self를 이용하여 3개의 멤버변수의 내용을 출력하는 역할을 한다. 

 

(4) 객체 생성

클래스의 생성자를 이용하여 객체를 생성한다.한 개의 클래스에 의해서 다수의 객체를 만들어낼 수 있다.

Car 클래스의 생성자를 이용하여 객체를 생성하는 방법은 참조변수 = Car(인수)

Car()는 Car 클래스의 생성자이고, 인수는 생성자의 매개변수에 전달할 실제값이다.

따라서 Car(2000, 4, "승용차") 형식의 명령문은 3개의 멤버변수에 각각 cc=2000, door=4, carType="승용차"가 할당되어 car1 객체가 생성된다.

 

(5) 멤버 호출

생성된 객체의 참조변수를 이용하여 객체의 멤버를 호출할 수 있다.  참조변수.멤버(멤버변수 or 메서드)

 

'Python' 카테고리의 다른 글

Day8. 가상환경 만들기  (1) 2024.01.19
Day7. 웹프로그래밍 개요  (1) 2024.01.18
Day5. 함수  (1) 2024.01.08
Day4. 딕셔너리와 반복문  (1) 2024.01.05
Day3. 조건문과 리스트  (2) 2024.01.04

Day5. 함수

0ㅑ채
|2024. 1. 8. 17:34

 

 

A. 함수의 정의와 호출

함수는 한마디로 호출의 집합이다.

def 함수 이름():
    문장
def print_n_times(value, n):
    for i in range(n):
        print(value)
        
print_n_times("안녕하세요", 5)

안녕하세요
안녕하세요
안녕하세요
안녕하세요
안녕하세요

 

 

가변 매개변수

  • 매개변수를 원하는 만큼 입력할 수 있는 함수 (매개변수의 개수가 변할 수 있다.)
  • 가변 매개변수 뒤에는 일반 매개변수가 올 수 없다.
  • 가변 매개변수는 하나만 사용할 수 있다.
def print_n_times(n, *values):
    #n번 반복합니다.
    for i in range(n):
        #values는 리스트처럼 활용합니다.
        for value in values:
            print(value)
            print()
            
print_n_times(2, "안녕하세요", "뚱쌤", "배고파요")

안녕하세요

뚱쌤

배고파요

안녕하세요

뚱쌤

배고파요

 

 

기본 매개변수

  • 일반 매개변수(n), 기본 매개변수(n=2)
  • 기본 매개변수 뒤에는 일반 매개변수가 올 수 없다.
def print_n_times(value, n=2):
    for i in range(n):
        print(value)
        
print_n_times("안녕하세요", 3)

안녕하세요

안녕하세요

안녕하세요

 

 

가변 매개변수가 기본 매개변수보다 앞에 오면, 어디까지가 values에 해당하는지 알 수가 없다.

def print_n_times(*values, n=2):
    for i in range(n):
        for value in values:
            print(value)
        print()        
print_n_times("오늘", "점심은", "마라탕", 3)

오늘
점심은
마라탕
3

오늘
점심은
마라탕
3

 

 

키워드 매개변수

  • 이러한 문제를 해결하기 위해 등장
  • 매개변수 이름을 직접적으로 지정해서 값을 입력한다.
  • ex. end=""
def print_n_times(*values, n=2):
    for i in range(n):
        for value in values:
            print(value)
        print()        
print_n_times("오늘", "점심은", "마라탕", n=3)

 

 

기본 매개변수 중에서 필요한 값만 입력하기

def test(a, b=10, c=100): #함수헤더
    print(a+b+c) #함수 바디

#기본형태
test(10, 20, 30)
#키워드 매개변수로 모든 매개변수를 지정한 상태
test(a=10, b=100, c=200)
# 키워드 매개변수로 모든 매개변수를 마구잡이로 지정한 형태
test(c=10, a=100, b=200)
# 키워드 매개변수로 일부 매개변수만 지정한 형태
test(10, c=200)

60
310
310
220

 

 

리턴 return

def 함수 이름():   #함수 헤더
    문장                 #함수 바디
  • 함수를 호출한 부분에 함수 바디에서 작업한 부분을 반환하는 장치
  • 함수의 바디 부분에 [ return + 식 ]을 써주면 바디에서 수행된 결과를 호출한 곳으로 반환시킨다.
def return_test():
    print("A 위치입니다.")
    return
    print("B 위치입니다.")

print(return_test())

A 위치입니다.
None

  • return이 시행되면 호출한 곳으로 돌아간다.
  • 따라서 5번 문장은 시행되지 않는다. 이것을 사문이라고 한다. (필요없는 사족 문장)

 

자료와 함께 리턴하기

def return_test():
    return 100       #얘도 식이다. 상수 100.

value = return_test()
print(value)

100

def return_test():
    return 100+100

value = return_test()
print(value)

200

def return_test(num1, num2):
    return num1 + 100

value = return_test(10, 20)
print(value)
  • return num1 + 100이 수행됐을 때
  • 호출한 지점인 return_test(10, 20)에 return 식의 결과가 호출되고
  • value에 이 결과가 할당되는 메커니즘!

 

아무것도 리턴하지 않기

def return_test():
    return 

value = return_test()
print(value)

None

  • None은 없다는 뜻!

 

 

기본적인 함수의 활용

def 함수(매개변수):   
      변수=초깃값   
       # 여러가지 처리   
       # 여러가지 처리   
       # 여러가지 처리   
       return 변수
def sum_all(start, end):
    output = 0
    for i in range(start, end+1):
        output += i
    return output
    
print("0 to 100:", sum_all(0, 100))
print("0 to 1000:", sum_all(0, 1000))
print("50 to 100:", sum_all(50, 100))
print("500 to 1000:", sum_all(500, 1000))

0 to 100: 5050
0 to 1000: 500500
50 to 100: 3825
500 to 1000: 375750

 

기본 매개변수 사용하기

def sum_all(start=0, end=100, step=1):
    output = 0
    for i in range(start, end+1, step):
        output += i
    return output
    
print("A:", sum_all(0, 100, 10))
print("B:", sum_all(end=100))
print("C:", sum_all(end=100, step=2))

A: 550
B: 5050
C: 2550

 

 

 

B. 함수의 활용

재귀함수

팩토리얼 구하기

  • n! = n * (n-1) * (n-2) * ... * 1
  • 반복문으로 구하기
def factorial(n):
    output = 1
    for i in range(1, n+1):
        output *= i
    return output

print("1!:", factorial(1))
print("2!:", factorial(2))
print("3!:", factorial(3))
print("4!:", factorial(4))
print("5!:", factorial(5))

1!: 1
2!: 2
3!: 6
4!: 24
5!: 120

 

  • 재귀함수로 구하기
def factorial(n):
    if n==0:
        return 1
    else:
        return n * factorial(n-1) #함수호출

print("1!:", factorial(1))
print("2!:", factorial(2))
print("3!:", factorial(3))
print("4!:", factorial(4))
print("5!:", factorial(5))

1!: 1
2!: 2
3!: 6
4!: 24
5!: 120

  • n=2일 때, return식에서는
    • 2 * factorial(2-1)
    • = 2 * factorial(1)
    • = 2 * 1
  • 따라서 2가 반환된다.

 

조기 리턴

  • return은 원래 함수 흐름의 끝에 써줘야 한다는 암묵적 룰이 있었는데
  • 요즘은 필요할 때 사용하면 된다는 주의. 옳고 그름은 없고 융통성 있게!
  • 이렇게 흐름중간에 return 키워드를 사용하는 것을 조기 리턴이라고 한다.

 

리스트 평탄화

[[1, 2, 3], [4, [5, 6]], 7, [8, 9]]  ▷  [1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

 

p.310

가독성은 프로그래밍에 굉장히 중요한 요소다.

주석을 잘 사용하는 사람이 프로그래밍을 잘하는 사람이다.

 

 

 

 

 

C. 함수 고급

튜플

(데이터, 데이터, 데이터, ...)

#튜플 선언
tuple_test = (10, 20, 30)

print(tuple_test[0]) #10
print(tuple_test[1]) #20
print(tuple_test[2]) #30

tuple_test[0] = 1 #오류!!
  • 튜플은 내부 요소 변경이 불가능하기 때문에 오류 발생
#괄호가 없는 튜플
tuple_test = 10, 20, 30, 40
print("tuple_test:", tuple_test)
print("type(tuple_test):", type(tuple_test))
print()

#괄호가 없는 튜플 활용
a, b, c = 10, 20, 30
print("a:", a)
print("b:", b)
print("c:", c)

tuple_test: (10, 20, 30, 40)
type(tuple_test): <class 'tuple'>

a: 10
b: 20
c: 30

 

튜플 할당

https://ko.from-locals.com/python-multi-variables-values/

# a, b = 100, 200, 300
# ValueError: too many values to unpack (expected 2)

# a, b, c = 100, 200
# ValueError: not enough values to unpack (expected 3, got 2)
a, *b = 100, 200, 300

print(a) # 100
print(type(a)) # <class 'int'>

print(b) # [200, 300]
print(type(b)) # <class 'list'>
  • 리스트로 저장이 가능하다.
*a, b = 100, 200, 300

print(a) # [100, 200] 
print(type(a)) # <class 'list'>

print(b) # 300
print(type(b)) # <class 'int'>

 

 

튜플 값 맞바꿈

a, b = 10, 20

print("# 교환 전 값")
print("a:", a)
print("b:", b)
print()

a, b, = b, a

print("# 교환 후 값")
print("a:", a)
print("b:", b)
print()

# 교환 전 값
a: 10
b: 20

# 교환 후 값
a: 20
b: 10

 

튜플과 함수

#함수 선언
def test():
    return (10, 20)

a, b = test()

print("a:", a)
print("b:", b)

a: 10
b: 20

#함수 선언
def test():
    return (10, 20)

a, b = test()

print("a:", a)
print(type(a))
print("b:", b)
print(type(b))

a: 10
<class 'int'>
b: 20
<class 'int'>

#함수 선언
def test():
    return (10, 20)

num = test()
print(type(num))

print("a:", num[0])
print("b:", num[1])

<class 'tuple'>
a: 10
b: 20

  • num = test() 이 문장은 
  • num = (10, 20) 과 같다.

 

함수의 매개변수로 함수 전달하기

# 매개변수로 받은 함수를 10번 호출하는 함수
def call_10_times(func):
    print(type(func))
    for i in range(3):
        func()
        
# 간단한 출력하는 함수
def print_hello():
    print("안녕하세요")
    
# 조합하기
call_10_times(print_hello)

print(type(print_hello))
  • func 함수는 정의되지 않았다. 
  • print_hello 함수를 인수로 사용했더니
  • 매개변수에 선언한 func가 이 형식을 할당받았다.
  • func = print_hello
  • 이걸 오버라이드라고 한다!

안녕하세요
안녕하세요
안녕하세요

<class 'function'>

 

 

filter() 함수와 map() 함수

함수를 매개변수로 사용하는 대표적인 표준 함수

map(함수, 리스트)
filter(함수, 리스트)
def power(item):
    return item * item
def under_3(item):
    return item < 3

list_input_a = [1, 2, 3, 4, 5]

output_a = map(power, list_input_a)
print("# map() 함수의 실행결과")
print("map(power, list_input_a):", output_a)
print("map(power, list_input_a):", list(output_a))

output_b = filter(under_3, list_input_a)
print("# filter() 함수의 실행결과")
print("filter(power, list_input_a):", output_b)
print("filter(power, list_input_a):", list(output_b))

# map() 함수의 실행결과
map(power, list_input_a): <map object at 0x0000028F61ECAB00>      
map(power, list_input_a): [1, 4, 9, 16, 25]
# filter() 함수의 실행결과
filter(power, list_input_a): <filter object at 0x0000028F61ECAC80>
filter(power, list_input_a): [1, 2]

  • 3이상이면 False, 3미만이면 Flase
  • 결과로 나오는 <map object>와 <filter object>는 제너레이터다. 

람다

  • lambda 매개변수: 리턴값
#일반 함수 사용
def power(item):
    return item * item
def under_3(item):
    return item < 3

#람다 함수 정의할 때 사용
power = lambda x: x * x
under_3 = lambda x: x < 3

#람다 함수 호출할 때 사용
output_a = map(lambda x: x*x)
output_b = filter(lambda x: x<3, list_input_a)

 

 

 

파일 열고 닫기

open() 함수

  • 파일 열기
  • 파일 객체 = open(문자열: 파일 경로, 문자열: 읽기 모드)
  • 첫 번째 인수에는 파일 경로 입력, 두 번째 인수에는 모드를 지정

* write모드: 존재하지 않는 파일을 새로 만들 때

* append모드: 존재하는 파일에 add on할 떄

 

close() 함수

  • 파일을 닫을 때 
file = open("basic.txt", "w")

file.write("baedalsikyo")

file.close()

 

with 키워드

  • 파일을 열고 닫지 않는 실수를 방지하기 위해 사용
  • with 구문이 종료될 때 자동으로 파일이 닫힌다.

 

텍스트 읽기

read() 함수

with open("basic.txt", "r") as file:
    contents = file.read()
print(contents)

 

랜덤으로 1000명 키와 몸무게 만들기

# 랜덤한 숫자를 만들기 위해 가져온다.
import random

#간단한 한글 리스트를 만든다.
hanguls = list("가나다라마바사아자차카타파하")

#파일을 쓰기 모드로 연다.
with open("info.txt", "w") as file:
    for i in range(1000):
        #랜덥한 값으로 변수를 생성한다.
        name = random.choice(hanguls) + random.choice(hanguls)
        weight = random.randrange(40, 100)
        height = random.randrange(140, 200)
        #텍스트를 쓴다. 
        file.write("{}, {}, {}\n".format(name, weight, height))

 

'Python' 카테고리의 다른 글

Day7. 웹프로그래밍 개요  (1) 2024.01.18
Day6. 객체지향 프로그래밍  (0) 2024.01.16
Day4. 딕셔너리와 반복문  (1) 2024.01.05
Day3. 조건문과 리스트  (2) 2024.01.04
Day2. 변수와 함수, 연산자  (1) 2024.01.03

 

 

A. 딕셔너리

  • 리스트가 '인덱스'를 기반으로 값을 저장하는 것이라면, 
  • 딕셔너리는 '키(Key)'를 기반으로 값을 저장하는 것이다.
  • 대괄호[ ]를 입력하고 내부에 인덱스처럼 키를 입력한다.
  • 참조할 때 리스트와 딕셔너리 차이
리스트 list_a = [] list_a[1]
딕셔너리 dict_a = {} dict_a["key"]
  • 모든 연속형 자료형의 중추는 리스트, 딕셔너리는 편집 가능한 리스트다.

 

in 키워드

딕셔너리 내부에 키가 있는지 없는지 확인한다. 

dictionary = {
    "name": "야채", 
    "age": 24, 
    "character": "활달함", 
    "nation": "한국"
}

#입력
key = input("접근하려는 키: ")

if key in dictionary:
    print(dictionary[key])
else:
    print("존재하지 않는 키에 접근하고 있다.")

접근하려는 키: 야채

>> 존재하지 않는 키에 접근하고 있다.

 

get() 함수

dictionary = {
    "name": "야채", 
    "age": 24, 
    "character": ["활달함", "호기심 많음"],
    "nation": "한국"
}

#입력
value = dictionary.get("name")
print("값:", value)
value2 = dictionary.get("health age")
print("값:", value2)

#None 확인 방법
if value or value2 == None:
    print("존재하지 않는 키에 접근했었습니다.")

값: 야채
값: None
존재하지 않는 키에 접근했었습니다.

 

값 추가 / 제거

  • dictionary['새로운 키"] = 새로운 값
  • del dictionary["이름"]

 

 

 

B. 딕셔너리 실습 오답노트

1. 자릿수를 구하는 방법

numbers = [123, 45, 63, 234, 352,123]

#My Answer
for number in numbers:
    if 100<= number<1000:
        print("{}는 3자릿수입니다.".format(number))
    elif 10<=number< 100:
        print("{}는 2자릿수입니다.".format(number))
    elif 0<number< 10:
        print("{}는 1자릿수입니다.".format(number))
    else:
        pass
        
 #Teacher's
for number in numbers:
    print("{}는 {}자릿수입니다.".format(number, len(str(number))))

 

2. 짝수 번째 요소를 제곱

#My Answer
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]

for i in range(0, len(numbers) // 2):
#My Answer : j = i+(i+1)
    #Teacher's
    j = i * 2 + 1
    print(f"i = {i}, j={j}")
    numbers[j] = numbers[j] **2
    
print(numbers)

 

 


 

C. 반복문

range() 범위

1. 숫자를 한 개 넣는 방법

  • range(n)
  • 0부터 n-1까지의 정수로 범위

2. 숫자를 두 개 넣는 방법

  • range(n1, n2)
  • n1부터 n2-1까지의 정수로 범위

3. 숫자를 두 개 넣는 방법 

  • range(n1, n2 , n3)
  • n1부터 n2-1까지의 정수로 범위를 만드는데, 간격이 n3
for i in range(4, 0-1, -1): #4부터, 마지막까지, -1에서 증감한 값 0
    print("현재 반복 변수: {}".format(i))

 

reversed() 

  • 함수와 반복문을 조합할 때는 함수의 결과를 여러 번 사용하지 않고 for 구문 내부에 reversed() 함수를 곧바로 넣어서 사용한다.
for i in reversed(range(5)):
    print("현재 반복 변수: {}".format(i))

현재 반복 변수: 4
현재 반복 변수: 3
현재 반복 변수: 2
현재 반복 변수: 1
현재 반복 변수: 0

 

enumerate()

  • 함수와 반복문 조합하기
  • for와 in 사이에 반복 변수를 두개 넣어서
  • index와 value를 각각 가져올 수 있다.
exapme_list = ["요소A", "요소B", "요소C"]

print("# enumerate() 함수 적용")
print(enumerate(exapme_list))
print()

print("# list() 함수로 강제 변환 출력")
print(list(enumerate(exapme_list)))
print()

print("# 반복문과 조합하기")
for i, value in enumerate(exapme_list): #반복설계구문
    print("{}번째 요소는 {}입니다.".format(i, value))

# enumerate() 함수 적용
<enumerate object at 0x000002569F183880>

# list() 함수로 강제 변환 출력
[(0, '요소A'), (1, '요소B'), (2, '요소C')]

# 반복문과 조합하기
0번째 요소는 요소A입니다.
1번째 요소는 요소B입니다.
2번째 요소는 요소C입니다.

 

튜플

  • (0, '요소A') 같은 것들
  • 수정 불가능한 리스트
  • 같은 요소여도 메모리가 적다.

itmes()

example_dictionary = {
    "키A": "값A", 
    "키B": "값B",
    "키C": "값C",
}

print("#딕셔너리의 items() 함수")
print("items():", example_dictionary.items())
print()

print("#딕셔너리의 items() 함수와 반복문 조합하기")

for key, element in example_dictionary.items():
    print("dictionary[{}] = {}".format(key, element))

#딕셔너리의 items() 함수
items(): dict_items([('키A', '값A'), ('키B', '값B'), ('키C', '값C')])

#딕셔너리의 items() 함수와 반복문 조합하기
dictionary[키A] = 값A
dictionary[키B] = 값B
dictionary[키C] = 값C

 

 

리스트 내포

  • 리스트 이름= [표현식 for 반복자 in 반복할 수 있는 것]
  • 리스트 이름 = [ 표현식 for  반복자 in 반복할 수 있는 것 if 조건문]
array = [i * i for i in range(0, 20, 2)]

print(array)

[0, 4, 16, 36, 64, 100, 144, 196, 256, 324]

array = ["사과", "자두", "초콜릿", "바나나", "체리"]
output = [fruit for fruit in array if fruit != "초콜릿"]

print(output)

['사과', '자두', '바나나', '체리']

 

이터레이터

  • 이터러블: 반복할 수 있는 것
  • 이터레이터: next() 함수를 적용해 하나하나 꺼낼 수 있는 요소
  • 필요한 요소만 꺼내 쓰기 때문에 메모리의 효율성을 높인다.
for 반복자 in 반복할 수 있는 것
  • reversed() 함수의 리턴값이 이터레이터
numbers = [1, 2, 3, 4, 5, 6]
r_num = reversed(numbers)

print("reversed_numbers:", r_num)
print(next(r_num))
print(next(r_num))
print(next(r_num))
print(next(r_num))
print(next(r_num))

6
5
4
3
2

 

 

기타

min(): 리스트 내부에서 최솟값을 찾는다.

max(): 리스트 내부에서 최댓값을 찾는다.

sum(): 리스트 내부에서 값을 모두 더한다.

'Python' 카테고리의 다른 글

Day6. 객체지향 프로그래밍  (0) 2024.01.16
Day5. 함수  (1) 2024.01.08
Day3. 조건문과 리스트  (2) 2024.01.04
Day2. 변수와 함수, 연산자  (1) 2024.01.03
Day1. 자료형  (1) 2024.01.02

Day3. 조건문과 리스트

0ㅑ채
|2024. 1. 4. 17:42

* 새롭게 배운 내용만 적었습니다. 교재는 '혼자 공부하는 파이썬

 

 

A. If 조건문

끝자리로 짝수와 홀수 구분

number = input("정수 입력> ")

last_character = number[-1]

last_number = int(last_character)

if last_number == 0 \
    or last_number == 2 \
    or last_number == 4 \
    or last_number == 6 \
    or last_number == 8:
    print("짝수입니다")
    
if last_number == 1 \
    or last_number == 3 \
    or last_number == 5 \
    or last_number == 7 \
    or last_number == 9:
    print("홀수입니다")

 

If문에서 코드가 너무 길면, \를 쓰고 다음 줄에 쓰면 된다!

위 코드를 더 단축시키면

num = int(input("정수를 입력해주세요: "))

if not(num % 2):
    print("{}은 2로 나누어 떨어지는 숫자입니다.".format(num))
else:
    print("{}은 2로 나누어 떨어지는 숫자가 아닙니다.".format(num))

Fals로 전환되는 값은 None, 숫자 0과 0.0, 빈 컨테이너(빈 문자열, 빈 바이트열, 빈 리스트, 빈 튜플, 빈 딕셔너리 등)이다. 

이 외에는 모두 True로 변환된다!

pass 키워드

아직 구현이 안된 종속문 대신 사용해준다.

 

 

 

B. 리스트

리스트

  • 대괄호[ ] 내부에 여러 종류의 자료를 넣어 선언한다.
array = [123, 45, "문자열", True]

 

  • 내부에 들어가는 자료를 요소·원소(element)라고 한다.
  • 접근 연산자를 이중으로 사용할 수 있다. 
list_a = [123, 45, "문자열", True, False]
print(list_a[3]) #True
print(list_a[2][0])#문

 

 

요소 추가 (단일)

append() : 리스트 뒤에 요소 추가

insert() : 리스트 중간에 요소 추가

list_a = [1, 2, 3]

print("#리스트 뒤에 요소 추가하기")
list_a.append(4)
list_a.append(5)
print(list_a) #[1, 2, 3, 4, 5]
print()

print("#리스트 중간에 요소 추가하기")
list_a.insert(0, 10)
print(list_a) #[10, 1, 2, 3, 4, 5]

 

요소 추가 (복수)

extend(): 리스트 뒤에 새로운 리스트 요소 모두 추가 (파괴적 처리)

list_a = [1, 2, 3]
list_b = [4, 5, 6]

print(list_a + list_b) #[1, 2, 3, 4, 5, 6]
print(list_a) #[1, 2, 3]

list_a.extend(list_b) 
print(list_a) #[1, 2, 3, 4, 5, 6]

 

요소 삭제 

  • 인덱스로 제거: del, pop()
  • 값으로 제거: remove()
  • 모두 제거: clear()
list_a = [0, 1, 2, 3, 4, 5]
print("#리스트의 요소 하나 제거하기")

# 인덱스로 제거
del list_a[1]
print(list_a) # [0, 2, 3, 4, 5]

list_a.pop(2)
print(list_a) # [0, 2, 4, 5]

# 값으로 제거
list_b = [1, 2, 1, 2]
list_b.remove(2)
print(list_b) # [1, 1, 2]

#모두 제거
list_c = [0, 1, 2, 3, 4, 5]
list_c.clear()
print(list_c) # [ ]

 

 

sort():  리스트 정렬하기 

  • 기본 오름차순 정렬
  • 내림차순 정렬 sort(reverse=True)
list_a = [24, 593, 5,103, 60, 920]
list_a.sort()
print(list_a) # [5, 24, 60, 103, 593, 920]

list_a.sort(reverse=True)
print(list_a) # [920, 593, 103, 60, 24, 5]
의문점) 파괴적 함수는 print() 안에서 출력되지 않는데?
list_b = [1, 2, 1, 2]
print(list_c.remove(2)) #None​

중첩된 함수는 내부에서부터 외부로 풀어나간다.
list_c.remove(2)는 list를 지우고 난 결과가 아니라 '지웠음' 그 자체이기 때문에, 반환값이 None이다.
일반적으로 None은 '성공했다'는 의미다. 

 

 

 

'Python' 카테고리의 다른 글

Day6. 객체지향 프로그래밍  (0) 2024.01.16
Day5. 함수  (1) 2024.01.08
Day4. 딕셔너리와 반복문  (1) 2024.01.05
Day2. 변수와 함수, 연산자  (1) 2024.01.03
Day1. 자료형  (1) 2024.01.02