<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자리</title>
    <link>https://edudeveloper.tistory.com/</link>
    <description>개발자 포트폴리오 준비하기 ! </description>
    <language>ko</language>
    <pubDate>Tue, 12 May 2026 23:53:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>개발자리</managingEditor>
    <item>
      <title>OSM tileserver 동아시아지역 잘라 사용하기.</title>
      <link>https://edudeveloper.tistory.com/183</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSM이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈소스 프로젝트로 지도 관련 프로젝트이며 전세계를 대상으로 개방형 월드맵 데이터베이스를 구현을 목표로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSM은 오픈소스인 만큼. 다양한 부가적인 플러그인이나 / 레이어 맵 이 엄청 많고 다양하다&amp;nbsp;&lt;br /&gt;따라서 맞춤형 지도 제작에 적합하고 유리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSM에 가장 큰 장점은 지도에 오류 정보를 내가 수정하고 내가 반영할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSM을 왜 직접만들어 사용하지?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 osm도 인터넷에서 사용하는 지도를 사용하면 네이버/카카오/구글 지도와 같이 그냥 API를 통해서 사용하면 간단하다. 다만 필자는 폐쇄망 Offline 환경에서 데이터를 사용할 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 직접만드는 이유 중 다른 하나는 OSM을 사용하여 만든 다른 오픈소스들이 인터넷에서 API등을 제공을 하지만 다만 외국이라/지원 폭이 넓지가 않은 경우 속도에 이슈가 걸릴 수 있다. 그럴 땐 내가 직접 빌드해서 사용하는게 맘 편하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSM pbf 다운로드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ubuntu와 Docker를 사용해서 빌드 할 것이다. Docker 같은 경우는 요즘 마이크로서비스들에 대하여 쿠버네티스와 같이&amp;nbsp; 교과서적으로 사용하기 때문에 사용방법은 스킵한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://download.geofabrik.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://download.geofabrik.de/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722907814211&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Geofabrik Download Server&quot; data-og-description=&quot;&quot; data-og-host=&quot;download.geofabrik.de&quot; data-og-source-url=&quot;https://download.geofabrik.de/&quot; data-og-url=&quot;https://download.geofabrik.de/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://download.geofabrik.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://download.geofabrik.de/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Geofabrik Download Server&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;download.geofabrik.de&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 페이지는 OSM 사용되는 파일을 pbf확장자로 만든 파일이다. 국가와&amp;nbsp; 원하는 지역을 다운로드해준다.&lt;br /&gt;필자는 빌드할려는&amp;nbsp; 지역이 중국 해역, 서해 지역 북한, 한국 일본 해역, 러시아 시베리아 극동지역이 필요하므로 해당 국가가 포함한 지역을 다운로드 할 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;OSM은 유저 커뮤니티가 만들어 pbf를 업데이트하는 방식으로 데이터의 크기는 국가의 크기보단 zoom 레벨에 따라 어떤 정보가 상세하게 존재하는지에 따라서 용량에 크기가 다르다. 일본이 중국보다 크고 시베리아보다 한국지역이 더 용량이 크다. 북한은 뭐.... 시리아..우즈베키스탄이랑 비슷하다. 그래도 있는것에 감사.... 따지고보면 한국도 굉장히 작은편인데 OSM에 정보를 입력하는 사람이 굉장히 적어서 그런지... 필자도 한번 재미로 id편집기를 사용해서 동네 편의점 정보나 입력해서 기여할려고해봤는데 생각보다 좀 귀찮은편 관심있으면 osm.kr나 osm wiki에 하는법이 자세히 나와있음&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvoMNw/btsIWivPdph/SSvutYLMZgZkQG76qKUfAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvoMNw/btsIWivPdph/SSvutYLMZgZkQG76qKUfAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvoMNw/btsIWivPdph/SSvutYLMZgZkQG76qKUfAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvoMNw%2FbtsIWivPdph%2FSSvutYLMZgZkQG76qKUfAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;900&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HHopj/btsIUvwpZcl/9X10vnSJO0SC2PcXvzUcp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HHopj/btsIUvwpZcl/9X10vnSJO0SC2PcXvzUcp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HHopj/btsIUvwpZcl/9X10vnSJO0SC2PcXvzUcp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHHopj%2FbtsIUvwpZcl%2F9X10vnSJO0SC2PcXvzUcp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;900&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드 할 지역들을 차례대로 다운로드 받은 후&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 해당 파일을 머지할 것이다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;OSM pbf 잘라쓰기/머지&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s02Tt/btsIVH3ZW6L/M4qgJrc1qPPLIi1Az9un7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s02Tt/btsIVH3ZW6L/M4qgJrc1qPPLIi1Az9un7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s02Tt/btsIVH3ZW6L/M4qgJrc1qPPLIi1Az9un7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs02Tt%2FbtsIVH3ZW6L%2FM4qgJrc1qPPLIi1Az9un7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;94&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1722914897237&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; apt-get install osmium-tool
 
 osmosis --read-pbf south-korea-latest.osm.pbf --read-pbf north-korea-latest.osm.pbf  --merge --write-pbf korea.osm.pbf
 
 osmosis --read-pbf korea.osm.pbf --read-pbf japan-latest.osm.pbf  --merge --write-pbf korea_jp.osm.pbf
 
 osmosis --read-pbf korea_jp.osm.pbf --read-pbf china-latest.osm.pbf  --merge --write-pbf korea_jp_cn.osm.pbf
 
osmosis --read-pbf korea_jp_cn.osm.pbf --read-pbf far-eastern-fed-district-latest.osm.pbf --merge --write-pbf merge.osm.pbf&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개 한번에 하면 좋겠지만 두개씩 나눠서 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 merge.osm.pbf 파일이 나온다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSM Build/RUN 하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 이제 overv/openstreetmap-tile-server를 이미지를 사용할 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Overv/openstreetmap-tile-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Overv/openstreetmap-tile-server&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722919520614&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Overv/openstreetmap-tile-server: Docker file for a minimal effort OpenStreetMap tile server&quot; data-og-description=&quot;Docker file for a minimal effort OpenStreetMap tile server - Overv/openstreetmap-tile-server&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Overv/openstreetmap-tile-server&quot; data-og-url=&quot;https://github.com/Overv/openstreetmap-tile-server&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MCEN2/hyWKDGAudy/p76zQGfKzaNfW9kemQHjdK/img.png?width=1200&amp;amp;height=600&amp;amp;face=973_133_1053_221&quot;&gt;&lt;a href=&quot;https://github.com/Overv/openstreetmap-tile-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Overv/openstreetmap-tile-server&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MCEN2/hyWKDGAudy/p76zQGfKzaNfW9kemQHjdK/img.png?width=1200&amp;amp;height=600&amp;amp;face=973_133_1053_221');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Overv/openstreetmap-tile-server: Docker file for a minimal effort OpenStreetMap tile server&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker file for a minimal effort OpenStreetMap tile server - Overv/openstreetmap-tile-server&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github주소이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;git clone https://github.com/Overv/openstreetmap-tile-server.git&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd openstreetmap-tile-server&lt;/p&gt;
&lt;pre id=&quot;code_1722919767079&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t overv/openstreetmap-tile-server .


docker volume create osm-data
docker volume create osm-tiles

docker run \
    -v /data/merge.osm.pbf:/data/region.osm.pbf \
    -v osm-data:/data/database/ \
    -v osm-tiles:/data/tiels/ \
    overv/openstreetmap-tile-server \
    import&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 import 까지 해서 pbf파일을 가지고 사전 데이터베이스 빌드하는 과정을 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker run \
    --name osm \
    -p 8080:80 \
    -v osm-data:/data/database/ \
    -v osm-tiles:/data/tiels/ \
    -d overv/openstreetmap-tile-server \
    run&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp; 볼륨에 빌드된 파일을 가지고 실행해주면된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eni4k/btsIXt43BKq/0ikvv84wkda1NuYkyJa6Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eni4k/btsIXt43BKq/0ikvv84wkda1NuYkyJa6Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eni4k/btsIXt43BKq/0ikvv84wkda1NuYkyJa6Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEni4k%2FbtsIXt43BKq%2F0ikvv84wkda1NuYkyJa6Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한식으로 중국, 극동시베리아, 한반도, 일본 지역을 병합한 영상이 출력된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSM은 특정지역에 줌(호출) 했을 때 Png파일이 생성되는데 이걸 랜더링이라고 하는것 같다. 따라서 한번 씩 다 호출하여 필요 사전 렌더링을 할 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker exec -it osm render_list -n 10 -a -z 0 Z 20&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-n 쓰레드 옵션 갯수&lt;br /&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;-a 지역&lt;br /&gt;&lt;/span&gt;-z&amp;nbsp; 최소 줌&lt;br /&gt;-Z 최대 줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;줌레벨은 1부터 20까지 있으며 한 단계 올라 갈 때마다 약 4배의 png 파일이 더 생성된다고 생각하면된다. 시간도 4배씩 증가.&amp;nbsp; 따라서 빌드 시간과 디스크 용량을 계산하여 미리 사전랜더링을 하면된다.&lt;/p&gt;</description>
      <category>GIS</category>
      <category>openstreetmap-tile-server</category>
      <category>osm</category>
      <category>tile server</category>
      <category>국가여러개</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/183</guid>
      <comments>https://edudeveloper.tistory.com/183#entry183comment</comments>
      <pubDate>Tue, 6 Aug 2024 14:19:45 +0900</pubDate>
    </item>
    <item>
      <title>이미지 처리(Image Processing)란?</title>
      <link>https://edudeveloper.tistory.com/182</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;이미지 처리(Image Processing)란?&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아날로그 이미지 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아날로그 이미지 처리는 사진 촬영 시 필름에 다양한 화학 처리를 하거나 카메라로 촬영한 이미지를 변경 및 편집하기 위해 물리적 필터를 사용하는 등 물리적 수단을 이용해 이미지를 조작하거나 편집.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디지털 이미지처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터가 디지털 이미지를 처리하는데 수학적 알고리즘과 계산 기술에 의존함. 이러한 기술에는 이미지 향상(Image upscaling), 이미지 복원(Image restoration), 특징 추출(feature extraction)등이 있음,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디지털 이미지 처리의 메커니즘을 살펴보면 모든 이미지의 구성요소인 픽셀의 역할을 이해하는것이 중요함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 픽셀은 색상과 강도에 대한 정보를 담고 있습니다. 이미지 처리 알고리즘은 이러한 픽셀에서 작동하여 이미지에서 중요한 정보를 향상 변환 또는 추출 할 수 있게 해줌.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이미지 처리 단계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지 획득: (이미지에 품질을 보존하면서 디지털 시그널로 변환하는게 중요, 여러 문제를 줄일려면 노이즈, 왜곡 빛의 변환등 처리 기술)&lt;/li&gt;
