묻고 답해요
131만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨실전! FastAPI 입문
pytest는 어떻게 모킹함수를 인지하는지
안녕하세요 강사님강의 정말 재밌게 보고 있습니다.수강 도중 궁금한 내용이 생겨 질문 남깁니다.mocker.patch("main.get_todo_by_todo_id", return_value=Todo(id=1,contents="todo",is_done=True))여기서 인자값으로 문자열 main.get_todo_by_todo_id 를 전달했는데, pytest는 어떻게 저 함수를 모킹대상으로 인지하나요? 개념적으로 설명해주시면 감사합니다~!! response = client.patch("/todos/1", json={"is_done":False})해당 api 를 호출하고 실행하는 과정에서main_get_todo_by_todo_id 함수를 호출할 때 어떻게 모킹처리가 되는지 궁금합니다.
-
해결됨실전! FastAPI 입문
타입힌트 질문
안녕하세요 강사님강의 듣는 도중 조금 궁금한 내용이 생겨서 질문드립니다. 코드에서 아래와 같이 타입힌트를 사용하는 경우가 있는데def done(self) -> "Todo": self>is done = True ~ 왜 Todo에 "" 를 감싸주시는걸까요??그냥 Todo 라고 타입힌트를 줘도될거 같은데 이유가 궁금해서요
-
해결됨실전! FastAPI 입문
코드 질문
안녕하세요.파이썬 2.7만 주로 쓰다 오랜만에 쓰니 좀 헷갈리는게 있어 질문드립니다.encoding: str = "UTF-8"service 작성하시면서 설명해주신 코드인데,encoding = "UTF - 8" 이렇게 써도 encoding 변수에 뭐가 들어가는지 바로 확인이 되는데 굳이 : str 과 타입을 명시할 이유가 있나요 ? 이렇게 작성하였을 때 왜 이렇게 작성하고 어떠한 장점이 있는지 궁금합니다.비슷한 질문으로 def save_user(self, user: User) -> User:다음과 같이 반환 타입을 적어줘야 하는 것도 설명 부탁드립니다.작성하면서도 이걸 굳이 적어줘야 하는지가 궁금해서 질문드립니다.
-
해결됨실전! FastAPI 입문
router testcode 문의
router test code 에서 test_main.py 파일에 api.todo라고 main을 바꾸어 줬는데 import를 따로 안 시켜줘도 되나요 ?main.py는 from api import todo로 import 시키는데 test_main.py는 안 그래도 되는지 궁금합니다.
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
태현님 안녕하세요!
좋은강의 만들어주셔서 감사합니다.잘보고있습니다. 테스트 코드 관련 궁금증이 생겨서 문의드립니다.BeforeEach 나 AfterEach 를 사용해서deleteAll() 등을 할때 Mysql 같은 DB 보다 In memory db가 조금더 적합할것같은데요 혹시현업에서도 로컬환경으로 개발하실때 DB 를 H2 In Memory DB 를 주로 사용하여 개발하셨는지 궁금합니다 !
-
해결됨실전! FastAPI 입문
docker 설치 에러
안녕하세요.윈도우 os 사용중이고 docker desktop 설치 시 이후데몬이 활성화가 안되어 질문드립니다.데몬 활성화를 위해서는 가상화 지원이 되어야 하는데, bios 세팅 및 os 가상화 설정을 모두 하여서 작업관리자에서 가상화:사용 이라고 까지 표기가 되어도 하이퍼바이저 지원이 안된다는 에러가 나옵니다.wsl 설치 또한 가상화가 지원이 안된다는 에러와 함께 설치가 안되어 구글링 이후 문의 드립니다.
-
해결됨실전! FastAPI 입문
uvicorn 실행 에러
안녕하세요.학습 도중 재부팅하여 다시 uvicorn 실행하려고 하니ERROR: Error loading ASGI app. Could not import module "main". 다음과 같은 메세지가 나오면서 fast api 앱이 실행이 안되는데 이유가 궁금합니다.
-
해결됨실전! FastAPI 입문
src 디렉토리를 기본으로 설정하는 방
from main import app이 아닌from src.main import app을 하게 되면 에러가 발생합니다. src. 을 생략할 수 있도록 하는 방법이 없을까요
-
해결됨실전! FastAPI 입문
session.scalar(select(1)) 에러 발생 질문입니다.
에러명은 다음과 같습니다. 도커 설정은 이상이 없는데 어디서 문제가 생긴걸까요pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1' ([WinError 10061] 대상 컴퓨터에서 연결을 거부했으므로 연결하지 못했습니다)")The above exception was the direct cause of the following exception:
-
해결됨실전! FastAPI 입문
DATABASE_URL 상수변수 질문
도커를 이용해 컨테이너를 실행시킬 때 root 사용자에 대해서 todos라는 비밀번호를 갖도록 설정을 해주었는데, DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos"상수 변수를 이용해 데이터베이스 연결 시도 시,(1045, "Access denied for user 'root'@'localhost' (using password: YES)") 이런 에러가 발생합니다.비밀번호를 설정하였는데도 왜 이렇게 발생하는 건가요?
-
해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
Kotlin에서 필드 정의할때 질문드립니다.
안녕하세요. 강의 다시 보기 하다가 질문이 생겨서 글 남깁니다. @Entity class Book( val name: String, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? = null, ) { } @Entity class Book( name: String, ) { var name: String = name private set @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L } 코틀린에서 필드를 기본생성자로 하는 방식과 클래스 본문으로 하는 방식으로의 차이가 궁금해서 질문드립니다! 감사합니다
-
해결됨실전! FastAPI 입문
(실습) ORM 적용 - HTTP Response 처리
from typing import List from fastapi import FastAPI, Body, HTTPException, Depends from pydantic import BaseModel from sqlalchemy.orm import Session from database.orm import ToDo from database.connection import get_db from database.repository import get_todos from schema.response import ListToDoResponse, ToDoSchema app = FastAPI() @app.get("/") def heath_check_handler(): return {"ping": "pong"} todo_data = { 1: { "id": 1, "contents": "실전! FastAPI 섹션 0 수강", "is_done": True, }, 2: { "id": 2, "contents": "실전! FastAPI 섹션 1 수강", "is_done": False, }, 3: { "id": 3, "contents": "실전! FastAPI 섹션 2 수강", "is_done": False, }, } @app.get("/todos", status_code=200) def get_todos_handler( order: str | None = None, session: Session = Depends(get_db), ) -> ListToDoResponse: todos: List[ToDo] = get_todos(session=session) if order and order == "DESC": return ListToDoResponse( todos=[ToDoSchema.from_orm(todo) for todo in todos[::-1]] ) return ListToDoResponse( todos=[ToDoSchema.from_orm(todo) for todo in todos] ) @app.get("/todos/{todo_id}", status_code=200) def get_todo_handler(todo_id: int): todo = todo_data.get(todo_id) if todo: return todo raise HTTPException(status_code=404, detail="ToDo Not Found") class CreateToDoRequest(BaseModel): id: int contents: str is_done: bool @app.post("/todos", status_code=201) def create_todo_handler(request: CreateToDoRequest): todo_data[request.id] = request.dict() return todo_data[request.id] @app.patch("/todos/{todo_id}", status_code=200) def update_todo_handler( todo_id: int, is_done: bool = Body(..., embed=True) ): todo = todo_data.get(todo_id) if todo: todo["is_done"] = is_done return todo raise HTTPException(status_code=404, detail="ToDo Not Found") @app.delete("/todos/{todo_id}") def delete_todo_handler(todo_id: int): todo = todo_data.pop(todo_id, None) if todo: return raise HTTPException(status_code=404, detail="ToDo Not Found") from typing import List from pydantic import BaseModel class ToDoSchema(BaseModel): id: int contents: str is_done: bool class Config: orm_mode = True class ListToDoResponse(BaseModel): todos: List[ToDoSchema] from typing import List from sqlalchemy import select from sqlalchemy.orm import Session from database.orm import ToDo def get_todos(session: Session) -> List[ToDo]: return list(session.scalars(select(ToDo))) from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos" engine = create_engine(DATABASE_URL, echo=True) SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) def get_db(): session = SessionFactory() try: yield session finally: session.close() from sqlalchemy import Boolean, Column, Integer, String from sqlalchemy.orm import declarative_base Base = declarative_base() class ToDo(Base): __tablename__ = 'todo' id = Column(Integer, primary_key=True, index=True) contents = Column(String(256), nullable=False) is_done = Column(Boolean, nullable=False) def __repr__(self): return f"ToDo(id={self.id}, contents={self.contents}, is_done={self.is_done})" 에러가 납니다. 파이썬 콘솔 <input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated; from schema.response import ToDoSchemafrom datagbase.orm import ToDoTraceback (most recent call last):File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcodecoro = func()^^^^^^File "<input>", line 1, in <module>File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\_pydev_bundle\pydev_import_hook.py", line 21, in do_importmodule = self._system_import(name, args, *kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ModuleNotFoundError: No module named 'datagbase'from database.orm import ToDotodo = ToDo(id=100, contents="test", is_done=True)ToDoSchema.from_orm(todo)<input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated; set model_config['from_attributes']=True and use model_validate instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/Traceback (most recent call last):File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcodecoro = func()^^^^^^File "<input>", line 1, in <module>File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapperreturn arg(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_ormraise PydanticUserError(pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm http://localhost:8000/docs#/default/get_todos_handler_todos_get접속시 터미널INFO: 127.0.0.1:56312 - "GET /docs HTTP/1.1" 200 OKINFO: 127.0.0.1:56312 - "GET /openapi.json HTTP/1.1" 200 OK2024-01-23 16:06:15,108 INFO sqlalchemy.engine.Engine BEGIN (implicit)2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine SELECT todo.id, todo.contents, todo.is_doneFROM todo2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine [cached since 826.5s ago] {}2024-01-23 16:06:15,113 INFO sqlalchemy.engine.Engine ROLLBACKINFO: 127.0.0.1:56312 - "GET /todos HTTP/1.1" 500 Internal Server ErrorERROR: Exception in ASGI applicationTraceback (most recent call last):File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 404, in run_asgiresult = await app( # type: ignore[func-returns-value]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 84, in callreturn await self.app(scope, receive, send)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\applications.py", line 1054, in callawait super().__call__(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\applications.py", line 123, in callawait self.middleware_stack(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 186, in callraise excFile "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 164, in callawait self.app(scope, receive, _send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in callawait wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_appraise excFile "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_appawait app(scope, receive, sender)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 762, in callawait self.middleware_stack(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 782, in appawait route.handle(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 297, in handleawait self.app(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 77, in appawait wrap_app_handling_exceptions(app, request)(scope, receive, send)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_appraise excFile "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_appawait app(scope, receive, sender)File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 72, in appresponse = await func(request)^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 299, in appraise eFile "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 294, in appraw_response = await run_endpoint_function(^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 193, in run_endpoint_functionreturn await run_in_threadpool(dependant.call, **values)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\concurrency.py", line 40, in run_in_threadpoolreturn await anyio.to_thread.run_sync(func, *args)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\to_thread.py", line 56, in run_syncreturn await get_async_backend().run_sync_in_worker_thread(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 2134, in run_sync_in_worker_threadreturn await future^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 851, in runresult = context.run(func, *args)^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\src\main.py", line 48, in get_todos_handlertodos=[ToDoSchema.from_orm(todo) for todo in todos]^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapperreturn arg(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_ormraise PydanticUserError(pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
코틀린에서 ModelMapper는 어떤지 궁금합니다.
안녕하세요! 강의를 모두 수강하고,최근 신규 프로젝트로 코틀린을 사용할 예정이라 강의를 다시 한번 곱씹어 보고 있습니다 궁금한 내용은 다름 아니라 java 프로젝트를 했을 때Entity > DTO 변환 시 필드의 추가/변경/삭제 시 누락을 방지하려고 ModelMapper를 자주 사용했던 기억이 있는데, 강사님 강의에서는 이러한 작업을 할 때 'of' 나, 'fixture' 와 같은 같은 팩토리 메서드를 주로 사용하시는 것을 보고궁금해서 찾아보니 코틀린은 매핑 관련 라이브러리를 잘 사용하지 않는다는 글도 있더라고요.. 혹시 이러한 부분은 어떻게 생각하시는지 궁금합니다!
-
해결됨실전! FastAPI 입문
test 코드 질문
강의 너무 잘보고 있습니다test 코드 실습 중에 생긴 문제인데요def test_update_todo(client, mocker): mocker.patch.object(ToDoRepository, "get_todo_by_todo_id", return_value=ToDo(id=1, contents="todo", is_done=True)) mocker.patch.object(ToDoRepository, "update_todo", return_value=ToDo(id=1, contents="todo", is_done=True)) body = { "is_done": False } response = client.patch("/todos/1", json=body) assert response.status_code == 200 assert response.json() == {"id": 1, "contents": "todo", "is_done": True} # 404 mocker.patch.object(ToDoRepository, "get_todo_by_todo_id", return_value=None) response = client.patch("/todos/1", json=body) assert response.status_code == 404 assert response.json() == {"detail": "ToDo Not Found"}이런식으로 test 코드를 작성한 다음에 리팩토링 과정에서 잘못선택되서 todo_id가 빠진 상태로 코드를 올렸습니다@router.patch("/{todo_id}", status_code=200) def update_todo_handler( todo_id: int, is_done: bool = Body(..., embed=True), todo_repo: ToDoRepository = Depends()): todo: ToDo | None = todo_repo.get_todo_by_todo_id() # 이 부분 todo_id를 빼버림 if todo: todo.done() if is_done else todo.undone() todo: ToDo = todo_repo.update_todo(todo) return ToDoSchema.from_orm(todo) else: raise HTTPException(status_code=404, detail="ToDo Not Found")이게 제가 잘못 작성한 코드고 todo.get_todo_by_todo_id 함수에 parameter를 안넣고 pytest를 실행해도 mocker.patch로 지정된 값이 넘어오게 되니까 에러가 나지 않더라구요 실행하면 당연히 500 internal error가 발생하는데 혹시 이런 경우까지 방지하도록 test 코드를 바꾼다면 어떻게 바꿔야할까요?
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
assertThat이 보이지 않습니다. ㅠㅠ
안녕하세요? 강의 잘 듣고 있습니다.강의를 들으면서 진행하고 있는데, assertThat을 import 할 수가 없고, 대신 import org.junit.jupiter.api.Assertions.assertEquals 이런 식으로 assertEquals가 import 되는데 혹시 이유를 알 수 있을까요? ㅠㅠ gradle은 pdf에서 제공해주신 내용을 그대로 사용하고 있습니다.감사합니다!plugins { id 'org.springframework.boot' version '2.6.8' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' id 'org.jetbrains.kotlin.jvm' version '1.6.21' } group = 'com.group' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() } compileKotlin { kotlinOptions { jvmTarget = "11" } } compileTestKotlin { kotlinOptions { jvmTarget = "11" } }
-
해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
kotlin first lambda에 관한 질문입니다.
안녕하세요 선생님 수업 잘 들었습니다. 질문이 있습니다.강의 == 13강9:20초 쯤에 returnBook을 작성하실때 fun returnBook(bookName: String) { this.userLoanHistories.first { it.bookName == bookName }.doReturn() }java 코드와는 다르게 orElseThrow()에 대한 구문이 없는데 생략해도 코틀린에서는 알아서 에러를 던져주는것인가요?
-
해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
userRepository.deleAll()관련 질문이 있습니다.
안녕하세요 선생님 강의잘듣고 있습니다. 질문이 2개 있습니다.강의 == 9강 책관련기능 테스트 작성하기1) 10:27 에 userRepository.deleteAll 이 자식 테이블 까지 지워주는게 User의 userLoanHistories 필드에 cascade, orphanRemoval 때문에 지워주는게 아닌가요?2) 상황에 따라 다르겠지만 보통 @OneToMany에서는 cascade = CascadeType.ALL, orphanRemoval = true 를 해주는게 좋나요?All 만 해줘도 User를 지우면 UserLoanHistories도 지워주게 되는것이 아닌가요?
-
해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
/v2/index.html로 책 등록시 서버에 연결이 불가능하거나, 네트워크 오류입니다. 라고 뜹니다ㅠㅠ
안녕하세요 최태현 강사님!강의 잘보고있습니다 : )다름이 아니라 제가 기존에 oracle을 사용하고 있어서 server port는 8089로 설정해서 사용하고 있습니다. localhost:8089/v1/index.html을 실행시켜서 사용자 등록, 책 등록을 하면 잘 실행이 되는데v2/index.html로 접속하여 책 등록을 하면 아무런 반응이 없다가 '서버에 연결이 불가능하거나, 네트워크 오류입니다.' 라는 alert 메시지를 봅니다. 이게 어떤 문제인지 알 수 있을까요??
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
혹시라도 @DiplayName 어노테이션이 동작하지 않으신다면
위에 처럼[Build, Execution, Deployment > Build Tools > Gradle]의 Run tests using 설정을 '인텔리제이'로 변경하고,인텔리제이를 재시작하시면 정상동작됩니다.
-
해결됨김영한의 실전 자바 - 기본편
반복문 리팩토링 질문드립니다.
안녕하세요 영한님!질문은 처음 드리는거 같습니다~ 기본형과 참조형 '문제와 풀이' 시간에ProductOrder를 리팩토링하는 부분에서 질문이 있습니다. 리팩토링 하는 과정에서 for문 안에서 수행하던 print와 totalAmount를 계산하는 로직을 각각 메서드로 나누었는데요,이렇게 되면 한번만 수행되던 반복문이 메서드로 나누면서 각각 수행되어 2번이 되는데 이런 부분은 for문이 한번 더 돌게되어 오는 성능이슈보다, 깔끔하게 리팩토링 되는 부분이 더 이점이 큰 부분일까요? 사실 현업에서 업무를 할때도,for안에서 여러가지 로직이 수행되면 한번에 파악하기가 어려워서 나눠야지 싶어서 나누었지만, 한번만 돌던 반복문이 여러번 돌게 될 수 있어서 망설여지는 부분이 있었습니다. 이 부분 질문드립니다!감사합니다~