&lt;li&gt;이미지 개선: (Image enhancement)단계에서는 이미지의 품질을 향상시키는 데 초점을 맞춥니다. (노이즈 제거, 명암 조절, 색상 보정) 등의 작업을 포함 (histogram equalized , 샤프닝)&lt;/li&gt;
&lt;li&gt;이미지 분석: 이미지의 유용한 정보를 추출함 이는 특징 추출, 패턴 인식, 객체 감지 등의 작업을 포함함 이 단계의 목표는 이미지에 의미 잇는 데이터를 얻는 것 입니다. 이를 위해 엣지 검출 코너 검출 텍스처 분석등의 기술이 사용 됨&lt;/li&gt;
&lt;li&gt;이미지 해석 및 이해.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 분석 단계에서는 이미지 분석 단계에서 얻은 데이터를 이용하여 이미지를 해석하고 이해합니다. 이는 이미지 분류(image classification), 이미지 검색(image retrieval), 이미지 인식(image recognition) 등의 작업을 포함함. 이 단계에서 목표는 이미지에서 얻은 데이터를 의미 있는 방식으로 사용하는 것. 이를 위해 패턴 매칭(pattern matching), 머신 러닝(ML), 딥 러닝(DL) 등의 기술이 사용 됨.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴퓨터 비전이란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이미지 처리와 컴퓨터 비전&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 처리와 컴퓨터 비전은 공통점이 많지만 목적과 접근 방식에서 중요한 차이점이 있습니다. 두 분야 모두 디지털 이미지를 사용하여 우리가 세상을 이해하는 방식을 확장하고 변형하는데 초점을 맞추고 있지만 추구하는 목표와 사용하는 기술은 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 처리는 주로 디지털 이미지 향상, 변형, 복원 등에 중점을 둡니다. 반면 컴퓨터 비전은 이미지 처리에서 생성된 이미지를 분석하고 해석하는데 초점을 맞춥니다. 그래서 컴퓨터 비전은 더 높은 수준의 이해를 필요로 하며, &lt;b&gt;객체 인식&lt;/b&gt;, &lt;b&gt;패턴 분석&lt;/b&gt;, &lt;b&gt;이미지 분류&lt;/b&gt; 등의 작업에 포함됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 비전의 목표는 디지털 이미지를 통해 우리가 세상을 인식하고 이해하는 방식을 모방하고, 이미지로부터 의미 있는 정보를 추출하는 것.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컴퓨터 비전의 정의.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각 기계의 과학 및 기술입니다. 좀 더 구체적으로 이미지에서 정보를 추출하는 인공 시스템의 이론과 관련이 있습니다. 이미지 데이터는 비디오 시퀀스, 여러 카메라의 뷰 또는 의료용 스캐너의 다차원 데이터 등 다양한 형태를 취할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 비전과 인간의 비전은 비슷한 목표를 공유하지만 프로세스에서는 큰 차이가 있습니다. 인간은 수년간 신경 훈련 개발이 필요한 작업인 물체를 쉽게 인식하고 장면의 깊이를 인식합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낮은 수준 비전 작업&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노이즈 제거&lt;/li&gt;
&lt;li&gt;대비 향상&lt;/li&gt;
&lt;li&gt;채도 항샹&lt;/li&gt;
&lt;li&gt;엣지 검출&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간 수준 비전 작업&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지 영역 분할&lt;/li&gt;
&lt;li&gt;이미지 객체로 분할&lt;/li&gt;
&lt;li&gt;이미지 광학 흐름 추정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;높은 수준 비전 작업&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 인식&lt;/li&gt;
&lt;li&gt;장면 재구성&lt;/li&gt;
&lt;li&gt;이미지 학습 및 추론&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 기술의 초석은 이미지에서 가장자리, 모서리 또는 텍스처와 같은 고유한 속성을 추출하는 &lt;b&gt;특징 추출&lt;/b&gt;입니다.&lt;/p&gt;</description>
      <category>Python/Python OpenCV</category>
      <category>이미지 프로세싱</category>
      <category>컴퓨터 비전</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/182</guid>
      <comments>https://edudeveloper.tistory.com/182#entry182comment</comments>
      <pubDate>Fri, 2 Aug 2024 15:27:31 +0900</pubDate>
    </item>
    <item>
      <title>[Ubuntu] Ubuntu 23.04 default source.list</title>
      <link>https://edudeveloper.tistory.com/180</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본 패키지 [백업용]&lt;/p&gt;
&lt;pre class=&quot;awk&quot; style=&quot;background-color: #f6f8fa; color: #1f2328; text-align: start;&quot;&gt;&lt;code&gt;deb http://mirrors.aliyun.com/ubuntu/ lunar main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ lunar main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ lunar-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ lunar-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ lunar-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ lunar-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ lunar-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ lunar-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ lunar-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ lunar-backports main restricted universe multiverse&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[KOR]&lt;/p&gt;
&lt;div style=&quot;color: #1f2328; text-align: start;&quot;&gt;
&lt;pre id=&quot;code_1720145756575&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://kr.archive.ubuntu.com/ubunu lunar main restricted
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://kr.archive.ubuntu.com/ubuntu lunar-updates main restricted
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://kr.archive.ubuntu.com/ubuntu lunar universe
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar universe
deb http://kr.archive.ubuntu.com/ubuntu lunar-updates universe
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://kr.archive.ubuntu.com/ubuntu lunar multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar multiverse
deb http://kr.archive.ubuntu.com/ubuntu lunar-updates multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://kr.archive.ubuntu.com/ubuntu lunar-backports main restricted universe multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-backports main restricted universe multiverse

deb http://kr.archive.ubuntu.com/ubuntu lunar-security main restricted
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-security main restricted
deb http://kr.archive.ubuntu.com/ubuntu lunar-security universe
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-security universe
deb http://kr.archive.ubuntu.com/ubuntu lunar-security multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu lunar-security multiverse
# deb https://ppa.launchpadcontent.net/mc3man/trusty-media/ubuntu lunar main&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;변경 후&lt;/div&gt;
&lt;div&gt;$sudo apt update&lt;/div&gt;</description>
      <category>Linux/Ubuntu</category>
      <category>ubuntu</category>
      <category>ubuntu 23.04 default source.list</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/180</guid>
      <comments>https://edudeveloper.tistory.com/180#entry180comment</comments>
      <pubDate>Fri, 5 Jul 2024 11:12:28 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 함수형 프로그래밍 이란</title>
      <link>https://edudeveloper.tistory.com/179</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍 페러다임에서는 프로그램의 상태를 변경하는 일련의 흐름의 단계가 아닌 수학적인 함수 평가를 통한 프로그램 플로우를 달성한다. 순수한 함수형 프로그래밍 상태의 변경을 피하고 가변데이터 구조를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍의 일반적인 기본 용어를 아라보자&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Side Effect(부작용): 함수가 자신의 로컬 환경 바깥에 있는 상태를 수정한다면 해당 함수는 Side Effect을 가진다. 다시 말해 &lt;b&gt;Side Effect이란 함수를 호출한 결과로 발생되는 함수 바깥에서 관찰 할 수 있는 모든 변경이다.&lt;/b&gt; Side Effect의 예시로는 글로벌 변수의 수정, 함수 범위 바깥에서 이루어지는 객체의 속성 변경, 외부 서비스로의 데이터 저장 등이 있다. side effect는 OOP 개념의 핵심이다. OOP에서는 클래스 인스턴스의 애플리케이션의 상태를 캡슐화 하기 위해 사용되는 객체이고, 메서드는 이 객체들의 상대를 조작하기 위해 해당 객체에 바인드 된 함수이다.&lt;/li&gt;
&lt;li&gt;Referential Transparency(참조 투명성): &lt;b&gt;함수 또는 표현식이 참조적으로 투명&lt;/b&gt;하면 이를 그 출력값에 해당하는 값으로 바꾸어도 프로그램의 동작을 변경하지 않는다. 그러므로 Side Effect 없는 것은 참조 투명성을 위한 필요 조건이지만, Side Effect 없는 모든 함수가 Referential Transparency 는 아니다 (필요충분조건 오랜만에보네..,,)&amp;nbsp; 예를 들어 pow(x, y)는 Referential Transparency 한 함수다 ( 참조하는 변수가 다 보임) 하지만 datetime.now()같은 것은 Referential Transparency 은 아니다.&lt;/li&gt;
&lt;li&gt;Pure Function(순수 함수): 순수 함수는 부작용을 갖지 않으며 &lt;b&gt;같은 입력에 대해 항상 같은 값을 반환하는 함수&lt;/b&gt;, 달리 말하면 이 함수는 참조적으로 투명하다. 모든 수학적 함수는 정의상 순수 함수다.&lt;/li&gt;
&lt;li&gt;First-Class Function(1급 함수): 어떤 언어의 함수가 다른 값 또는 엔티티로서 취급되며 이 언어는 1급함수를 갖고 있다고 부른다. 1급 &lt;b&gt;함수들은 인수로 전달될 수 있고, 함수 반환값으로 변환되며 변수에 할당될 수 있&lt;/b&gt;다. 다시 말해, 1급 함수를 가진 언어는 함수를 1급 시민으로 다룬다. 파이썬의 함수들은 1급 함수다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;따라서.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 언어는 다음과 같이 정의 할 수 있따.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;First-Class Function - 1급 함수를 가진 언어&lt;/li&gt;
&lt;li&gt;Pure Function&amp;nbsp; - 순수 함수만을 다루는 언어&lt;/li&gt;
&lt;li&gt;모든 상태 수정과 Side Effect를 피하는 언어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다만&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은&amp;nbsp; 순수한 함수형 프로그래밍언어가 아니라서 어떤 Side Effect도 갖지 않는 완전히 순수한 함수로만 사용해서 만든 유용판 파이썬 라이브러리를 찾기 힘들지만 다른 언어에서 함수형언어에서 사용할 수 있는 순수한 함수들을 몇 개 가지고있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;람다 함수와 1급함수&lt;/li&gt;
&lt;li&gt;map(), filter(), reduce()&lt;/li&gt;
&lt;li&gt;부분 객체 및 부분함수&lt;/li&gt;
&lt;li&gt;제네레이터 및 제네레이터 표현식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 순수한 함수형 언어는 아니지만 피처들을 이용하면 함수형 언어적인 방식으로 코드를 작성 할 수 있따&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>파이썬</category>
      <category>파이썬 함수형프로그래밍</category>
      <category>함수형 프로그래밍</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/179</guid>
      <comments>https://edudeveloper.tistory.com/179#entry179comment</comments>
      <pubDate>Wed, 3 Jul 2024 18:21:40 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 싱글-디스패치 함수(single-dispatch function)</title>
      <link>https://edudeveloper.tistory.com/178</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍에서 JAVA나 C++ (다른랭기지도 있겠지만 생략) 등 에서 같은 함수를 2개 이상 작성하여 매개변수에 따라서 함수 처리를 다르게 하는 것을 본 적이 있을것이다. 그것을 오버로딩이라고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;파이썬은 오버로딩을 지원하지 않는다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면 오버로딩은 지원하지 않는다. 파이썬은 연산자 오버로딩(던더메서드를 활용한 add, sub 등등) 은 제공하지만 함수와 메서드 오버로딩은 지원하지 않는다. 한 모듈 안에서 같은 이름을 사용하면 맨 마지막으로 정의된 매서드가 앞에 모든 정의를 덮어 씌워버린다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그렇다면 오버로딩을 못하나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 쉬운 언어이므로 다른 방법으로 메서드 오버로딩과 같은 개념으로 지원한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드/서브클래싱을 이용: 함수가 매개변수를 구분하도록 해당 타입의 메서드로 정의함으로써 특정한 타입과 연결 할 수 있슴.&lt;/li&gt;
&lt;li&gt;인수와 키워드 인수 언패킹 이용: 파이썬은 가변함수 *args, **kwars 패턴을 통해 여러 인수를 함수 시그니처나 사용할 수 있는 기능을 제공함&lt;/li&gt;
&lt;li&gt;타입 체킹 이용: isinstance 메서드를 이용하여 입력 인수를 특정 타입 및 클래스와 비교 한뒤 처리 방법을 결정 할 수 있슴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제 isinstance를 활용한&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719991203907&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Calculator:
    def add(self, a, b):
        if isinstance(a, int) and isinstance(b, int):
            return a + b
        elif isinstance(a, float) and isinstance(b, float):
            return a + b
        else:
            raise TypeError(&quot;Unsupported operand types&quot;)

# Example usage
calc = Calculator()
print(calc.add(2, 3))  # Output: 5
print(calc.add(2.5, 3.7))  # Output: 6.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 자동적으로 float과 int에 연산을 지원하긴 하지만 그냥 예제용으로 느낌만 보면&amp;nbsp;&lt;br /&gt;인자가 정수형으로 올 때 와 실수형으로 올때 조건을 다르게 가진다 이것으로 다른 언어에서 오버로딩을 구현할 수 있고 같은 개념이라고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이러한 방법에 한계는 존재한다. 이 기법은 함수 호출 시그니처의 수가 적을 떄 는 매우 편리하게 이용할 수 있지만 지원하는 타입의 수가 많아지면 보다 모듈화된 패턴을 사용하는 것이 좋다. 이런 패턴들은 싱글-디스패치 함수에 의존한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이것에 대한 해결 방법은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 오버로딩의 대한이 필요하고 대안 함수를 많이 구연해야 하는 경우라면 if instance 사용은 선택지에서 배제해도 된다 왜냐하면 입력 인수를 다르게 처리하기 위해 여러 갈래로 나뉘는 큰 함수를 만드는 것은 썩 좋은 디자인은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 표준 라이브러리에서는 보다 편리한 대안을 제공한다 functools.singledispatch()&amp;nbsp; 데커레이터를 이용하면 한 함수의 여러 구현을 등록 할 수 있다 이것은 인수를 수의 제한 없이 받을 수 있지만 구현은 첫 번쨰 인수의 타입에 선정(dispatch) 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1719992839826&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from numbers import Real
from datetime import datetime
from functools import singledispatch


@singledispatch
def report(value):
    return f&quot;raw: {value}&quot;


@report.register
def _(value: datetime):
    return f&quot;dt: {value.isoformat()}&quot;


@report.register
def _(value: Real):
    return f&quot;real: {value:f}&quot;


@report.register
def _(value: complex):
    return f&quot;complex: {value.real}{value.imag:+}j&quot;


print(report(datetime.now()))
print(report(100 - 30j))
print(report(&quot;January&quot;))
print(report(9001))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 single-dispatch 기법을 적용하여 파이썬에서 오버로딩 한 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;_ 토큰을&amp;nbsp; 함수 이름으로 사용한 점에 주의한다. 여기에는 두가지 목적이 있다. 첫 번째, 이는 명시적으로 사용되지 않아야 하는 객체의 이름에 관습적으로 사용한다. 두 번째 report라는 이름을 이용하면 원래 함수를 숨기게 되므로 그 함수에 접근해 새로운 타입을 정의할 수 없게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;report()함수는 등록된 함수 컬렉션의 진입점(entrypoint)이 된다.&amp;nbsp; 인수를 전달해서 호출할 때마다 report.registry에 저장된 등록 매핑을 검색한다. 언제나 최소 하나의 키가 객체 타입을 함수의 기본 구현에 매핑한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 안에서도 사용하는 방법을 아라보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;functiools.singledispatch() 메서드를 그대로 받으면 항상 첫 번째 인수는 self이므로 해당 방법은 적합하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친절하게 functools에서 singledispatchmethod() 라는 함수를 지원해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1719993320576&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Exmaple:
    
    @singledispatchmethod
    def method(self, argument):
        pass

    @method.register
    def _(self, argument: float):
        pass&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 &lt;b&gt;파이썬에서는 오버로딩과 유사한 다형성 같지는 않다는 점에 주의해야한다&lt;/b&gt;. 또한 여러 인수에 타입에 대한 하나의 함수의 여러구현을 제공할 수 없으며 파이썬 표준라이브러리는 현재 이러한 다중-디스패치 유틸리티를 제공하지 않는다,.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 작성하던 와 중에 pypi multipledispatch 가 존재하긴 하는 것 같긴한데 관리를 안하는 것 같아 과감하게 패스했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>Python</category>
      <category>python overloading</category>
      <category>python single dispatch</category>
      <category>python single-dispatch</category>
      <category>python 다형성</category>
      <category>오버로딩</category>
      <category>파이썬 싱글 디스패치</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/178</guid>
      <comments>https://edudeveloper.tistory.com/178#entry178comment</comments>
      <pubDate>Wed, 3 Jul 2024 16:59:58 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 디스크립터(Discriptor)</title>
      <link>https://edudeveloper.tistory.com/177</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;디스크립터란 무엇인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서는 다른언어와 다르게 디스크립터 라는 개념이 있다.&lt;br /&gt;이게 무엇이냐면&amp;nbsp; 객체 속성을 참조했을 때 어떻게 되어야 하는지 커스터마이즈 할 수 있다.&lt;br /&gt;다시 말해 클래스는 한 속성의 관리를 다른 클래스에게 위임(delegate) 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크립터 클래스들은 세 개의 특별한 메서드에 기반하며, 이 클래스들은 디스크립터 프로토콜을 형성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;__set__(self, obj, vaule): 흔히 아는 세터 (Setter)다.&lt;/li&gt;
&lt;li&gt;__get__(self, obj, owner=None): Getter&lt;/li&gt;
&lt;li&gt;__detete__(self, obj): 속성에서 del이 불렸을 때 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__get__, __set__ 을 구현한 디스크립터를 데이터 디스크립터라고 부른다,&amp;nbsp;&lt;br /&gt;__get__ 만 구현한 디스크립터를 비데이터 디스크립터라 부른다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크립터의 메서드 속성을 확인하기 위해 __getatrribute__() 메서드로 호출되며 이것이 암묵적으로 호출되고 이것으로 디스크립터인지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습&lt;/p&gt;
&lt;pre id=&quot;code_1719969397605&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class RevealAccess(object):
    &quot;&quot;&quot;데이터 데커레이터로 일반적인 값을 설정하고 반환하며, 접근에대한 로깅메시지를 표기한다.&quot;&quot;&quot;

    def __init__(self, initval=None, name=&quot;var&quot;):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print(&quot;Retrieving&quot;, self.name)
        return self.val

    def __set__(self, obj, val):
        print(&quot;Updating&quot;, self.name)
        self.val = val

    def __delete__(self, obj):
        print(&quot;Deleting&quot;, self.name)


class MyClass(object):
    x = RevealAccess(10, 'var &quot;x&quot;')
    y = 5


m = MyClass()
m.x  # get이 호출되면서 Retrieving var&quot;x&quot;가 출력된다.
m.x = 20  #  set이 호출되면서 Updating var&quot;x&quot;가 출력된다.

del m.x  # delete가 호출되면서 Delete var &quot;x&quot;가 출력된당&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드를 통해 디스크립터(get,set,delete) print로 출력한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그래서 이게 getter/setter라고 하면 되지 왜 굳이 디스크립터로 나누지? 다른게 있나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 차이점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의&amp;nbsp;위치:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getter/Setter: 인스턴스 메서드로 정의되며 인스턴스 속성 접근을 제어함&lt;/li&gt;
&lt;li&gt;Descriptor: 클래스 레벨에서 정의되며 인스턴스 및 클래스 속성 접근을 모두 제어함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유연성:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getter/Setter: 특정 속성에 대해 제한된 동작만을 정의합니다.&lt;/li&gt;
&lt;li&gt;Descriptor: __get__, __set__, __delete__ 메서드를 통해 다양한 속성 접근 동작을 정의할 수 있으며, 여러 클래스에서 재사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용&amp;nbsp;편의성:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getter/Setter: 단순한 속성 접근 제어에 적합하며, 코드가 더 직관적이고 간단함&lt;/li&gt;
&lt;li&gt;Descriptor: 더 복잡한 속성 접근 로직을 구현해야 할 때 유용하며, 보다 정교한 제어가 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재사용성:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getter/Setter: 특정 클래스의 특정 속성에 국한됨&lt;/li&gt;
&lt;li&gt;Descriptor: 여러 클래스에 걸쳐 재사용될 수 있는 독립적인 구성 요소&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 디스크립터 프로토콜을 이용해 클래스 함수를 인스턴스 메서드로 바인드 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크립터는 classmethod와 staticmethod 데커레이터 메커니즘의 기반이 된다. 실제로 해당 함수 객체가 비데이터 객체이기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1719971316966&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(hasattr(function, &quot;__get__&quot;))  # True
print(hasattr(function, &quot;__set__&quot;))  # False&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 hasattr 메서드로 결과를 출력하면 get은 True, set은 False로 나뉜다. 따라서 이것은 비데이터 디스크립터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 __dict__메서드가 비 데이터 디스크립터 보다 우선하지 않는다면, 이미 생성된 인스턴스으 특정 메서드를 런타임에 동적으로 오버라이딩 할 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 멍키패칭이라는 기법을 이용해서 서브 클래싱 하지 않고도 어떤 애드혹으로 동작하도록 변경한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;멍키패칭;&amp;nbsp; 대충 아래와 같은 코드로 함수를 바꿔치기하여 오버라이딩함.&lt;br /&gt;&lt;br /&gt;class MyClass:&lt;br /&gt;&amp;nbsp; &amp;nbsp; def greet(self):&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &quot;Hello&quot; &lt;br /&gt;&lt;br /&gt;def new_greet(self): &lt;br /&gt;&amp;nbsp; &amp;nbsp; return &quot;Hello, Monkey Patch!&quot;&lt;br /&gt;MyClass.greet = new_greet &lt;br /&gt;obj = MyClass()&lt;br /&gt;print(obj.greet())&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속성평가지연;사용 예시) 클래스가 임포트 되는 시점에 아직 사용할 수 없는 콘텍스트에 따라 이 속성들을 초기화 해야하는 경우가 있따. 이럴때 컴퓨팅 자원들이 필요하지만, 클래스가 임포트 되는 시점에 그 사용 여부를 알 수 있는 경우도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719972442665&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class InitOnAccess:
    def __init__(self, init_func, *args, **kwargs):
        self.klass = init_func
        self.args = args
        self.kwargs = kwargs
        self._initialized = None

    def __get__(self, instance, owner):
        if self._initialized is None:
            print(&quot;initialized&quot;)
            self._initialized = self.klass(*self.args, **self.kwargs)
        else:
            print(&quot;cached!&quot;)
        return self._initialized&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 (디스크립터)클래스는 몇몇 print() 호출을 포함하고 잇으며 이를 이용해 값에 접근 시 초기화되는지, 캐시에 해당 값에 접근하는지 확인 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 다른 클래스가 있다고 가정해보자.&lt;br /&gt;이 클래스는&amp;nbsp; 정렬된 무작위 값으로 이루어진 공용 리스트에 접근할 수 있다, 또한 리스트의 길이는 자유롭게 변할 수 있고, 모든 인스턴스는 하나의 리스트를 재사용한다.&amp;nbsp; 매우 긴 리스트를 정렬하는데는 많은 시간 이 걸릴 것 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1719973431259&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random


class InitOnAccess:
    def __init__(self, init_func, *args, **kwargs):
        self.klass = init_func
        self.args = args
        self.kwargs = kwargs
        self._initialized = None

    def __get__(self, instance, owner):
        if self._initialized is None:
            print(&quot;initialized&quot;)
            self._initialized = self.klass(*self.args, **self.kwargs)
        else:
            print(&quot;cached!&quot;)
        return self._initialized


class WithSortedRandoms:
    lazily_initialized = InitOnAccess(sorted, [random.random() for _ in range(5)])


m = WithSortedRandoms()
print(m.lazily_initialized)  # initialized
# [0.09225735667653667, 0.4460156144933808, 0.4802389291835204, 0.7955825518506061, 0.826629276623519]
print(m.lazily_initialized)  # cached!
# [0.09225735667653667, 0.4460156144933808, 0.4802389291835204, 0.7955825518506061, 0.826629276623519]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크립터로 정의된 클래스(InitOnAccess)에&amp;nbsp; WithSortedRandom클래스를 만들어서 호출 하므로 처음에 생성하고 그 후 캐시가 된다. 이것을 지연적 방법으로 디스크립터를 활용해서 호출한 예씨이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719976212754&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class lazy_proerty(object):
    def __init__(self, function):
        self.fget = function

    def __get__(self, obj, cls):
        value = self.fget(obj)
        setattr(obj, self.fget.__name__, value)
        return value


class WithSortedRandoms:
    @lazy_proerty
    def lazily_initialized(self):
        return sorted([[random.random() for _ in range(5)]])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setattr() 함수로 위치 전달한 위치 인수의 속성을 이용하여 객체 인스턴스의 속성을 설정할 수 있다.&lt;br /&gt;이때의 형태는 self.fget.__name__이다.&amp;nbsp; 이런 형태로 구성 된 이유는 lazy_property가 디스크립터가 해당 메서드의 데커레이터이며, 프러퍼티 데커레이터로 사용하기 위해서이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 속성은 디스크립터 보다 우선하므로, 해당 클래스 인스턴스에 대해서는 더 이상 초기화가 수행 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기법을 사용하려면 두 가지 요구사항을 동시에 만족해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 객체 인스턴스가 클래스 속성으로 저장되어, &lt;b&gt;해당 클래스의 인스턴스 사이에서 공유된다&lt;/b&gt;( 리소스 절약 목적)&lt;/li&gt;
&lt;li&gt;이 객체는&lt;b&gt; 임포트 시점에 초기화 되어서는 안된다&lt;/b&gt;. 생성 프로세스는 몇몇 글로벌 애플리케이션 상태 콘택스트에 의존하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenGL을 이용해 작성한 애플리케이션에서는 이런 상황을 자주 만날 수 있다. OpenGL에 셰어더를 생성하는 비용은 상당히 크다.&amp;nbsp; &lt;b&gt;최초 한번은 코드를 작성하고 동시에 이를 요구하는 클래스들에 가까이 정의해야 하는 것은 정의해야 하는 것은 충분히 합리적이다&lt;/b&gt;. 한편 셰이더 컴파일은 OpenGL 콘텍스트 초기화를 해야만 이를 수행할 수 있기 때문에 임포트 시점에 글로벌 모듈 네임스페이스에서 신뢰성 있게 이들을 정의하고 컴파일 하기는 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719983058021&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import glfw
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import numpy


# lazy_class_attribute 정의
class lazy_class_attribute:
    def __init__(self, func):
        self.func = func
        self.attr_name = f&quot;_{func.__name__}&quot;

    def __get__(self, instance, owner):
        if not hasattr(instance, self.attr_name):
            setattr(instance, self.attr_name, self.func(instance))
        return getattr(instance, self.attr_name)


# OpenGL 프로그램 클래스
class OpenGLApp:
    def __init__(self):
        # GLFW 초기화
        if not glfw.init():
            raise Exception(&quot;GLFW can't be initialized&quot;)

        # 윈도우 생성
        self.window = glfw.create_window(800, 600, &quot;OpenGL Window&quot;, None, None)
        if not self.window:
            glfw.terminate()
            raise Exception(&quot;GLFW window can't be created&quot;)

        glfw.make_context_current(self.window)

        # 셰이더 프로그램 초기화
        self.shader = self.init_shader_program

    @lazy_class_attribute
    def init_shader_program(self):
        vertex_src = &quot;&quot;&quot;
        #version 330 core
        layout(location = 0) in vec3 position;
        void main()
        {
            gl_Position = vec4(position, 1.0);
        }
        &quot;&quot;&quot;

        fragment_src = &quot;&quot;&quot;
        #version 330 core
        out vec4 FragColor;
        void main()
        {
            FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
        &quot;&quot;&quot;

        vertex_shader = compileShader(vertex_src, GL_VERTEX_SHADER)
        fragment_shader = compileShader(fragment_src, GL_FRAGMENT_SHADER)
        shader = compileProgram(vertex_shader, fragment_shader)
        return shader

    def run(self):
        # 삼각형 데이터
        vertices = [-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0]
        vertices = numpy.array(vertices, dtype=numpy.float32)

        # VAO와 VBO 생성
        VAO = glGenVertexArrays(1)
        VBO = glGenBuffers(1)

        glBindVertexArray(VAO)

        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
        glEnableVertexAttribArray(0)

        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glBindVertexArray(0)

        # 메인 루프
        while not glfw.window_should_close(self.window):
            glfw.poll_events()

            glClear(GL_COLOR_BUFFER_BIT)

            glUseProgram(self.shader)
            glBindVertexArray(VAO)
            glDrawArrays(GL_TRIANGLES, 0, 3)
            glBindVertexArray(0)
            glUseProgram(0)

            glfw.swap_buffers(self.window)

        # 정리
        glDeleteVertexArrays(1, [VAO])
        glDeleteBuffers(1, [VBO])
        glfw.terminate()


# 실행
if __name__ == &quot;__main__&quot;:
    app = OpenGLApp()
    app.run()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyOpenGL을 활용하여 작성한 lazy_property 데커레이터를 활용한 예시이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크립터는 클래스의 기본적인 동작에 영향을 미친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI프로그램 같이 클래스에 임폴트 할 때 말고 불러올때 해야 콘택스트에 적합하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 pyqt나 다른 GUI라이브러리에서는 직접 lazy_property를 구현하지 않고 내장메서드로 존재하긴한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>descriptor</category>
      <category>lazy_property</category>
      <category>Python</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/177</guid>
      <comments>https://edudeveloper.tistory.com/177#entry177comment</comments>
      <pubDate>Wed, 3 Jul 2024 14:09:46 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 파이썬 접근지정자 강제 접근 방법   파이썬 네임맹글링</title>
      <link>https://edudeveloper.tistory.com/176</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Python 에서는 다른 언어와 다르게 public/private/protected 같은 접근지정자가 따로 없다.&lt;br /&gt;하지만 우리는 네임맹글링이라는 기법으로 고유한 방법으로 던더(__) 기법을 사용하여&amp;nbsp; private하게 접근지정자를 만들고들 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로&amp;nbsp; private한 변수를 가져오거나 값을 바꿀때에는 getter/setter 사용하여 클래스 내부에서 호출하여 변수를 보호한다. 그런데 파이썬에서 정말로 이러한 방법으로 완전하게 변수를 보호할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 아니다. 아래 코드처럼 클래스 자체를 &lt;b&gt;네임맹글링 방식으로 호출하면 결국에는 변수에 접근이 가능하다&lt;/b&gt;.&lt;/p&gt;
&lt;pre id=&quot;code_1719911135384&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass:
    def __init__(self):
        self.__secret_value = 1
        self._atb = 2


obj = MyClass()

print(obj._MyClass__secret_value)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 저렇게 선언이 가능하다고 해서 일반적으로 클래스 바깥에서 저런식으로 접근하지는 않다 그러나 그냥 접근이 가능하다고 알고만 있으면 된당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>dunder method</category>
      <category>Python</category>
      <category>python private public</category>
      <category>python 네임맹글링</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/176</guid>
      <comments>https://edudeveloper.tistory.com/176#entry176comment</comments>
      <pubDate>Tue, 2 Jul 2024 18:11:52 +0900</pubDate>
    </item>
    <item>
      <title>[Python] Pytest Fixtures에 대한 가이드</title>
      <link>https://edudeveloper.tistory.com/175</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일단 해당글은 &lt;a href=&quot;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&lt;/a&gt;를 읽고 나름 정리한 내용을 바탕으로 정리하는 것 에 목적이 있슴ㅁ_ㅁ&lt;/p&gt;
&lt;figure id=&quot;og_1719796655128&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;A Complete Guide to Pytest Fixtures | Better Stack Community&quot; data-og-description=&quot;Learn how to use Pytest fixtures for writing maintainable and isolated tests.&quot; data-og-host=&quot;betterstack.com&quot; data-og-source-url=&quot;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&quot; data-og-url=&quot;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dVe0wc/hyWrKmtSgH/KaQKaTWjUBTrh17OWMKbj0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zJlWF/hyWvPsUdMI/dXfqEwPXPWuS4pcpdChnz1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://betterstack.com/community/guides/testing/pytest-fixtures-guide/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dVe0wc/hyWrKmtSgH/KaQKaTWjUBTrh17OWMKbj0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/zJlWF/hyWvPsUdMI/dXfqEwPXPWuS4pcpdChnz1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;A Complete Guide to Pytest Fixtures | Better Stack Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to use Pytest fixtures for writing maintainable and isolated tests.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;betterstack.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단위 테스트는 소프트웨어 품질에 필수적이지만 반복적인 설정과 데이터 복제로 인해 이를 번거롭게 만들 수 있다. Pytest픽스처는 이러한 문제에 대한 솔루션을 제공함.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pytest Fixtures란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적 테스트 설정을 캡슐화하고 재사용함으로써 픽스처는 테스트 작업 흐름을 크게 향상시킴&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복된 코드를 제거하고 테스트 설정 코드를 복사하여 붙여넣는 일을 없앤다&lt;/li&gt;
&lt;li&gt;중앙 위치에서 테스트 데이터를 업데이트하여 테스트 유지 관리를 단순하게 함&lt;/li&gt;
&lt;li&gt;테스트를 더욱 간결하고 이해하기 쉽게 만들어 가독성을 향상 시킴&lt;/li&gt;
&lt;li&gt;각 테스트가 독립적이고 일관되게 실행되도록 테스트 환경을 격리시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실습&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습하기 위해 기본적인 클래스와 일반적인 pytest를 작성해봄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tree&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;├──&amp;nbsp;app.py &lt;br /&gt;├──&amp;nbsp;tests &lt;br /&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;├──&amp;nbsp;__init__.py &lt;br /&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;├──&amp;nbsp;test_library.py &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;app.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719798999105&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Library:
    def __init__(self):
        self.books = []

    def add_book(self, title, author):
        self.books.append({&quot;title&quot;: title, &quot;author&quot;: author})
        return &quot;Book added successfully&quot;

    def get_book(self, index):
        if 0 &amp;lt;= index &amp;lt; len(self.books):
            book = self.books[index]
            return f&quot;Title: {book['title']}, Author: {book['author']}&quot;
        else:
            return &quot;Index out of range&quot;

    def update_book(self, index, title, author):
        if 0 &amp;lt;= index &amp;lt; len(self.books):
            self.books[index][&quot;title&quot;] = title
            self.books[index][&quot;author&quot;] = author
            return &quot;Book updated successfully&quot;
        else:
            return &quot;Index out of range&quot;

    def list_books(self):
        if not self.books:
            return &quot;No books in the library&quot;
        return &quot;\n&quot;.join(
            f&quot;Title: {book['title']}, Author: {book['author']}&quot; for book in self.books
        )

    def clear_books(self):
        self.books = []

# Example usage:
if __name__ == &quot;__main__&quot;:
    library = Library()
    print(library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;))
    print(library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;))
    print(library.update_book(0, &quot;Nineteen Eighty-Four&quot;, &quot;George Orwell&quot;))
    print(library.list_books())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리 CRUD에 관한 클래스다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;tests/test_library.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719799374909&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from app import Library  


def test_add_book():
    library = Library()

    library.add_book(&quot;The Great Gatsby&quot;, &quot;F. Scott Fitzgerald&quot;)
    assert library.books == [
        {&quot;title&quot;: &quot;The Great Gatsby&quot;, &quot;author&quot;: &quot;F. Scott Fitzgerald&quot;}
    ]


def test_get_book():
    library = Library()
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    assert library.get_book(0) == &quot;Title: 1984, Author: George Orwell&quot;


def test_update_book():
    library = Library()
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    library.update_book(0, &quot;The Catcher in the Rye&quot;, &quot;J.D. Salinger&quot;)

    assert library.books[0] == {
        &quot;title&quot;: &quot;The Catcher in the Rye&quot;,
        &quot;author&quot;: &quot;J.D. Salinger&quot;,
    }



def test_list_books():
    library = Library()
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    assert library.list_books() == (
        &quot;Title: To Kill a Mockingbird, Author: Harper Lee\n&quot;
        &quot;Title: 1984, Author: George Orwell&quot;
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 클래스에 대한 CRUD 테스트이다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;pytest -v&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;이러한 결과물이 나온다.&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;collected 4 items

tests/test_library.py::test_add_book PASSED                             [ 25%]
tests/test_library.py::test_get_book PASSED                             [ 50%]
tests/test_library.py::test_update_book PASSED                          [ 75%]
tests/test_library.py::test_list_books PASSED                           [100%]

============================== 4 passed in 0.02s ===============================&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이테스트 픽스처에 대한 4단계 프로세스&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Arrange:&amp;nbsp; 테스트에 필요한 서비스, 데이터베이스 레코드 ,URL 자격증명 등을 조건을 설정하여 테스트환경을 준비&lt;/li&gt;
&lt;li&gt;Act: 함수 호출과 같이 테스트하려는 작업을 수행&lt;/li&gt;
&lt;li&gt;Assert: 작업 결과가 기대와 일치하는지 확인&lt;/li&gt;
&lt;li&gt;Cleanup: 다른 테스트에 영향을 주지 않도록 환경을 복원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Arrange단계에대한 픽처 설계 Pytest에게 데코레이터를 통해 픽스처임을 알려줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pytest fixtures에 대해서 사용해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1719800358254&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture
def library():
    return Library()


@pytest.fixture
def library_with_books():
    library = Library()
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    return library


def test_add_book(library):
    library.add_book(&quot;The Great Gatsby&quot;, &quot;F. Scott Fitzgerald&quot;)
    assert library.books == [
        {&quot;title&quot;: &quot;The Great Gatsby&quot;, &quot;author&quot;: &quot;F. Scott Fitzgerald&quot;}
    ]


def test_get_book(library):
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    assert library.get_book(0) == &quot;Title: 1984, Author: George Orwell&quot;


def test_update_book(library_with_books):
    library_with_books.update_book(0, &quot;The Catcher in the Rye&quot;, &quot;J.D. Salinger&quot;)

    assert library_with_books.books[0] == {
        &quot;title&quot;: &quot;The Catcher in the Rye&quot;,
        &quot;author&quot;: &quot;J.D. Salinger&quot;,
    }



def test_list_books(library_with_books):
    assert library_with_books.list_books() == (
        &quot;Title: To Kill a Mockingbird, Author: Harper Lee\n&quot;
        &quot;Title: 1984, Author: George Orwell&quot;
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 pytest-fixtures로 적용했을 때 이다. 기존테스트 코드에서 library변수를 fixture로 함수 바깥으로 뺐따. 그래서 test_add_book 메서드나 test_get_book 메서드는 Library() 클래스를 따로 호출하지 않고 픽스처로 된 library를 변수로 받게 하고 바로 실행하여 코드가 2줄씩 줄어들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 test_update_book 메서드와 test_list_books 메서드는 library_with_books 라는 픽스처를 만들어&amp;nbsp; add_book 하는 과정을 줄 일 뿐만 아니라 독립적인 환경을 구축하여서 테스트를 실행할 수 있게 되었다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;pytest -v&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;collected 4 items

tests/test_library.py::test_add_book PASSED                             [ 25%]
tests/test_library.py::test_get_book PASSED                             [ 50%]
tests/test_library.py::test_update_book PASSED                          [ 75%]
tests/test_library.py::test_list_books PASSED                           [100%]

============================== 4 passed in 0.02s ===============================&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;픽스처로 정리했을 때 도 동일한 결과가 나오게 된다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;픽스처가 또 픽스처로 부터 할당 받을 수 있나?&lt;br /&gt;가능하다. 아래처럼 변경하여도 결과 자체는 동일하게 나온다.&lt;/p&gt;
&lt;pre id=&quot;code_1719800838320&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@pytest.fixture
def library():
    return Library()


@pytest.fixture
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    return library&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 test_파일에 픽스처를 저렇게 작성하여도 어차피 결과적으로는 코드에 중복이 불가피한 것 이 아닌가 이를 효율적으로 관리하는 방법은 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;픽스처를 다른 파일에 작성하여서 거기서 자동으로 할당받게 하는 방법이다. 이를 위해서 conftest.py파일을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;tests/conftest.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719801031231&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture
def library():
    return Library()


@pytest.fixture
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield library
    # Teardown code
    library.clear_books()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 작성했던 pytest 픽스처를 conftest에 작성한 예시이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 test_library에 있는 pytest픽스처를 지워도 결과는 동일하게 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Pytest 픽스처에 범위&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pytest에서 픽스처는 테스트에 필요한 리소스를 설정한다 픽스처가 작동하는 기간과 설치 및 다운되는 시기를 아라보자.순서대로 낮은순서부터 높은 범위다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Function Scope: 기본 범위이며 픽스처가 각 테스트&lt;u&gt; 기능 이전에 설정되고 테스트 기능이 종료된 후에 해체됨&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;Class Scope: &lt;u&gt;클래스당 한 번씩 설계&lt;/u&gt;되며 클래스 내의 모든 테스트 방법에서 사용 됨.&lt;/li&gt;
&lt;li&gt;Module Scope: 픽스처는 &lt;u&gt;테스트 모듈당 한 번&lt;/u&gt; 설정되며 해당 모듈 내의 모든 테스트 기능에 사용할 수 있음&lt;/li&gt;
&lt;li&gt;Package Scope: &lt;u&gt;패키지당 한번 설정되며&lt;/u&gt; 패키지내의 모든 테스트에서 사용 가능.&lt;/li&gt;
&lt;li&gt;Session Scope: 전체 &lt;u&gt;테스트 세션마다 한 번씩 설정&lt;/u&gt;되며 해당 세션 동안 실행되는 모든 테스트에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;conftest.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719802526576&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture
def library():
    lib = Library()
    lib.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    lib.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield lib
    # Teardown code
    lib.clear_books()


@pytest.fixture
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield library
    # Teardown code
    library.clear_books()&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;test_library.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719802585188&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def test_add_book(library):
    library.add_book(&quot;The Great Gatsby&quot;, &quot;F. Scott Fitzgerald&quot;)
    expected_books = [
        {&quot;title&quot;: &quot;The Great Gatsby&quot;, &quot;author&quot;: &quot;F. Scott Fitzgerald&quot;},
        {&quot;title&quot;: &quot;To Kill a Mockingbird&quot;, &quot;author&quot;: &quot;Harper Lee&quot;},
        {&quot;title&quot;: &quot;1984&quot;, &quot;author&quot;: &quot;George Orwell&quot;},
    ]
    assert sorted(library.books, key=lambda x: x[&quot;title&quot;]) == sorted(
        expected_books, key=lambda x: x[&quot;title&quot;]
    )


def test_get_book(library):
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    assert library.get_book(2) == &quot;Title: 1984, Author: George Orwell&quot;


def test_update_book(library):
    library.update_book(0, &quot;The Catcher in the Rye&quot;, &quot;J.D. Salinger&quot;)

    assert library.books[0] == {
        &quot;title&quot;: &quot;The Catcher in the Rye&quot;,
        &quot;author&quot;: &quot;J.D. Salinger&quot;,
    }


def test_list_books(library):
    assert library.list_books() == (
        &quot;Title: To Kill a Mockingbird, Author: Harper Lee\n&quot;
        &quot;Title: 1984, Author: George Orwell&quot;
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 변경함으로써 library에 픽스처가 올바르게 추가되었는지 확인하기 위해 테스트에서는 기존 책과 새로운 책이 모두 있는지 확인하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pytest -v 를 사용하면 결과는 통과로 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 스코프(범위)의 차이를 이해하기 위해서 테스트할 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;test_library_operations.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719802837086&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def test_add_book(library):
    library.add_book(&quot;The Great Gatsby&quot;, &quot;F. Scott Fitzgerald&quot;)
    expected_books = [
        {&quot;title&quot;: &quot;The Great Gatsby&quot;, &quot;author&quot;: &quot;F. Scott Fitzgerald&quot;},
        {&quot;title&quot;: &quot;To Kill a Mockingbird&quot;, &quot;author&quot;: &quot;Harper Lee&quot;},
        {&quot;title&quot;: &quot;1984&quot;, &quot;author&quot;: &quot;George Orwell&quot;},
    ]
    assert sorted(library.books, key=lambda x: x[&quot;title&quot;]) == sorted(
        expected_books, key=lambda x: x[&quot;title&quot;]
    )


def test_get_book(library):
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    assert library.get_book(2) == &quot;Title: 1984, Author: George Orwell&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;test_library_management.py&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1719802876169&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def test_update_book(library):
    library.update_book(0, &quot;The Catcher in the Rye&quot;, &quot;J.D. Salinger&quot;)

    assert library.books[0] == {
        &quot;title&quot;: &quot;The Catcher in the Rye&quot;,
        &quot;author&quot;: &quot;J.D. Salinger&quot;,
    }


def test_list_books(library):
    assert library.list_books() == (
        &quot;Title: To Kill a Mockingbird, Author: Harper Lee\n&quot;
        &quot;Title: 1984, Author: George Orwell&quot;
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 파일을 새로 만들고&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;test_library.py&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 이제. pytest 픽스처에 대한 범위(Socpe)를 아라보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Function Scope&lt;/b&gt;는 기본 설정값으로 다른 설정은 따로 안해줘도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세한 로그를 보기위해 pytest -v --setup-show 커맨드에 옵션을 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1719803058287&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tests/test_library_management.py::test_update_book
        SETUP    F library
        tests/test_library_management.py::test_update_book (fixtures used: library)PASSED
        TEARDOWN F library
tests/test_library_management.py::test_list_books
        SETUP    F library
        tests/test_library_management.py::test_list_books (fixtures used: library)PASSED
        TEARDOWN F library
tests/test_library_operations.py::test_add_book
        SETUP    F library
        tests/test_library_operations.py::test_add_book (fixtures used: library)PASSED
        TEARDOWN F library
tests/test_library_operations.py::test_get_book
        SETUP    F library
        tests/test_library_operations.py::test_get_book (fixtures used: library)PASSED
        TEARDOWN F library&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SETUP F library&lt;/b&gt; 그리고 &lt;b&gt;TEARDOWN F library&lt;/b&gt; 라는 구문이 종종 보인다.&lt;br /&gt;이는 테스트가 생기고 소멸됨에 따라 fresh한 상태를 보장한다는 것을 나타낸다 또한 여기서 &lt;b&gt;F&lt;/b&gt; 는 Function Scope에 약자 이므로 이것은 기본 함수 스코프를 의미한다. 이는 테스트 &lt;b&gt;기능 별로 픽스처가 적용됨&lt;/b&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MODULE SCOPE&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pytest를 통해 다음을 정의할 수 있습니다. module 스코프는 모듈 내의 테스트에서 픽스처를 공유할 수 있도록 하여 일관된 상태를 보장함, 이는 픽스처가 한 번 인스턴스화되어 모듈에서 테스트 코드를 실행하는 동안 지속됨을 의미하며 마지막 테스트가 실행되고 나면 픽스처가 소멸된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스코프는 다음과 같은 시나리오에 적합하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정 또는 해체 프로세스에는 데이터베이스 연결 또는 모듈별 구성 로드와 같은 리소스 집약접인 작업&lt;/li&gt;
&lt;li&gt;인스턴스가 공유 픽스처 장치가 필요한 모든 테스트에 재사용되므로 반복적인 설정과 소멸을 줄 일 수 있어 성능이 향상됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1719805361502&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture(scope=&quot;module&quot;)
def library():
    lib = Library()
    lib.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    lib.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield lib
    # Teardown code
    lib.clear_books()


@pytest.fixture
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield library
    # Teardown code
    library.clear_books()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;ada&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;pytest -v --setup-show&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719805442425&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tests/test_library_management.py::test_update_book
    SETUP    M library
        tests/test_library_management.py::test_update_book (fixtures used: library)PASSED
tests/test_library_management.py::test_list_books
        tests/test_library_management.py::test_list_books (fixtures used: library)FAILED
    TEARDOWN M library
tests/test_library_operations.py::test_add_book
    SETUP    M library
        tests/test_library_operations.py::test_add_book (fixtures used: library)PASSED
tests/test_library_operations.py::test_get_book
        tests/test_library_operations.py::test_get_book (fixtures used: library)FAILED
    TEARDOWN M library

========================================================= FAILURES ========================================================== 
______________________________________________________ test_list_books ______________________________________________________ 

library = &amp;lt;app.Library object at 0x00000166327D1690&amp;gt;

    def test_list_books(library):
&amp;gt;       assert library.list_books() == (
            &quot;Title: To Kill a Mockingbird, Author: Harper Lee\n&quot;
            &quot;Title: 1984, Author: George Orwell&quot;
        )
E       AssertionError: assert 'Title: The C...George Orwell' == 'Title: To Ki...George Orwell'
E         - Title: To Kill a Mockingbird, Author: Harper Lee
E         + Title: The Catcher in the Rye, Author: J.D. Salinger
E           Title: 1984, Author: George Orwell

tests\test_library_management.py:11: AssertionError
_______________________________________________________ test_get_book _______________________________________________________ 

library = &amp;lt;app.Library object at 0x000001663282A990&amp;gt;

    def test_get_book(library):
        library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
&amp;gt;       assert library.get_book(2) == &quot;Title: 1984, Author: George Orwell&quot;
E       AssertionError: assert 'Title: The G...tt Fitzgerald' == 'Title: 1984,...George Orwell'
E         - Title: 1984, Author: George Orwell
E         + Title: The Great Gatsby, Author: F. Scott Fitzgerald

tests\test_library_operations.py:15: AssertionError
================================================== short test summary info ================================================== 
FAILED tests/test_library_management.py::test_list_books - AssertionError: assert 'Title: The C...George Orwell' == 'Title: To Ki...George Orwell'
FAILED tests/test_library_operations.py::test_get_book - AssertionError: assert 'Title: The G...tt Fitzgerald' == 'Title: 1984,...George Orwell'
================================================ 2 failed, 2 passed in 0.19s ================================================&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pytest 를 통해 로그를 출력해보면 2개는 성공했고 2개는 실패했다. 일단&amp;nbsp; &lt;b&gt;Function Module&lt;/b&gt; 과 마찬가지로 &lt;b&gt;SETUP M library&lt;/b&gt;와 &lt;b&gt;TEARDOWN M library&lt;/b&gt; 이는 모듈의 모든 테스트가 실행되기 전에 픽스처를 한 번 설치하고 모듈의 모든 테스트가 완료된 후 소멸한다는 것을 의미한다. 이를 통해 각 테스트에 대해 라이브러리를 생성하고 해체하는 오버헤드를 줄여 보다 효율적인 설정을 제공하는 동시에 서로 다른 테스트 파일 간의 격리를 보장함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 픽스처는 &lt;b&gt;&lt;u&gt;모듈 내에서 공유되므로 한 테스트에서 픽스처 상태에 대한 변경 사항이 후속 테스트에 영향을 줄 수 있음&lt;/u&gt;&lt;/b&gt;, 이 때문에 픽스처가 깨끗한 상태에서 시작되지만 그렇지 않다고 가정하기 때문에 일부 테스트가 실패 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, test_update_book가 먼저 실행되어서 후속 결과에 영향을 주므로 test_list_book 메서드 테스트에서 실패했다. 마찬가지 이유로 test_add_book이 후속 결과에 영향을 미쳐 test_get_book 메서드 테스트가 실패했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PackageScope&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 스코프는 여러모듈에 걸쳐 픽스처를 공유하는데 유용함,&amp;nbsp; __init__.py file 및 해당 패키지 내의 모든 하위 디렉터리에서 공유 되며 마지막 테스트가 중단되는 동안 픽스처가 파괴됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;test/conftest.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719898837327&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture(scope=&quot;package&quot;)
def library():
    lib = Library()
    lib.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    lib.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield lib
    # Teardown code
    lib.clear_books()


@pytest.fixture()
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield library
    # Teardown code
    library.clear_books()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;ada&quot; style=&quot;background-color: #f4f5f8; color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;pytest -v --setup-show&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과를 출력하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719899632576&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;collected 4 items

tests/test_library_management.py::test_update_book
  SETUP    P library
        tests/test_library_management.py::test_update_book (fixtures used: library)PASSED
tests/test_library_management.py::test_list_books
        tests/test_library_management.py::test_list_books (fixtures used: library)FAILED
tests/test_library_operations.py::test_add_book
        tests/test_library_operations.py::test_add_book (fixtures used: library)FAILED
tests/test_library_operations.py::test_get_book
        tests/test_library_operations.py::test_get_book (fixtures used: library)FAILED
  TEARDOWN P library&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 확인해보면 시작부분( &lt;b&gt;SETUP P&amp;nbsp; library&lt;/b&gt;)에서 한 번 설정된 것을 볼 수 있음, 그리고 마지막에 &lt;b&gt;TEARDOWN P library&lt;/b&gt; 로 소멸됨, 결과적으로 일단. test_update_book 픽스처가 업데이트 됨 모듈 픽스처와 마찬가지로 마찬가지로 앞에 결과값이 뒤에 결과 값에 영향을 미침 ,&amp;nbsp; 다른 모든 테스트는 픽스처가 깨끗하게&amp;nbsp; 슬레이트될 것으로 작성 됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SessionScope&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Session 스코프는 동일한 테스트 설정을 공유하기를 원할 때 도움이 될 수 있는 또 다른 스코프임, Session 스코프 픽스처는 테스트 실행 초기에 생성되며 모든 테스트가 끝나면 파괴 됨, 이러한 기능은 전체 테스트 세션동안 지속되며 보통 데이터베이스 연결 같은 비싼 리소스를 설정하는 픽스처에 유용함&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;tests/conftest.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719900037521&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest
from app import Library


@pytest.fixture(scope=&quot;session&quot;)
def library():
    lib = Library()
    lib.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    lib.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield lib
    # Teardown code
    lib.clear_books()


@pytest.fixture()
def library_with_books(library):
    library.add_book(&quot;To Kill a Mockingbird&quot;, &quot;Harper Lee&quot;)
    library.add_book(&quot;1984&quot;, &quot;George Orwell&quot;)
    yield library
    # Teardown code
    library.clear_books()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 출력하면,&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719900113502&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;collected 4 items

tests/test_library_management.py::test_update_book
SETUP    S library
        tests/test_library_management.py::test_update_book (fixtures used: library)PASSED
tests/test_library_management.py::test_list_books
        tests/test_library_management.py::test_list_books (fixtures used: library)FAILED
tests/test_library_operations.py::test_add_book
        tests/test_library_operations.py::test_add_book (fixtures used: library)FAILED
tests/test_library_operations.py::test_get_book
        tests/test_library_operations.py::test_get_book (fixtures used: library)FAILED
TEARDOWN S library
...

=========================================================================================== 3 failed, 1 passed in 0.04s ===========================================================================================&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 스코프나 모듈 스코프와 같이 실패한다 이 또한 마찬가지로 선행결과가 후속 결과에 영향을 미치는것을 알 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 스코프는 library 픽스처에서는 전체 테스트 세션이 시작 될 때 한번 설정 되며 모든 테스트가 완료 된 후 해체 됨 이 스코프는 관련된 테스트 패키지 또는 모듈의 수에 관계없이 전체 테스트동안 한 번만 수행하므로 설정 및 해체 작업을 최소화하는데 효율적임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도&amp;nbsp; 다른 범위는 &lt;b&gt;ClassScope&lt;/b&gt; 도 존재한다, class 스코프는 각 테스트 기능 후에 소멸되지 않고 테스트 클래스의 모든 메서드에 대해 한 번 픽스처를 설정하려는 경우에 유용함, 모든 메서드에서 재사용할 수 있으므로 특히 테스트가 분리되어 있거나&amp;nbsp; 설정에 자주 설정 및 해체해야 하는 비싼 것이 포함되어 있는 경우 효율적임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;픽스처에 변수화(Parametrizing fixtures)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python에서는 픽스처를 사용하는 메서드에 매개변수화 하여 간결하고 읽기 쉬운 테스트를 작성할 수 있음 이러한 픽스처를 사용하는 &lt;b&gt;테스트 메서드는 여러번 호출되며 매번 다른 인수를 사용하여 실행&lt;/b&gt; 됨, 이 접근 방식은 &lt;b&gt;다양한 데이터베이스의 연결 값&lt;/b&gt;, &lt;b&gt;여러 파일&lt;/b&gt; 등을 다룰 때 유용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개 변수화를 사용하려면 다음을 통과함, params 다음과 같은 입력 값의 집합을 사용하여 픽스처 데코레이터에 대한 키워드 인수로 사용 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새 파일을 작성한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;tests/test_parametrization.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719900879305&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pytest

@pytest.fixture(params=[&quot;image_1.jpg&quot;, &quot;document_1.pdf&quot;, &quot;image_2.png&quot;, &quot;image_3.jpeg&quot;])
def original_file_path(request):
    return request.param

def convert_to_hyphens(file_path):
    return file_path.replace(&quot;_&quot;, &quot;-&quot;)

def test_convert_to_hyphens(original_file_path):
    converted_file_path = convert_to_hyphens(original_file_path)
    assert &quot;-&quot; in converted_file_path&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;original_file_path()메서드에서는&amp;nbsp; 픽스처에 대하여 다양한 파일 경로를 제공하고 있으며 params를 리스트로 받아서 사용 함 test_convert_to_hyphens() 메서드는&amp;nbsp; 픽스처에 따라 달라지며 목록의 각 파일 경로에 대하여 한 번씩 여러번 실행 되며 _ 를 - 문자로 바꾸어 테스트가 진행 됨&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;픽스처에 내장 메서드 (Using built-in fixtures)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이테스트는 일반적인 테스트 시나리오를 다루는 내장형 픽스처와 함께 제 공 됨 이러한&amp;nbsp; 픽스처는 보일러 플레이트(&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;boilerplate: 변경 없이[최소한 수정] 계속하여 재사용할 수 있는 코드 코드를 줄이고 표준 기능을 통해 일관성을&amp;nbsp; 유지 함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내장 메서드 일부는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;monkeypath: Functions, classes dictionaries, 등 을 일시적으로 수정함&lt;/li&gt;
&lt;li&gt;request: 픽스처를 요청하는 테스트 기능에 대한 정보를 제공함&lt;/li&gt;
&lt;li&gt;tmpdir: 각 테스트 메서드에 고유한 임시 디렉터리 경로 개체를 반환&lt;/li&gt;
&lt;li&gt;tmppathfactory: 공통 기본 임시 디렉터리 아래의 임시 디랙터리를 반환&lt;/li&gt;
&lt;li&gt;recwarn: 테스트 기능에서 발생한 경고를 기록함&lt;/li&gt;
&lt;li&gt;capsys: sysdout, sysderr에 대한 쓰기를 캡처&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmp_path 픽스처는 임시 디렉터리를 관리하는데 필수적이므로 실제 디렉터리와의 작업을 피할 수 있으며 다양한 OS에서 서로 다른 파일 경로로 인해 복잡해 질 수 있음을 방지함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;tests/test_builtin_fixtures.py&lt;/blockquote&gt;
&lt;pre id=&quot;code_1719902810563&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def test_create_and_verify_temp_file(tmp_path):
    # Create a temporary directory within tmp_path
    temporary_directory = tmp_path / &quot;example_temp_dir&quot;
    temporary_directory.mkdir()

    # Create a file inside the temporary directory
    temporary_file = temporary_directory / &quot;example_file.txt&quot;
    temporary_file.write_text(&quot;Temporary file content&quot;)

    # Verify that the file exists
    assert temporary_file.is_file()

    # Verify the file's contents
    assert temporary_file.read_text() == &quot;Temporary file content&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 임시 디렉터리와 파일을 만든다. &lt;b&gt;tmp_path&amp;nbsp;&lt;/b&gt;픽스처 파일의 존재와 내용을 확인하여 테스트 환경이 서로 다른 OS에서 격리되고 일관성있는지 확인 함,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시) 만약에 내장 매서드 (픽스처)를 사용하지 않고 수동으로 하면 다음과 같이 복잡해진다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719902917272&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tempfile
import os
import pytest


def create_and_verify_temp_file(temp_dir):
    # Create a file inside the temporary directory
    temp_file_path = os.path.join(temp_dir, &quot;example_file.txt&quot;)

    with open(temp_file_path, &quot;w&quot;) as temp_file:
        temp_file.write(&quot;Temporary file content&quot;)

    # Verify that the file exists
    assert os.path.isfile(temp_file_path)

    # Verify the file's contents
    with open(temp_file_path, &quot;r&quot;) as temp_file:
        content = temp_file.read()
        assert content == &quot;Temporary file content&quot;


def test_create_and_verify_temp_file_without_fixture():
    # Create a temporary directory
    with tempfile.TemporaryDirectory() as temp_dir:
        # Call the function to create and verify the file
        create_and_verify_temp_file(temp_dir)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 읽기 어려울 뿐만 아니라 장황함, 픽스처를 사용하면 이를 단순화 하고 테스트를 더 쉽게 읽을 수 있고 유지 관리할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내장된 픽스처가 충분하지 않으면 pytest에는 플러그인 목록이 있음 이러한 플러그인 중에서 유용한 고정 픽스처를 제공하는 것 들도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python weekly 뉴스레터로 메일이 와서 이 글을 읽으면서 좋은 내용인 것 같아 글을 작성하였땅&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>pytest</category>
      <category>pytest fixtures</category>
      <category>Python</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/175</guid>
      <comments>https://edudeveloper.tistory.com/175#entry175comment</comments>
      <pubDate>Tue, 2 Jul 2024 15:51:16 +0900</pubDate>
    </item>
    <item>
      <title>[Python]: 다중상속과 메서드 결정 순서 MRO(Method Resolution Order)</title>
      <link>https://edudeveloper.tistory.com/174</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;다중상속이 무엇인가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python에서 다중 상속은 하나의 클래스가 둘 이상의 부모 클래스로부터 속성과 메서드를 상속받는 기능을 의미합니다. 다중 상속은 매우 유용하지만, 복잡성을 증가시키기 때문에 신중하게 사용해야 합니다. Python의 다중 상속에서 주의해야 할 주요 특징과 개념은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MRO( Method Resolution Order )는 무엇인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MRO는 다중 상속 시 메서드나 속성을 검색하는 순서를 결정하는 규칙입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;파이썬은 MRO는 C3 슈퍼클래스 선형화(&lt;a href=&quot;https://en.wikipedia.org/wiki/C3_linearization&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;C3 linearization&lt;/a&gt;)에 기반한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C3 선형화 메서드로 변경하기 이전에는 하나의 클래스가 두 개의 조상을 가졋을 경우, 다중 상속을 계단식으로 사용하지 않는 단순한 경우만 고려했기에 계산과 추적이 매우 쉬웠따~.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MRO가 생기기전에는 간단히 깊이 우선 depth-first으로 검색했다.&lt;/p&gt;
&lt;pre id=&quot;code_1719455365683&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CommonBase:
    pass


class Base1(CommonBase):
    pass


class Base2(CommonBase):
    def method(self):
        print(&quot;Base2.method() called()&quot;)


class MyClass(Base1, Base2):
    pass&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에서 오른쪽으로 탐색하는 깊이 우선left-to-right depth-first 규칙에 따라 동작한다. 단순한 알고리즘 결정 순서에서는 Base클래스를 따라 최상위까지 올라온 뒤, 다시 Base2를 탐색한다. [아래 그림 참조]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1327&quot; data-origin-height=&quot;957&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGYSpq/btsIdzMTTgI/mJe2mS3oS51kN3ohdPc190/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGYSpq/btsIdzMTTgI/mJe2mS3oS51kN3ohdPc190/img.png&quot; data-alt=&quot;다이아몬드 클래스 계층( diamond class hierachy )&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGYSpq/btsIdzMTTgI/mJe2mS3oS51kN3ohdPc190/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGYSpq%2FbtsIdzMTTgI%2FmJe2mS3oS51kN3ohdPc190%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1327&quot; height=&quot;957&quot; data-origin-width=&quot;1327&quot; data-origin-height=&quot;957&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;다이아몬드 클래스 계층( diamond class hierachy )&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준라이브러리는 이런 구조의 상속 계층을 갖지 않으며, 이를 나쁜 프랙티스라고 생각한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서는 이런상속이 가능하므로 보다 명확하게 잘 정의해야 한다.&lt;br /&gt;Object 클래스 타입의 최상위 계층에 위치한다. 모든 클래스는 필연적으로 큰 다이아몬드 클래스 상속 계층의 일부가 된다. 이는 C언어 측면에서 해결되어야 하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 이유에서 파이썬은 MRO 알고리즘으로 C3선형화를 사용한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;파이썬 MRO 참조문서에서는 선형화에 관해서 기술한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;C의 선형화는 C와 그 부모(언어)의 선형화 병합, 부모(언어)의 리스트를 합친 것이다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 상속 예시에 심벌릭 표기법은&lt;/p&gt;
&lt;pre id=&quot;code_1719456661165&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;L[MyClass(Base1, Base2)] = [MyClass] + merge(L[Base1], L[Base2], [Base1, Base2])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 표기 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;- L은 클래스에 대한 MRO 리스트를 저장하는 사전(dictionary)입니다.&lt;br /&gt;- L[MyClass(Base1, Base2)]: MyClass가 Base1과 Base2를 상속할 때의 MRO 리스트를 의미합니다.&lt;br /&gt;- = [MyClass]: 새로운 클래스 MyClass를 포함한 리스트로 초기화합니다.&lt;br /&gt;- + merge(L[Base1], L[Base2], [Base1, Base2]): Base1과 Base2의 MRO 리스트를 병합하여 새로운 MRO 리스트를 생성합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 L[MyClass]는 MyClass의 선형화이며, merge는 여러 선형화 결과를 병합하는 특정한 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge 알고리즘은 중복을 줄이고 올바른 순서를 보존한다. 이 알고리즘은 리스트 헤드([0])와 테일([-1]) 개념을 이용한다. &lt;b&gt;만약 이헤드가 어떤 리스트에 테일에 포함되지 않으면 헤드를 MyClass의 선형화에 추가한다&lt;/b&gt;. 그리고 헤드를 Merge의 리스트에서 제거한다. 그렇지 않으면 다음 리스트의 헤드를 찾고 좋은 헤드라면 그것을 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 깊이 우선 룩업을 모든 부모에 대해서 실행해서 시퀀스를 얻는다.&lt;br /&gt;2. 왼쪽에서 오른쪽으로 검색하는 규칙을 적용해 모든 리스트를 병합함으로 써 한 클래스가 여러 리스트에포함되어 있을 때 계층을 명확하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심벌릭 단계를 통해 MyClass MRO를 계산해야 한다면 모든 L[Class]를 선형화를 풀어낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MRO 계산방법을 작성 할 것인데 글로 설명을 다 표현하기 어려우므로 직접 해보시길. (머리가 나빠서 작성자는 이해하는데 좀 오래걸림;;;)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형화 과정&lt;/p&gt;
&lt;pre id=&quot;code_1719463598512&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;L[MyClass] = [MyClass] + merge(L[Base1], L[Base2], [Base1, Base2])
    = [MyClass] + merge(
        [Base1 + merge(L[CommonBase], [CommonBase])],
        [Base2 + merge(L[CommonBase], [CommonBase])],
        [Base1, Base2]
        )
    = [MyClass] + merge(
        [Base1] + merge(L[CommonBase], [CommonBase]),
        [Base2] + merge(L[CommonBase], [CommonBase]),
        [Base1, Base2]
        )
    = [MyClass] + merge(
        [Base1] + merge([CommonBase] + merge(L[Object]), [CommonBase]),
        [Base2] + merge([CommonBase] + merge(L[Object]), [CommonBase]),
        [Base1, Base2]
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소가 하나인 리스트 [Object]이다. 이는 merge([object])를 [object]로 계속 풀어낼 수 있음을 의미한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719463665501&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass] + merge(
    [Base1] + merge([CommonBase] + merge[object]), [CommonBase]),
    [Base2] + merge([CommonBase] + merge[object]), [CommonBase]),
    [Base1, Base2]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge[object]는 요소가 하나인 리스트이므로 [object]로 풀어낼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719463925228&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass] + merge(
    [Base1] + merge([CommonBase, object], [CommonBase]),
    [Base2] + merge([CommonBase, object], [CommonBase]),
    [Base1, Base2]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 merge([CommonBase, object], [CommonBase])를 풀어낸다. 첫 번째 리스트의 헤드는 CommonBase이며 다른 리스트의 테일에 속하지 않는다. merge에서 CommonBase를 제거한 뒤 바깥선형 결과에 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719465338630&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass] + merge(
    [Base1, CommonBase] + merge([object]),
    [Base2, CommonBase] + merge([object]),
    [Base1, Base2]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge([object])가 계속 남아 있으므로 계속 풀어낸다.&lt;/p&gt;
&lt;pre id=&quot;code_1719465366387&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass] + merge(
    [Base1, CommonBase, object],
    [Base2, CommonBase, object],
    [Base1, Base2]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막&amp;nbsp;merge가&amp;nbsp;남아&amp;nbsp;있으면&amp;nbsp;이는&amp;nbsp;간단하지&amp;nbsp;않다.&amp;nbsp;non-trival.&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;헤드는&amp;nbsp;Bsae1이다.&amp;nbsp;Base1은&amp;nbsp;다른&amp;nbsp;리스트&amp;nbsp;테일에&amp;nbsp;속하지&amp;nbsp;않는다.&amp;nbsp;merge에서&amp;nbsp;제거한&amp;nbsp;뒤&amp;nbsp;바깥&amp;nbsp;선형화&amp;nbsp;결과에서&amp;nbsp;추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719465473261&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [Myclass] + merge(
    [CommonBase, object],
    [Base2, CommonBase, object],
    [Base2]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 첫 번째 헤드는 CommonBase이다. 이는 두 번째 list [Base2, CommonBase, object]의 테일에 속한다. 이는 현 시점에서 더는 진행할 수 없으므로 다음 헤드인 Base2로 이동해야 함을 의미한다. Base2는 다른 리스트의 테일에 속하지 않는다. merge에서 Base2를 제거한 뒤 바깥 선형화 결과에 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719465599243&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass, Base1, Base2] + merge(
    [CommonBase, object],
    [CommonBase, object],
    []
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CommonBase가 다시 첫 번째 헤드가 되었으며, 이제 다른 리스트 테일에 속하지 않는다. merge에서 Base1을 제거한 뒤 바깥 선형화 결과에 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719465665407&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;= [MyClass, Base1, Base2, CommonBase] + merge([object], [object], [])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 merge 결과를 거치면 최종결과는&lt;/p&gt;
&lt;pre id=&quot;code_1719465715790&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Myclass, Base1, Base2, CommonBase, object]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 MyClass.__mro__ 로 출력해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&amp;lt;class&amp;nbsp;'__main__.MyClass'&amp;gt;,&amp;nbsp;&amp;lt;class&amp;nbsp;'__main__.Base1'&amp;gt;,&amp;nbsp;&amp;lt;class&amp;nbsp;'__main__.Base2'&amp;gt;,&amp;nbsp;&amp;lt;class&amp;nbsp;'__main__.CommonBase'&amp;gt;,&amp;nbsp;&amp;lt;class&amp;nbsp;'object'&amp;gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 결과를 가질 수 있따. 따라서 우리는 다중 상속시 위와같은 MRO 방식을 인지하고 사용해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다중 상속 사용 시 주의점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;복잡성&lt;/b&gt;: 다중 상속은 클래스 관계를 복잡하게 만들 수 있습니다. 이를 관리하기 위해서는 설계를 신중히 해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명확성&lt;/b&gt;: 클래스 간의 관계가 명확하지 않을 경우 유지보수가 어려울 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;충돌&lt;/b&gt;: 동일한 이름의 메서드나 속성이 여러 부모 클래스에 존재할 경우 충돌이 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MRO를 사용하여 순서를 확인하고 super()를 활용하여 적절히 값에 접근하는것으로 효과적으로 관리할 수 있따.&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>MRO</category>
      <category>Python</category>
      <category>다중상속</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/174</guid>
      <comments>https://edudeveloper.tistory.com/174#entry174comment</comments>
      <pubDate>Thu, 27 Jun 2024 14:30:20 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 파이썬 개발모드 dev</title>
      <link>https://edudeveloper.tistory.com/173</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;파이썬 3.7부터 전용 개발모드(development mode)에서 파이썬 인터프리터를 호출해 추가적인 런타임을 체크할 수 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 코드를 실행했을 때 발생할 수 있는 잠재적인 이슈를 분석하는 데 유용하다. 올바르게 동작하는 코드에서 이를 적용하는 비용은 매우 높기 때문에 기본적으로 비활성화 되어 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;두 가지 방법으로 활성화 가능.&lt;/p&gt;
&lt;pre id=&quot;code_1719321089518&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python -x dev application.py&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;PYTHONDEVMODE 환경 변수 이용&lt;/p&gt;
&lt;pre id=&quot;code_1719321147514&quot; class=&quot;ini&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;PYTHONDEVMODE = 1 application&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;기본 경고 필터 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;https://docs.python.org/ko/3.9/library/exceptions.html#DeprecationWarning&quot;&gt;&lt;span&gt;DeprecationWarning&lt;/span&gt;&lt;/a&gt;(&lt;span&gt;종료 경고): 지원이 종료된 표준 라이브러리 요소&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;a style=&quot;color: #0072aa;&quot; href=&quot;https://docs.python.org/ko/3.9/library/exceptions.html#ImportWarning&quot;&gt;&lt;span&gt;ImportWarning&lt;/span&gt;&lt;/a&gt;&lt;span&gt;(임포트 경고): 모듈 임포트 시 실수와 관련해서 발생&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;a style=&quot;color: #0072aa;&quot; href=&quot;https://docs.python.org/ko/3.9/library/exceptions.html#PendingDeprecationWarning&quot;&gt;&lt;span&gt;PendingDeprecationWarning&lt;/span&gt;&lt;/a&gt;(종료 예정 경고): &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;지원이 종료도어 향후 릴르스에서 제거 될 표준 라이브러리 요소&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;a style=&quot;color: #0072aa;&quot; href=&quot;https://docs.python.org/ko/3.9/library/exceptions.html#ResourceWarning&quot;&gt;&lt;span&gt;ResourceWarning&lt;/span&gt;&lt;/a&gt;(자원 경고): 열린 파일 닫지 않기와 같이 적합하지 않은 처리 시 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;메모리 할당자 디버그 옵션&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #222222; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;버퍼 언더플로&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;버퍼 오버플로&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;메모리 할당자 API 위반&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;GIL의 안전하지 않은 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 옵션&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴트 핸들러(falut handler) 활성화: 애플리케이션이 SIGSEGV, SIGFPE, SIGBRT, SIGBUS, SIGILL이라는 시스템 호출이 을 받았을 때 애플리케이션 스택트레이스 출력.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 모드에서 발생한 경고(Warning)는 무언가 의도된 방식으로 작동하지 않음을 나타낸다.&lt;br /&gt;코드가 정상적인 동작을 하는 동안에 에러로 간주하지 않아도 좋지만 장기적으로 부누명한 결함이 될 문제들을 찾아 낼 수 있따.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;열려 있는 파일을 적절히 정리하지 않으면 어느 시점에 애플리케이션이 실행되고 있는 환경 자원고갈을 일으킬 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;파일 디스크립터 RAM 디스크 저장 공간은 모두 자원이다. 모든 운영체제에는 동시에 열 수 있는 파일 수의 한도가 존재한다. 애플리케이션이 열었떤 파일을 닫지 않고 새 파일을 계속 열면 어느 시점에서는 새로운 파일을 열지 못하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 모드를 사용하면 미리 발견할&amp;nbsp; 수 있다. 따라서 애플리케이션 테스팅을 하는 동안에는 개발 모드를 사용하는 것을 권장한다. 다만 &lt;b&gt;개발 환경 모드의 확인으로 발생되는 추가적인 오버헤드 떄문에 운영환경에서는 그 사용을 권장하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/Python</category>
      <category>파이썬 개발모드</category>
      <author>개발자리</author>
      <guid isPermaLink="true">https://edudeveloper.tistory.com/173</guid>
      <comments>https://edudeveloper.tistory.com/173#entry173comment</comments>
      <pubDate>Tue, 25 Jun 2024 22:27:04 +0900</pubDate>
    </item>
  </channel>
</rss>