<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Native Python Programing</title>
    <link>https://nativepython.tistory.com/</link>
    <description>파이썬 네이티브 프로그래밍을 위한 블로그입니다. 파이썬 언어의 특징을 활용하는 방법론을 올립니다.
Python Native Programing을 기반으로 다양한 프로젝트를 운영할 수 있도록 역량을 발휘하겠습니다. :)</description>
    <language>ko</language>
    <pubDate>Fri, 22 May 2026 07:34:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>코드수집가</managingEditor>
    <image>
      <title>Native Python Programing</title>
      <url>https://tistory1.daumcdn.net/tistory/6755808/attach/07bd9a252efa432c8edc7794d6253373</url>
      <link>https://nativepython.tistory.com</link>
    </image>
    <item>
      <title>[Native Python Programing] 프랙탈 그래픽 엔진(계산/렌더링)</title>
      <link>https://nativepython.tistory.com/entry/Native-Python-Programing-%ED%94%84%EB%9E%99%ED%83%88-%EA%B7%B8%EB%9E%98%ED%94%BD-%EC%97%94%EC%A7%84%EA%B3%84%EC%82%B0%EB%A0%8C%EB%8D%94%EB%A7%81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;PyQt5 GUI(뷰/입력)와 **프랙탈 그래픽 엔진(계산/렌더링)**을 완전히 분리해서, 엔진은 **Native Python(표준 라이브러리 중심)**으로 구성하는 건 &amp;ldquo;장기적으로 이득이 큰 선택&amp;rdquo;이에요. 대신 프랙탈은 계산량이 커서, 분리 설계만으로 해결 안 되는 성능/동시성 함정이 몇 개 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 **장점/단점 &amp;rarr; 특징 &amp;rarr; 주의점(실전 체크리스트)**로 정리할게요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1) 장점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 테스트/검증이 쉬워짐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진이 Qt에 의존하지 않으면 pytest로 &lt;b&gt;순수 함수/클래스 단위 테스트&lt;/b&gt;가 가능&lt;/li&gt;
&lt;li&gt;예: &amp;ldquo;같은 파라미터 &amp;rarr; 같은 픽셀 결과(결정성)&amp;rdquo; 검증, 회귀 테스트(렌더 결과 비교) 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 재사용/이식성이 커짐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 엔진을
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PyQt5 GUI&lt;/li&gt;
&lt;li&gt;CLI 렌더러(이미지 파일 출력)&lt;/li&gt;
&lt;li&gt;웹 백엔드(타일 렌더링)&lt;/li&gt;
&lt;li&gt;다른 GUI(Tkinter, Delphi, Electron)&lt;br /&gt;로 쉽게 교체 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;엔진 = 제품&amp;rdquo;, &amp;ldquo;GUI = 어댑터&amp;rdquo;가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) 설계가 명확해짐(DDD/포트-어댑터에 잘 맞음)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진 쪽은
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RenderSpec(입력)&lt;/li&gt;
&lt;li&gt;RenderResult(출력)&lt;/li&gt;
&lt;li&gt;Renderer(서비스)&lt;/li&gt;
&lt;li&gt;Palette, Viewport(값 객체)&lt;br /&gt;같은 구조가 깔끔하게 자리잡음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GUI는 &amp;ldquo;현재 뷰포트/팔레트/프리셋 상태&amp;rdquo;만 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) 디버깅이 쉬움(재현 가능성 &amp;uarr;)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Qt 이벤트 루프/스레드 문제와 분리되면 &amp;ldquo;렌더링 버그&amp;rdquo;를 &lt;b&gt;순수 엔진 코드로 재현&lt;/b&gt; 가능&lt;/li&gt;
&lt;li&gt;크래시/멈춤/글리치 원인 분리가 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) 의존성/배포가 단순해짐(엔진은 표준 라이브러리만)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진을 별도 패키지로 떼면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진은 pip 의존 거의 없음&lt;/li&gt;
&lt;li&gt;GUI만 PyQt5 의존&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;유지보수 비용이 줄어듦&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2) 단점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 성능 한계가 빨리 드러남(특히 pure Python 루프)&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;&amp;ldquo;엔진을 Native Python으로만&amp;rdquo; 만들면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큰 해상도/높은 iteration에서 CPU가 쉽게 한계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결국 어느 시점엔
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;multiprocessing(표준)&lt;/li&gt;
&lt;li&gt;또는 NumPy/Numba/C 확장(비표준)&lt;br /&gt;같은 옵션을 고민하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 경계 설계 비용이 생김(데이터 전달/형식)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI &amp;harr; 엔진 사이에 주고받는 데이터(픽셀 버퍼, 타일, 팔레트)가 커서:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무작정 list[list[int]] 같은 구조로 주고받으면 느리고 메모리 폭발&lt;/li&gt;
&lt;li&gt;&amp;ldquo;표준+효율&amp;rdquo; 사이에서 데이터 포맷 설계가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) 동시성 복잡도(스레드/프로세스/취소/진행률)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI는 항상 반응해야 하고, 렌더링은 오래 걸리니:&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;br /&gt;를 구현해야 함&lt;br /&gt;&amp;rarr; 분리하면 더 &amp;ldquo;정교한 작업 관리&amp;rdquo;가 필요해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Qt 이미지 변환 비용(브릿지 비용)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진 결과를 Qt에 표시하려면 결국:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;raw bytes &amp;rarr; QImage &amp;rarr; QPixmap&lt;br /&gt;변환이 들어가는데, 이 변환이 병목이 될 수도 있음&lt;br /&gt;(특히 프레임이 자주 갱신될 때)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3) 특징(이 구조에서 &amp;ldquo;잘 되는&amp;rdquo; 패턴)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 엔진은 &amp;ldquo;결정적(deterministic) + 순수&amp;rdquo;에 가깝게&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 입력(RenderSpec)이면 같은 출력(RenderResult)&lt;/li&gt;
&lt;li&gt;내부 상태 최소화(캐시/랜덤 최소화)&lt;/li&gt;
&lt;li&gt;I/O 없음(파일/Qt/네트워크 금지)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ GUI는 &amp;ldquo;상태 머신 + 이벤트&amp;rdquo; 중심&lt;/h3&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;이벤트가 발생하면 &amp;ldquo;새 RenderSpec 생성 &amp;rarr; 렌더 요청&amp;rdquo;&lt;/li&gt;
&lt;li&gt;렌더 완료 신호가 오면 화면 갱신&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 경계 데이터는 &amp;ldquo;작고 명확&amp;rdquo;하게&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력: viewport, size, max_iter, palette_id, formula_id &amp;hellip;&lt;/li&gt;
&lt;li&gt;출력: bytes(RGBA), width/height, stats(시간, iter 히트맵 요약 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4) 주의해야 할 점(실전 함정)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) &lt;b&gt;GUI 스레드에서 렌더링 금지&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Qt 메인 스레드는 이벤트 루프용&lt;/li&gt;
&lt;li&gt;렌더링을 여기서 하면 UI가 멈춤&lt;/li&gt;
&lt;li&gt;해결:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;QThread + 작업 객체&lt;/li&gt;
&lt;li&gt;또는 concurrent.futures.ThreadPoolExecutor&lt;/li&gt;
&lt;li&gt;CPU-bound면 &lt;b&gt;multiprocessing&lt;/b&gt;이 더 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) &lt;b&gt;취소(Cancel) 설계를 처음부터 넣기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프랙탈 탐색은 &amp;ldquo;사용자가 계속 줌/팬&amp;rdquo;하므로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이전 렌더는 의미 없어짐 &amp;rarr; 즉시 중단해야 함&lt;/li&gt;
&lt;li&gt;해결 패턴:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;render 요청마다 job_id 발급&lt;/li&gt;
&lt;li&gt;엔진은 루프 중간중간 cancel_token.is_cancelled() 확인&lt;/li&gt;
&lt;li&gt;GUI는 최신 job_id만 수용(낡은 결과 폐기)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) &lt;b&gt;데이터 포맷: list 대신 bytes/bytearray/memoryview&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;픽셀 버퍼는 bytearray(RGBA) 추천&lt;/li&gt;
&lt;li&gt;memoryview로 슬라이스/타일 처리하면 복사 줄어듦&lt;/li&gt;
&lt;li&gt;struct / array('I')도 옵션&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) &lt;b&gt;프로세스 사용 시 &amp;ldquo;pickle 비용&amp;rdquo; 관리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;multiprocessing으로 타일을 나누면 좋은데:&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;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;가능하면 shared_memory(표준 lib)로 공유 버퍼 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) &lt;b&gt;부동소수/확대(zoom) 정밀도 한계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊게 확대하면 float 정밀도가 깨져서 아티팩트가 생김&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Native Python만 쓰면 decimal로 가는 선택지가 있지만 매우 느림&lt;/li&gt;
&lt;li&gt;현실적 대안:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일정 줌 이상에서는 품질/속도 타협(샘플링/iteration 조절)&lt;/li&gt;
&lt;li&gt;또는 고정소수/임의정밀(비표준 라이브러리) 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6) &lt;b&gt;색상 매핑(팔레트)도 엔진 규칙으로 고정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI에서 색을 &amp;ldquo;그때그때&amp;rdquo; 바꾸면 재현이 어려움&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팔레트 정의는 엔진 쪽 &amp;ldquo;순수 함수&amp;rdquo;로&lt;/li&gt;
&lt;li&gt;GUI는 팔레트 ID/파라미터만 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7) &lt;b&gt;이벤트 폭주(thrashing) 방지&lt;/b&gt;&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;작업이 계속 쌓이고 CPU만 낭비&lt;/li&gt;
&lt;li&gt;해결:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바운스(예: 50~120ms)&lt;/li&gt;
&lt;li&gt;드래그 중엔 저해상도 프리뷰, 손 뗄 때 고해상도&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5) 한 줄 결론&lt;/h2&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; 성능&amp;middot;동시성&amp;middot;데이터 전달(버퍼/변환) 설계를 제대로 안 하면 오히려 복잡해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하면 다음 단계로, 당신이 원하던 스타일(DDD + 이벤트)로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RenderSpec / RenderResult / Viewport / Palette&lt;/li&gt;
&lt;li&gt;Renderer 인터페이스 + TMandelbrotRenderer급 구현(파이썬)&lt;/li&gt;
&lt;li&gt;RenderJobManager(취소/디바운스/최신결과만 수용)&lt;/li&gt;
&lt;li&gt;PyQt5 어댑터(QImage 변환 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &amp;ldquo;바로 붙여서 실행&amp;rdquo; 가능한 스켈레톤을 코드 파일 세트로 정리해줄까요?&lt;/p&gt;</description>
      <category>Native Python Programing</category>
      <category>파이썬</category>
      <category>프랙탈</category>
      <category>프로그래밍</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/241</guid>
      <comments>https://nativepython.tistory.com/entry/Native-Python-Programing-%ED%94%84%EB%9E%99%ED%83%88-%EA%B7%B8%EB%9E%98%ED%94%BD-%EC%97%94%EC%A7%84%EA%B3%84%EC%82%B0%EB%A0%8C%EB%8D%94%EB%A7%81#entry241comment</comments>
      <pubDate>Sat, 17 Jan 2026 21:03:49 +0900</pubDate>
    </item>
    <item>
      <title>[Native Python Programing] 재사용 가능한 소프트웨어 만들기</title>
      <link>https://nativepython.tistory.com/entry/Native-Python-Programing-%EC%9E%AC%EC%82%AC%EC%9A%A9-%EA%B0%80%EB%8A%A5%ED%95%9C-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;파이썬으로 &lt;b&gt;재사용 가능한 소프트웨어&lt;/b&gt;&amp;rdquo;를 만든다는 건 결국 &lt;b&gt;패키지화 + 경계(레이어) 분리 + 안정적인 API&lt;/b&gt;를 만드는 일이라, 아래 템플릿대로 가면 거의 실패가 없습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1) 재사용 가능성을 만드는 7가지 원칙&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;코어 로직을 프레임워크/입출력에서 분리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB, 웹(Flask), CLI, GUI는 &amp;ldquo;어댑터&amp;rdquo;&lt;/li&gt;
&lt;li&gt;핵심 규칙/유스케이스는 &amp;ldquo;순수 파이썬&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Public API를 작게 고정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;__init__.py에서 외부 노출 대상을 최소화&lt;/li&gt;
&lt;li&gt;내부 구현은 바꿔도 사용자 코드는 안 깨지게&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존성 주입(Dependency Injection)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수/클래스 생성자에 repo/logger/clock 등을 주입&lt;/li&gt;
&lt;li&gt;전역 싱글턴, 직접 import로 묶지 않기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 구조는 dataclass + 타입 힌트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입출력 DTO(Record), 도메인 객체(Entity/ValueObject) 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 모델을 &amp;ldquo;예외 계층&amp;rdquo;으로 표준화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DomainError, ValidationError, NotFound 등&lt;/li&gt;
&lt;li&gt;호출자가 예외를 예측하고 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 가능한 경계&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코어는 unittest/pytest로 순수 단위 테스트 가능해야 함&lt;/li&gt;
&lt;li&gt;DB/HTTP는 통합 테스트로 따로&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문서/예제(Example)가 곧 제품&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;examples/ 폴더 하나만 잘 만들어도 재사용성이 폭발함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2) 추천 프로젝트 구조 (Native Python 스타일)&lt;/h2&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;myproduct/
  pyproject.toml
  README.md
  src/
    myproduct/
      __init__.py          # public API만 export
      version.py
      domain/
        __init__.py
        types.py
        errors.py
        models.py          # dataclasses: Entity/ValueObject
      usecases/
        __init__.py
        services.py        # 유스케이스(순수 파이썬)
      ports/
        __init__.py
        repo.py            # Protocol/ABC (인터페이스)
        clock.py
      adapters/
        __init__.py
        sqlite_repo.py     # sqlite3 구현
        cli.py             # argparse
        web_flask.py       # flask(선택)
  tests/
    test_services.py
    test_domain.py
  examples/
    quickstart.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 &lt;b&gt;domain/usecases는 순수 파이썬&lt;/b&gt;, adapters만 환경 의존.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3) 최소 예제 코드 (재사용 가능한 &amp;ldquo;코어 + 포트 + 어댑터&amp;rdquo;)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) ports/repo.py &amp;mdash; 인터페이스(Protocol)&lt;/h3&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from __future__ import annotations
from typing import Protocol, Optional
from dataclasses import dataclass

@dataclass(frozen=True)
class Member:
    id: str
    email: str
    name: str

class MemberRepo(Protocol):
    def save(self, m: Member) -&amp;gt; None: ...
    def find_by_email(self, email: str) -&amp;gt; Optional[Member]: ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) usecases/services.py &amp;mdash; 유스케이스(순수 로직)&lt;/h3&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from __future__ import annotations
from dataclasses import dataclass
from ..ports.repo import MemberRepo, Member

class DomainError(Exception): ...
class DuplicateEmail(DomainError): ...

@dataclass
class RegisterMember:
    repo: MemberRepo

    def execute(self, *, id: str, email: str, name: str) -&amp;gt; Member:
        if self.repo.find_by_email(email):
            raise DuplicateEmail(email)
        m = Member(id=id, email=email, name=name)
        self.repo.save(m)
        return m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(3) adapters/sqlite_repo.py &amp;mdash; sqlite3 구현(환경 의존)&lt;/h3&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import sqlite3
from typing import Optional
from ..ports.repo import MemberRepo, Member

class SqliteMemberRepo(MemberRepo):
    def __init__(self, conn: sqlite3.Connection):
        self.conn = conn
        self.conn.execute(&quot;&quot;&quot;
        CREATE TABLE IF NOT EXISTS members(
          id TEXT PRIMARY KEY,
          email TEXT UNIQUE NOT NULL,
          name TEXT NOT NULL
        )
        &quot;&quot;&quot;)

    def save(self, m: Member) -&amp;gt; None:
        self.conn.execute(
            &quot;INSERT OR REPLACE INTO members(id,email,name) VALUES (?,?,?)&quot;,
            (m.id, m.email, m.name)
        )
        self.conn.commit()

    def find_by_email(self, email: str) -&amp;gt; Optional[Member]:
        cur = self.conn.execute(&quot;SELECT id,email,name FROM members WHERE email=?&quot;, (email,))
        row = cur.fetchone()
        return Member(*row) if row else None
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(4) examples/quickstart.py &amp;mdash; 사용 예&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import sqlite3
from myproduct.usecases.services import RegisterMember
from myproduct.adapters.sqlite_repo import SqliteMemberRepo

conn = sqlite3.connect(&quot;:memory:&quot;)
repo = SqliteMemberRepo(conn)
uc = RegisterMember(repo=repo)

m = uc.execute(id=&quot;u1&quot;, email=&quot;a@b.com&quot;, name=&quot;Dave&quot;)
print(m)
&lt;/code&gt;&lt;/pre&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;CLI/Flask/GUI가 바뀌어도 코어는 그대로 재사용&lt;/li&gt;
&lt;li&gt;DB가 sqlite&amp;rarr;postgres로 바뀌어도 어댑터만 교체&lt;/li&gt;
&lt;li&gt;테스트는 RegisterMember만 단위로 즉시 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4) 패키지로 배포 가능하게 만들기 (pyproject.toml 핵심)&lt;/h2&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;[project]
name = &quot;myproduct&quot;
version = &quot;0.1.0&quot;
requires-python = &quot;&amp;gt;=3.10&quot;
dependencies = []

[tool.pytest.ini_options]
testpaths = [&quot;tests&quot;]

[build-system]
requires = [&quot;setuptools&amp;gt;=68&quot;]
build-backend = &quot;setuptools.build_meta&quot;
&lt;/code&gt;&lt;/pre&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;개발 설치: pip install -e .&lt;/li&gt;
&lt;li&gt;배포 빌드: python -m build (build 설치 필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5) 체크리스트 (재사용성 점검)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;domain/usecases에서 flask, sqlite3, requests import가 없다&lt;/li&gt;
&lt;li&gt;외부 공개 API는 myproduct/__init__.py에 정리되어 있다&lt;/li&gt;
&lt;li&gt;예외 타입이 문서화되어 있고 호출자가 처리 가능하다&lt;/li&gt;
&lt;li&gt;tests는 DB 없이도 코어를 테스트한다&lt;/li&gt;
&lt;li&gt;examples 하나로 사용법이 끝난다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 방향을 하나만 골라줘도, 그에 맞춰 &lt;b&gt;&amp;ldquo;붙여넣으면 바로 돌아가는 스켈레톤 프로젝트&amp;rdquo;&lt;/b&gt; 형태로 확장해 줄게요:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;CLI 도구 형태&lt;/b&gt;(argparse 서브커맨드)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라이브러리 형태&lt;/b&gt;(API 안정성/버전 관리 중심)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;웹 백엔드 형태&lt;/b&gt;(Flask/FastAPI는 어댑터로)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플러그인/프로세스 매니저 형태&lt;/b&gt;(당신이 하던 구조에 맞춤)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 만들고 싶은 건 1~4 중에 어느 쪽에 더 가까워요?&lt;/p&gt;</description>
      <category>Native Python Programing</category>
      <category>파이썬 #재사용 #소프트웨어</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/240</guid>
      <comments>https://nativepython.tistory.com/entry/Native-Python-Programing-%EC%9E%AC%EC%82%AC%EC%9A%A9-%EA%B0%80%EB%8A%A5%ED%95%9C-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0#entry240comment</comments>
      <pubDate>Sat, 17 Jan 2026 20:46:44 +0900</pubDate>
    </item>
    <item>
      <title>[Native Python Programing] Native Python Programing이란?</title>
      <link>https://nativepython.tistory.com/entry/Native-Python-Programming%EC%9D%B4%EB%9E%80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;**&amp;ldquo;Native Python Programming&amp;rdquo;**은 공식 용어라기보다는, &lt;b&gt;프로그래밍 철학&amp;middot;스타일을 지칭하는 개념적 표현&lt;/b&gt;에 가깝습니다.&lt;br /&gt;당신이 진행 중인 프로젝트 맥락에 딱 맞는 개념이기도 하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에서 &lt;b&gt;정의 &amp;rarr; 핵심 특징 &amp;rarr; 다른 스타일과의 비교 &amp;rarr; 왜 당신의 프로젝트에 잘 맞는지&lt;/b&gt; 순서로 설명할게요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1️⃣ Native Python Programing이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Native Python Programing&lt;/b&gt;은 한마디로 말하면:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파이썬을 &amp;ldquo;파이썬답게&amp;rdquo;, 외부 의존을 최소화하고&lt;br /&gt;언어 자체가 제공하는 구조&amp;middot;철학&amp;middot;표준 라이브러리를 중심으로&lt;br /&gt;시스템을 설계하고 구현하는 방식&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&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;Native&lt;/b&gt;의 의미는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C 확장이나 다른 언어 바인딩이 아니라&lt;/li&gt;
&lt;li&gt;Django/ORM/대형 프레임워크 의존도 아니라&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Python 언어와 표준 라이브러리 자체를 1급 시민으로 사용하는 것&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 뜻합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2️⃣ 핵심 특징 (Native Python의 기준)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 1. 표준 라이브러리 우선주의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dataclasses&lt;/li&gt;
&lt;li&gt;typing&lt;/li&gt;
&lt;li&gt;abc&lt;/li&gt;
&lt;li&gt;enum&lt;/li&gt;
&lt;li&gt;sqlite3&lt;/li&gt;
&lt;li&gt;argparse&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;li&gt;ast&lt;/li&gt;
&lt;li&gt;json / pathlib&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &amp;ldquo;이건 pip 패키지가 필요할까?&amp;rdquo;를 &lt;b&gt;항상 의심&lt;/b&gt;함&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 2. 언어 구조를 설계의 중심에 둠&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@dataclass &amp;rarr; 도메인 모델&lt;/li&gt;
&lt;li&gt;Value Object &amp;rarr; 불변 객체&lt;/li&gt;
&lt;li&gt;Enum / NewType &amp;rarr; 타입 안정성&lt;/li&gt;
&lt;li&gt;ABC + Protocol &amp;rarr; 인터페이스&lt;/li&gt;
&lt;li&gt;Exception 계층 &amp;rarr; 도메인 에러 모델&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  프레임워크보다 &lt;b&gt;언어 기능 자체가 아키텍처의 뼈대&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 3. 프레임워크 비의존 / 약의존&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Native Python은 보통:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;❌ Django-first&lt;/li&gt;
&lt;li&gt;❌ ORM-first&lt;/li&gt;
&lt;li&gt;❌ Magic-heavy&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;✔ Flask/FastAPI는 &amp;ldquo;어댑터&amp;rdquo;&lt;/li&gt;
&lt;li&gt;✔ SQL은 직접 작성&lt;/li&gt;
&lt;li&gt;✔ ORM 없이 Repository 패턴&lt;/li&gt;
&lt;li&gt;✔ 테스트는 pytest + 순수 Python 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 4. &amp;ldquo;보여지는 코드&amp;rdquo;를 중시&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;IDE 없이도 읽히는 구조&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;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ 다른 스타일과의 비교&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;중심&lt;/td&gt;
&lt;td&gt;언어 자체&lt;/td&gt;
&lt;td&gt;프레임워크 규칙&lt;/td&gt;
&lt;td&gt;즉흥 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;구조&lt;/td&gt;
&lt;td&gt;명시적&amp;middot;계층적&lt;/td&gt;
&lt;td&gt;규약 중심&lt;/td&gt;
&lt;td&gt;거의 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;의존성&lt;/td&gt;
&lt;td&gt;최소&lt;/td&gt;
&lt;td&gt;매우 많음&lt;/td&gt;
&lt;td&gt;거의 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;테스트&lt;/td&gt;
&lt;td&gt;단위 테스트 쉬움&lt;/td&gt;
&lt;td&gt;설정 복잡&lt;/td&gt;
&lt;td&gt;테스트 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;확장성&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;프레임워크 수명 의존&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장기 유지&lt;/td&gt;
&lt;td&gt;매우 유리&lt;/td&gt;
&lt;td&gt;프레임워크 교체 비용 큼&lt;/td&gt;
&lt;td&gt;재작성 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분Native PythonFramework-DrivenScript Python&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ 당신의 프로젝트와 왜 잘 맞는가&lt;/h2&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;DSL 인터프리터&lt;/li&gt;
&lt;li&gt;AST &amp;rarr; Native Python Code&lt;/li&gt;
&lt;li&gt;Process / Thread / Signal Manager&lt;/li&gt;
&lt;li&gt;Plugin 시스템&lt;/li&gt;
&lt;li&gt;DDD (Aggregate / Value / Event)&lt;/li&gt;
&lt;li&gt;Flask / PHP / Delphi까지 &lt;b&gt;이식 가능 구조&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 것은 공통적으로:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;프레임워크가 아니라 언어 자체를 기반으로 한 시스템&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&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;Native Python Programming의 정석적인 적용 대상&lt;/b&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;&amp;ldquo;붙여넣으면 바로 실행&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;코어와 어댑터 분리&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;프레임워크는 껍데기&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;DSL &amp;rarr; AST &amp;rarr; Python&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &lt;b&gt;Native Python 철학 그 자체&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5️⃣ 한 줄 정의 (정리)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Native Python Programming이란&lt;/b&gt;&lt;br /&gt;파이썬을 스크립트도, 프레임워크도 아닌&lt;br /&gt;하나의 &amp;ldquo;완전한 시스템 언어&amp;rdquo;로 다루는 개발 방식이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;✅ Native Python + DDD 공식 템플릿&lt;/li&gt;
&lt;li&gt;✅ Native Python 프로젝트 표준 디렉토리&lt;/li&gt;
&lt;li&gt;✅ Native Python DSL/Interpreter 아키텍처&lt;/li&gt;
&lt;li&gt;✅ Native Python vs Rust/Go 철학 비교&lt;/li&gt;
&lt;li&gt;✅ &amp;ldquo;Native Python Manifesto&amp;rdquo; 문서화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어디까지 같이 정리해볼까요?&lt;/p&gt;</description>
      <category>Native Python Programing</category>
      <category>파이썬 #언어 #프로그래밍 #철학</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/239</guid>
      <comments>https://nativepython.tistory.com/entry/Native-Python-Programming%EC%9D%B4%EB%9E%80#entry239comment</comments>
      <pubDate>Sat, 17 Jan 2026 20:37:37 +0900</pubDate>
    </item>
    <item>
      <title>[데이터 카드 자료구조] json 기반 데이터 카드 모델, enum 기반 데이터 타입 모델 1</title>
      <link>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-json-%EA%B8%B0%EB%B0%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EB%AA%A8%EB%8D%B8-enum-%EA%B8%B0%EB%B0%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EB%AA%A8%EB%8D%B8-1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;json을 기반으로 한 &lt;b&gt;데이터 카드 모델&lt;/b&gt;과 enum.Enum을 활용한 &lt;b&gt;데이터 타입 모델&lt;/b&gt;을 함께 구성하면 다음과 같이 만들 수 있습니다. 이 구조는 예: 문학관 콘텐츠 시스템(PoemTree)에서 시, 수필, 댓글, 메타정보 등을 저장할 때 사용할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. Enum 기반 데이터 카드 타입 모델&lt;/h2&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;from enum import Enum

class DataCardType(Enum):
    CONTENT = &quot;content&quot;           # 시, 수필 등 주요 콘텐츠
    META = &quot;meta&quot;                 # 작성자, 날짜, 길이 등 메타정보
    COMMENT = &quot;comment&quot;           # 댓글 정보
    RATING = &quot;rating&quot;             # 평점 정보
    HISTORY = &quot;history&quot;           # 수정 내역
    TAG = &quot;tag&quot;                   # 태그 목록
    CONFIG = &quot;config&quot;             # 설정 정보
    INTERACTION = &quot;interaction&quot;   # 사용자 반응 (좋아요, 즐겨찾기 등)
    STAT = &quot;stat&quot;                 # 통계 정보 (조회수, 댓글 수 등)
    MULTIMEDIA = &quot;multimedia&quot;     # 이미지, 오디오, 영상 등 첨부 자료
    USER = &quot;user&quot;                 # 사용자 정보 카드
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. JSON 기반 데이터 카드 기본 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python 객체로 JSON 직렬화가 가능한 구조이며, dataclasses와 함께 사용하면 깔끔하게 표현할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from dataclasses import dataclass, field, asdict
from datetime import datetime
from typing import List, Dict, Optional, Any
import json
import uuid

@dataclass
class DataCard:
    id: str
    card_type: DataCardType
    data: Dict[str, Any]
    created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    updated_at: Optional[str] = None
    metadata: Dict[str, Any] = field(default_factory=dict)

    def to_json(self) -&amp;gt; str:
        # Enum은 value로 변환해서 JSON 직렬화
        dict_data = asdict(self)
        dict_data[&quot;card_type&quot;] = self.card_type.value
        return json.dumps(dict_data, ensure_ascii=False, indent=2)

    @staticmethod
    def from_json(json_str: str) -&amp;gt; 'DataCard':
        obj = json.loads(json_str)
        return DataCard(
            id=obj[&quot;id&quot;],
            card_type=DataCardType(obj[&quot;card_type&quot;]),
            data=obj[&quot;data&quot;],
            created_at=obj.get(&quot;created_at&quot;, datetime.utcnow().isoformat()),
            updated_at=obj.get(&quot;updated_at&quot;),
            metadata=obj.get(&quot;metadata&quot;, {})
        )
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 예제: 콘텐츠 카드 생성 및 JSON 출력&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 시 콘텐츠 카드 예시 생성
poetry_card = DataCard(
    id=str(uuid.uuid4()),
    card_type=DataCardType.CONTENT,
    data={
        &quot;title&quot;: &quot;그대 떠난 자리에&quot;,
        &quot;author&quot;: &quot;이상&quot;,
        &quot;content&quot;: &quot;바람이 불어오는 자리에 당신의 이름이 있었습니다.&quot;
    },
    metadata={
        &quot;language&quot;: &quot;ko&quot;,
        &quot;length&quot;: 34
    }
)

# JSON 출력
print(poetry_card.to_json())
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 활용 포인트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 저장 시에는 card_type, data, created_at 필드만 JSON 컬럼 하나로 저장해도 충분합니다.&lt;/li&gt;
&lt;li&gt;데이터 필터링 시에는 card_type을 기준으로 분류하면 됩니다.&lt;/li&gt;
&lt;li&gt;확장이 용이하며, 데이터 카드 자체를 API 응답 포맷으로도 바로 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하다면 이 구조를 기반으로 Flask/FastAPI CRUD 연동, SQLAlchemy JSON 필드 매핑, 검색 인덱싱 전략까지도 설계해드릴 수 있습니다. 요청 주세요!&lt;/p&gt;</description>
      <category>데이터 카드 자료구조</category>
      <category>enum</category>
      <category>JSON</category>
      <category>데이터카드</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/238</guid>
      <comments>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-json-%EA%B8%B0%EB%B0%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EB%AA%A8%EB%8D%B8-enum-%EA%B8%B0%EB%B0%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EB%AA%A8%EB%8D%B8-1#entry238comment</comments>
      <pubDate>Tue, 1 Jul 2025 20:50:07 +0900</pubDate>
    </item>
    <item>
      <title>[마이크로 웹 프레임워크]  카드 콜렉션 자료구조의 CRUD 및 검색 기능을 제공하는 간단한 RESTful API 서버 샘플</title>
      <link>https://nativepython.tistory.com/entry/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EC%B9%B4%EB%93%9C-%EC%BD%9C%EB%A0%89%EC%85%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-CRUD-%EB%B0%8F-%EA%B2%80%EC%83%89-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EA%B0%84%EB%8B%A8%ED%95%9C-RESTful-API-%EC%84%9C%EB%B2%84-%EC%83%98%ED%94%8C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Flask를 사용해서 위에서 정의한 &lt;b&gt;카드 콜렉션 자료구조&lt;/b&gt;의 CRUD 및 검색 기능을 제공하는 간단한 RESTful API 서버 샘플을 만들어볼게요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  구조 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/cards&lt;br /&gt;POST: 카드 추가&lt;br /&gt;GET: 모든 카드 조회&lt;/li&gt;
&lt;li&gt;/cards/&amp;lt;id&amp;gt;&lt;br /&gt;GET: 특정 카드 조회&lt;br /&gt;PUT: 카드 업데이트&lt;br /&gt;DELETE: 카드 삭제&lt;/li&gt;
&lt;li&gt;/search&lt;br /&gt;GET: 키워드로 검색&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Flask 기반 샘플 코드&lt;/h2&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from flask import Flask, request, jsonify
from dataclasses import dataclass, field, asdict
from datetime import date
from typing import List, Dict, Optional, Union
import uuid

app = Flask(__name__)

# ----------- 카드 모델 정의 -----------

@dataclass
class BaseCard:
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    title: str = &quot;&quot;
    last_updated: date = field(default_factory=date.today)

@dataclass
class DataCard(BaseCard):
    description: str = &quot;&quot;
    data_source: str = &quot;&quot;
    variables: List[Dict[str, str]] = field(default_factory=list)
    collection_method: str = &quot;&quot;
    time_coverage: str = &quot;&quot;
    geographic_coverage: str = &quot;&quot;
    quality_notes: Optional[str] = None
    usage_notes: Optional[str] = None

@dataclass
class MetaCard(BaseCard):
    metadata: Dict[str, str] = field(default_factory=dict)

@dataclass
class HistoryCard(BaseCard):
    change_log: List[str] = field(default_factory=list)

@dataclass
class StatsCard(BaseCard):
    metrics: Dict[str, Union[int, float]] = field(default_factory=dict)
    summary: str = &quot;&quot;

CardTypes = {
    'data': DataCard,
    'meta': MetaCard,
    'history': HistoryCard,
    'stats': StatsCard
}

# ----------- 카드 콜렉션 -----------

class CardCollection:
    def __init__(self):
        self.cards: Dict[str, BaseCard] = {}

    def add_card(self, card: BaseCard):
        self.cards[card.id] = card

    def get_card(self, card_id: str):
        return self.cards.get(card_id)

    def update_card(self, card_id: str, data: dict):
        card = self.cards.get(card_id)
        if not card:
            return None
        for key, value in data.items():
            if hasattr(card, key):
                setattr(card, key, value)
        card.last_updated = date.today()
        return card

    def delete_card(self, card_id: str):
        return self.cards.pop(card_id, None)

    def search_cards(self, keyword: str) -&amp;gt; List[BaseCard]:
        return [
            card for card in self.cards.values()
            if keyword.lower() in card.title.lower()
            or (hasattr(card, 'description') and keyword.lower() in getattr(card, 'description', '').lower())
        ]

    def all_cards(self) -&amp;gt; List[BaseCard]:
        return list(self.cards.values())

collection = CardCollection()

# ----------- API 엔드포인트 -----------

@app.route('/cards', methods=['POST'])
def create_card():
    data = request.json
    card_type = data.pop('type', '').lower()
    CardClass = CardTypes.get(card_type)
    if not CardClass:
        return jsonify({'error': 'Invalid card type'}), 400
    card = CardClass(**data)
    collection.add_card(card)
    return jsonify(asdict(card)), 201

@app.route('/cards', methods=['GET'])
def list_cards():
    return jsonify([asdict(card) for card in collection.all_cards()])

@app.route('/cards/&amp;lt;card_id&amp;gt;', methods=['GET'])
def get_card(card_id):
    card = collection.get_card(card_id)
    if not card:
        return jsonify({'error': 'Card not found'}), 404
    return jsonify(asdict(card))

@app.route('/cards/&amp;lt;card_id&amp;gt;', methods=['PUT'])
def update_card(card_id):
    data = request.json
    updated = collection.update_card(card_id, data)
    if not updated:
        return jsonify({'error': 'Card not found'}), 404
    return jsonify(asdict(updated))

@app.route('/cards/&amp;lt;card_id&amp;gt;', methods=['DELETE'])
def delete_card(card_id):
    deleted = collection.delete_card(card_id)
    if not deleted:
        return jsonify({'error': 'Card not found'}), 404
    return jsonify({'message': 'Card deleted'})

@app.route('/search', methods=['GET'])
def search_cards():
    keyword = request.args.get('q', '')
    results = collection.search_cards(keyword)
    return jsonify([asdict(card) for card in results])

# ----------- 실행 -----------

if __name__ == '__main__':
    app.run(debug=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  실행 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;위 코드를 app.py로 저장&lt;/li&gt;
&lt;li&gt;터미널에서 실행:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;pip install flask
python app.py
&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;POST, GET, PUT, DELETE 요청은 curl, Postman, 또는 웹 프론트엔드에서 테스트 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  예시 JSON 입력 (POST /cards)&lt;/h2&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;data&quot;,
  &quot;title&quot;: &quot;2024년 고용 통계&quot;,
  &quot;description&quot;: &quot;전국 고용 상태 요약&quot;,
  &quot;data_source&quot;: &quot;고용노동부&quot;,
  &quot;variables&quot;: [{&quot;name&quot;: &quot;job_status&quot;, &quot;description&quot;: &quot;고용 상태&quot;}],
  &quot;collection_method&quot;: &quot;표본 조사&quot;,
  &quot;time_coverage&quot;: &quot;2024.01 ~ 2024.03&quot;,
  &quot;geographic_coverage&quot;: &quot;전국&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하시면 &lt;b&gt;파일 저장&lt;/b&gt;, &lt;b&gt;JWT 인증&lt;/b&gt;, &lt;b&gt;웹 UI 연동&lt;/b&gt;까지 확장할 수 있어요. 원하시나요?&lt;/p&gt;</description>
      <category>마이크로 웹 프레임워크</category>
      <category>웹프레임워크</category>
      <category>플라스크</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/237</guid>
      <comments>https://nativepython.tistory.com/entry/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EC%B9%B4%EB%93%9C-%EC%BD%9C%EB%A0%89%EC%85%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-CRUD-%EB%B0%8F-%EA%B2%80%EC%83%89-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EA%B0%84%EB%8B%A8%ED%95%9C-RESTful-API-%EC%84%9C%EB%B2%84-%EC%83%98%ED%94%8C#entry237comment</comments>
      <pubDate>Mon, 14 Apr 2025 23:02:49 +0900</pubDate>
    </item>
    <item>
      <title>[데이터 카드 자료구조] 데이터카드, 메타카드, 히스토리카드, 통계카드 등 다양한 카드 타입을 카드 콜렉션(Card Collection)</title>
      <link>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%B9%B4%EB%93%9C-%EB%A9%94%ED%83%80%EC%B9%B4%EB%93%9C-%ED%9E%88%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%B9%B4%EB%93%9C-%ED%86%B5%EA%B3%84%EC%B9%B4%EB%93%9C-%EB%93%B1-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%B9%B4%EB%93%9C-%ED%83%80%EC%9E%85%EC%9D%84-%EC%B9%B4%EB%93%9C-%EC%BD%9C%EB%A0%89%EC%85%98Card-Collection</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터카드, 메타카드, 히스토리카드, 통계카드 등 다양한 카드 타입을 &lt;b&gt;카드 콜렉션(Card Collection)&lt;/b&gt; 형태로 관리할 수 있는 자료구조와 함께, &lt;b&gt;CRUD(Create, Read, Update, Delete)&lt;/b&gt; 기능과 &lt;b&gt;검색 기능&lt;/b&gt;까지 포함한 파이썬 예제 코드를 만들어볼게요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  1. 카드 타입 정의&lt;/h2&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;from dataclasses import dataclass, field
from datetime import date
from typing import List, Dict, Optional, Union
import uuid

# 공통 기반 클래스
@dataclass
class BaseCard:
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    title: str = &quot;&quot;
    last_updated: date = field(default_factory=date.today)

@dataclass
class DataCard(BaseCard):
    description: str = &quot;&quot;
    data_source: str = &quot;&quot;
    variables: List[Dict[str, str]] = field(default_factory=list)
    collection_method: str = &quot;&quot;
    time_coverage: str = &quot;&quot;
    geographic_coverage: str = &quot;&quot;
    quality_notes: Optional[str] = None
    usage_notes: Optional[str] = None

@dataclass
class MetaCard(BaseCard):
    metadata: Dict[str, str] = field(default_factory=dict)

@dataclass
class HistoryCard(BaseCard):
    change_log: List[str] = field(default_factory=list)

@dataclass
class StatsCard(BaseCard):
    metrics: Dict[str, Union[int, float]] = field(default_factory=dict)
    summary: str = &quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  2. 카드 콜렉션(CardCollection) 및 CRUD 기능&lt;/h2&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class CardCollection:
    def __init__(self):
        self.cards: Dict[str, BaseCard] = {}

    # Create
    def add_card(self, card: BaseCard):
        self.cards[card.id] = card
        print(f&quot;✅ 카드 추가됨: {card.title} ({card.__class__.__name__})&quot;)

    # Read
    def get_card(self, card_id: str) -&amp;gt; Optional[BaseCard]:
        return self.cards.get(card_id)

    # Update
    def update_card(self, card_id: str, **kwargs):
        card = self.cards.get(card_id)
        if not card:
            print(&quot;❌ 카드 없음&quot;)
            return
        for key, value in kwargs.items():
            if hasattr(card, key):
                setattr(card, key, value)
        card.last_updated = date.today()
        print(f&quot;  카드 업데이트됨: {card.title}&quot;)

    # Delete
    def delete_card(self, card_id: str):
        if card_id in self.cards:
            del self.cards[card_id]
            print(f&quot; ️ 카드 삭제됨: {card_id}&quot;)
        else:
            print(&quot;❌ 삭제할 카드 없음&quot;)

    # Search
    def search_cards(self, keyword: str) -&amp;gt; List[BaseCard]:
        result = [
            card for card in self.cards.values()
            if keyword.lower() in card.title.lower()
            or (hasattr(card, 'description') and keyword.lower() in getattr(card, 'description', '').lower())
        ]
        return result
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  3. 사용 예제&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 카드 콜렉션 생성
collection = CardCollection()

# 데이터 카드 추가
data_card = DataCard(
    title=&quot;2024 인구 센서스&quot;,
    description=&quot;전국 인구의 분포와 변화 분석&quot;,
    data_source=&quot;통계청&quot;,
    variables=[{&quot;name&quot;: &quot;age&quot;, &quot;description&quot;: &quot;연령&quot;}, {&quot;name&quot;: &quot;region&quot;, &quot;description&quot;: &quot;지역&quot;}],
    collection_method=&quot;현장 조사&quot;,
    time_coverage=&quot;2024.01&quot;,
    geographic_coverage=&quot;전국&quot;
)
collection.add_card(data_card)

# 메타카드 추가
meta_card = MetaCard(
    title=&quot;인구 데이터셋 메타정보&quot;,
    metadata={&quot;creator&quot;: &quot;KOSTAT&quot;, &quot;license&quot;: &quot;CC-BY&quot;}
)
collection.add_card(meta_card)

# 통계 카드 추가
stats_card = StatsCard(
    title=&quot;인구 증가 통계&quot;,
    metrics={&quot;growth_rate&quot;: 2.5, &quot;total_population&quot;: 52000000},
    summary=&quot;2023년 대비 2.5% 증가&quot;
)
collection.add_card(stats_card)

# 카드 검색
results = collection.search_cards(&quot;인구&quot;)
print(&quot;\n  검색 결과:&quot;)
for card in results:
    print(f&quot;- {card.title} ({card.__class__.__name__})&quot;)

# 카드 업데이트
collection.update_card(data_card.id, description=&quot;2024년 전국 인구 분석&quot;)

# 카드 삭제
collection.delete_card(meta_card.id)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BaseCard를 상속해 다양한 유형의 카드를 정의&lt;/li&gt;
&lt;li&gt;CardCollection으로 여러 카드 통합 관리 (CRUD + 검색)&lt;/li&gt;
&lt;li&gt;추후 JSON 저장, 파일 입출력, UI 연동 등에 쉽게 확장 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하다면 &lt;b&gt;카드 직렬화(JSON export/import)&lt;/b&gt;, &lt;b&gt;카테고리별 필터링&lt;/b&gt;, 또는 &lt;b&gt;웹 API 기반 관리&lt;/b&gt;로도 확장 가능해요. 혹시 이걸 웹 앱 형태로 만들고 싶으신가요, 아니면 CLI 형태로만 쓸 예정이신가요?&lt;/p&gt;</description>
      <category>데이터 카드 자료구조</category>
      <category>데이터카드</category>
      <category>자료구조</category>
      <category>카드콜렉션</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/236</guid>
      <comments>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%B9%B4%EB%93%9C-%EB%A9%94%ED%83%80%EC%B9%B4%EB%93%9C-%ED%9E%88%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%B9%B4%EB%93%9C-%ED%86%B5%EA%B3%84%EC%B9%B4%EB%93%9C-%EB%93%B1-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%B9%B4%EB%93%9C-%ED%83%80%EC%9E%85%EC%9D%84-%EC%B9%B4%EB%93%9C-%EC%BD%9C%EB%A0%89%EC%85%98Card-Collection#entry236comment</comments>
      <pubDate>Mon, 14 Apr 2025 22:52:09 +0900</pubDate>
    </item>
    <item>
      <title>[데이터 카드 자료구조] 통계 분석, 데이터 공유, 메타데이터 관리를 위한 데이터 요약 카드</title>
      <link>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%86%B5%EA%B3%84-%EB%B6%84%EC%84%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B3%B5%EC%9C%A0-%EB%A9%94%ED%83%80%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9A%94%EC%95%BD-%EC%B9%B4%EB%93%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 카드는 통계 분석, 데이터 공유, 메타데이터 관리 등을 위한 &lt;b&gt;데이터 요약 카드&lt;/b&gt; 개념입니다. 특히 통계 목적에서는 &lt;b&gt;데이터의 출처, 변수 설명, 수집 방법, 품질 정보, 사용 제한&lt;/b&gt; 등을 메타 수준에서 표현할 수 있어야 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  통계 목적 데이터 카드(Data Card) 자료구조 모델 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 카드는 일반적으로 다음과 같은 항목을 포함합니다:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;title&lt;/td&gt;
&lt;td&gt;데이터의 제목&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;description&lt;/td&gt;
&lt;td&gt;데이터셋의 요약 설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;data_source&lt;/td&gt;
&lt;td&gt;수집 기관 또는 출처 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;variables&lt;/td&gt;
&lt;td&gt;주요 변수와 각 변수의 설명, 단위 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;collection_method&lt;/td&gt;
&lt;td&gt;데이터 수집 방법 (예: 설문조사, 센서 수집 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;time_coverage&lt;/td&gt;
&lt;td&gt;데이터가 수집된 시기 (예: 2022.01 ~ 2022.12)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;geographic_coverage&lt;/td&gt;
&lt;td&gt;지역 범위 (예: 전국, 서울 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;quality_notes&lt;/td&gt;
&lt;td&gt;결측치, 신뢰도, 오류율 등 품질 관련 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;usage_notes&lt;/td&gt;
&lt;td&gt;사용 제한, 적절한 해석 방법 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;last_updated&lt;/td&gt;
&lt;td&gt;데이터 카드가 마지막으로 수정된 날짜&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 설명&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Python 예제 코드: 데이터 카드 모델 정의 및 생성&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from dataclasses import dataclass, field
from datetime import date
from typing import List, Dict, Optional

@dataclass
class VariableInfo:
    name: str
    description: str
    unit: Optional[str] = None
    data_type: Optional[str] = None

@dataclass
class DataCard:
    title: str
    description: str
    data_source: str
    variables: List[VariableInfo]
    collection_method: str
    time_coverage: str
    geographic_coverage: str
    quality_notes: Optional[str] = None
    usage_notes: Optional[str] = None
    last_updated: date = field(default_factory=date.today)

    def summarize(self):
        print(f&quot;  데이터 카드: {self.title}&quot;)
        print(f&quot;설명: {self.description}&quot;)
        print(f&quot;출처: {self.data_source}&quot;)
        print(f&quot;수집 방법: {self.collection_method}&quot;)
        print(f&quot;시기: {self.time_coverage}, 지역: {self.geographic_coverage}&quot;)
        print(&quot;\n  변수 정보:&quot;)
        for var in self.variables:
            print(f&quot;- {var.name} ({var.data_type or 'N/A'}): {var.description} ({var.unit or '단위 없음'})&quot;)
        if self.quality_notes:
            print(f&quot;\n  품질 정보: {self.quality_notes}&quot;)
        if self.usage_notes:
            print(f&quot;  사용 시 유의사항: {self.usage_notes}&quot;)
        print(f&quot;\n⏰ 마지막 수정일: {self.last_updated}&quot;)

# 예제 사용
card = DataCard(
    title=&quot;2023년 전국 가구 소득 조사&quot;,
    description=&quot;전국 가구의 연간 소득을 분석한 통계 데이터&quot;,
    data_source=&quot;통계청&quot;,
    variables=[
        VariableInfo(name=&quot;household_id&quot;, description=&quot;가구 고유 식별자&quot;, data_type=&quot;string&quot;),
        VariableInfo(name=&quot;annual_income&quot;, description=&quot;연간 소득&quot;, unit=&quot;KRW&quot;, data_type=&quot;integer&quot;),
        VariableInfo(name=&quot;num_members&quot;, description=&quot;가구 구성원 수&quot;, data_type=&quot;integer&quot;),
    ],
    collection_method=&quot;온라인 설문조사&quot;,
    time_coverage=&quot;2023.01 ~ 2023.12&quot;,
    geographic_coverage=&quot;대한민국 전역&quot;,
    quality_notes=&quot;응답률 87%, 일부 소득 비공개 응답 존재&quot;,
    usage_notes=&quot;단위는 천 원 기준이며, 지역별 차이 고려 필요&quot;
)

card.summarize()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  요약&lt;/h2&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;dataclass를 이용하면 구조적이고 명확한 표현이 가능합니다.&lt;/li&gt;
&lt;li&gt;변수에 대한 정보를 별도의 클래스로 관리하면 확장성이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하면 JSON 형식으로 내보내는 기능도 추가해줄게요. 이 구조를 기반으로 어떤 용도에 적용할 예정인가요?&lt;/p&gt;</description>
      <category>데이터 카드 자료구조</category>
      <category>데이터카드</category>
      <category>통계</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/235</guid>
      <comments>https://nativepython.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%86%B5%EA%B3%84-%EB%B6%84%EC%84%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B3%B5%EC%9C%A0-%EB%A9%94%ED%83%80%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9A%94%EC%95%BD-%EC%B9%B4%EB%93%9C#entry235comment</comments>
      <pubDate>Mon, 14 Apr 2025 22:19:18 +0900</pubDate>
    </item>
    <item>
      <title>[Excel을 활용한 알고리즘 개발] 피벗 테이블(Pivot Table) 활용 방법</title>
      <link>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%ED%94%BC%EB%B2%97-%ED%85%8C%EC%9D%B4%EB%B8%94Pivot-Table-%ED%99%9C%EC%9A%A9-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;h1&gt;&lt;b&gt;엑셀 VBA에서 피벗 테이블(Pivot Table) 활용 방법&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 VBA를 사용하여 **피벗 테이블(Pivot Table)**을 생성, 수정, 업데이트하는 방법을 정리합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 피벗 테이블 개요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피벗 테이블&lt;/b&gt;은 데이터를 요약하고 분석할 수 있는 강력한 기능으로, 특정 필드를 기준으로 그룹화하거나, 합계, 평균 등을 계산하는 데 사용됩니다.&lt;br /&gt;VBA에서는 PivotTable, PivotCache, PivotFields 등의 객체를 사용하여 피벗 테이블을 생성하고 조작할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 피벗 테이블 생성 방법&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 기본 피벗 테이블 생성 (새 워크시트에 추가)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub CreatePivotTable()
    Dim wsData As Worksheet
    Dim wsPivot As Worksheet
    Dim ptCache As PivotCache
    Dim pt As PivotTable
    Dim dataRange As Range

    ' 원본 데이터 시트 및 범위 설정
    Set wsData = ThisWorkbook.Sheets(&quot;Data&quot;) ' 원본 데이터가 있는 시트
    Set dataRange = wsData.Range(&quot;A1:D100&quot;) ' A1:D100 데이터를 사용

    ' 피벗 테이블을 삽입할 새 워크시트 추가
    Set wsPivot = ThisWorkbook.Sheets.Add
    wsPivot.Name = &quot;PivotTableSheet&quot;

    ' 피벗 캐시 생성 (데이터를 메모리에 로드)
    Set ptCache = ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=dataRange)

    ' 피벗 테이블 생성
    Set pt = ptCache.CreatePivotTable(TableDestination:=wsPivot.Range(&quot;A3&quot;), TableName:=&quot;MyPivotTable&quot;)

    ' 필드 추가
    With pt
        .PivotFields(&quot;카테고리&quot;).Orientation = xlRowField ' 행 필드
        .PivotFields(&quot;제품명&quot;).Orientation = xlColumnField ' 열 필드
        .PivotFields(&quot;매출액&quot;).Orientation = xlDataField ' 값 필드
    End With

    MsgBox &quot;피벗 테이블이 생성되었습니다!&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&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;: wsData.Range(&quot;A1:D100&quot;)에서 가져옴.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 시트에 피벗 테이블 생성&lt;/b&gt;: TableDestination:=wsPivot.Range(&quot;A3&quot;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;행(Row) 필드&lt;/b&gt;: 카테고리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;열(Column) 필드&lt;/b&gt;: 제품명&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값(Data) 필드&lt;/b&gt;: 매출액&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 기존 워크시트에서 피벗 테이블 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 있는 시트에 피벗 테이블을 추가하려면:&lt;/p&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub CreatePivotInExistingSheet()
    Dim wsData As Worksheet
    Dim wsPivot As Worksheet
    Dim ptCache As PivotCache
    Dim pt As PivotTable
    Dim dataRange As Range

    ' 원본 데이터와 피벗 테이블을 넣을 시트 지정
    Set wsData = ThisWorkbook.Sheets(&quot;Data&quot;)
    Set wsPivot = ThisWorkbook.Sheets(&quot;PivotSheet&quot;)
    Set dataRange = wsData.Range(&quot;A1:D100&quot;)

    ' 기존 워크시트에서 피벗 캐시 생성
    Set ptCache = ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=dataRange)

    ' 기존 시트의 특정 위치에 피벗 테이블 생성
    Set pt = ptCache.CreatePivotTable(TableDestination:=wsPivot.Range(&quot;B4&quot;), TableName:=&quot;PivotTable2&quot;)

    ' 필드 설정
    With pt
        .PivotFields(&quot;카테고리&quot;).Orientation = xlRowField
        .PivotFields(&quot;매출액&quot;).Orientation = xlDataField
    End With

    MsgBox &quot;피벗 테이블이 기존 시트에 생성되었습니다!&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 피벗 테이블 필드 수정 및 데이터 조작&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 데이터 필드 요약 방식 변경 (합계 &amp;rarr; 평균)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub ChangeDataFieldSummary()
    Dim wsPivot As Worksheet
    Dim pt As PivotTable

    Set wsPivot = ThisWorkbook.Sheets(&quot;PivotTableSheet&quot;)
    Set pt = wsPivot.PivotTables(&quot;MyPivotTable&quot;)

    ' 데이터 필드 요약 방식을 평균으로 변경
    With pt.PivotFields(&quot;매출액&quot;)
        .Function = xlAverage ' 평균으로 설정
    End With

    MsgBox &quot;피벗 테이블 요약 방식이 '평균'으로 변경되었습니다.&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Function = xlAverage &amp;rarr; xlSum(합계), xlCount(개수), xlMax(최대값) 등 변경 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 특정 필드 정렬 및 필터링&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub FilterPivotField()
    Dim wsPivot As Worksheet
    Dim pt As PivotTable

    Set wsPivot = ThisWorkbook.Sheets(&quot;PivotTableSheet&quot;)
    Set pt = wsPivot.PivotTables(&quot;MyPivotTable&quot;)

    ' &quot;카테고리&quot; 필드에서 &quot;전자제품&quot;만 필터링
    With pt.PivotFields(&quot;카테고리&quot;)
        .ClearAllFilters ' 기존 필터 제거
        .CurrentPage = &quot;전자제품&quot;
    End With

    MsgBox &quot;필터가 적용되었습니다!&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.ClearAllFilters &amp;rarr; 기존 필터를 제거하고 특정 값만 필터링.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 피벗 테이블 업데이트 및 삭제&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 피벗 테이블 업데이트 (데이터 변경 후 새로고침)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub RefreshPivotTable()
    Dim wsPivot As Worksheet
    Dim pt As PivotTable

    Set wsPivot = ThisWorkbook.Sheets(&quot;PivotTableSheet&quot;)
    Set pt = wsPivot.PivotTables(&quot;MyPivotTable&quot;)

    ' 데이터 업데이트
    pt.RefreshTable

    MsgBox &quot;피벗 테이블이 업데이트되었습니다!&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 피벗 테이블 삭제&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub DeletePivotTable()
    Dim wsPivot As Worksheet
    Dim pt As PivotTable

    Set wsPivot = ThisWorkbook.Sheets(&quot;PivotTableSheet&quot;)

    ' 특정 피벗 테이블 삭제
    For Each pt In wsPivot.PivotTables
        pt.TableRange2.Clear ' 피벗 테이블 삭제
    Next pt

    MsgBox &quot;피벗 테이블이 삭제되었습니다!&quot;, vbInformation
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.Clear를 사용하여 테이블을 삭제 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 결론&lt;/b&gt;&lt;/h2&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;: PivotCaches.Create 및 CreatePivotTable 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필드 추가 및 수정&lt;/b&gt;: PivotFields(&quot;필드명&quot;).Orientation = xlRowField 등 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 요약 변경&lt;/b&gt;: .Function = xlSum, xlAverage, xlCount 등 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필터 및 정렬&lt;/b&gt;: .ClearAllFilters, .CurrentPage = &quot;필터값&quot; 적용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;업데이트 및 삭제&lt;/b&gt;: .RefreshTable을 사용하여 새로고침, .Clear로 삭제.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 VBA를 활용하여 피벗 테이블을 자동화할 수 있습니다!  &lt;/p&gt;</description>
      <category>Excel을 활용한 알고리즘 개발</category>
      <category>VBA</category>
      <category>엑셀</category>
      <category>자동화</category>
      <category>피벗테이블</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/234</guid>
      <comments>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%ED%94%BC%EB%B2%97-%ED%85%8C%EC%9D%B4%EB%B8%94Pivot-Table-%ED%99%9C%EC%9A%A9-%EB%B0%A9%EB%B2%95#entry234comment</comments>
      <pubDate>Fri, 21 Mar 2025 23:30:22 +0900</pubDate>
    </item>
    <item>
      <title>[Excel을 활용한 알고리즘 개발] 워크시트, 표, 차트, 셀 접근 및 객체 변수 생성</title>
      <link>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%EC%9B%8C%ED%81%AC%EC%8B%9C%ED%8A%B8-%ED%91%9C-%EC%B0%A8%ED%8A%B8-%EC%85%80-%EC%A0%91%EA%B7%BC-%EB%B0%8F-%EA%B0%9D%EC%B2%B4-%EB%B3%80%EC%88%98-%EC%83%9D%EC%84%B1</link>
      <description>&lt;h1&gt;&lt;b&gt;엑셀 VBA에서 워크시트, 표, 차트, 셀 접근 및 객체 변수 생성 방법&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 VBA에서 &lt;b&gt;워크시트(Worksheet), 표(ListObject), 차트(Chart), 셀(Range)&lt;/b&gt; 등의 데이터를 조작하기 위해서는 객체(Objects)를 사용해야 합니다.&lt;br /&gt;엑셀의 다양한 요소에 접근하는 방법과 객체 변수를 생성하는 방법을 설명합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 워크시트(Worksheet) 접근 및 객체 변수 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀에서 워크시트에 접근하는 방법은 여러 가지가 있으며, Worksheets 또는 Sheets 컬렉션을 사용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 특정 워크시트 접근 방법&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 워크시트 이름으로 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(&quot;Sheet1&quot;) ' 또는 Worksheets(&quot;Sheet1&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sheets(&quot;Sheet1&quot;) 또는 Worksheets(&quot;Sheet1&quot;) 둘 다 사용 가능.&lt;/li&gt;
&lt;li&gt;ThisWorkbook은 현재 VBA가 포함된 파일을 의미.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 워크시트 인덱스로 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Set ws = ThisWorkbook.Sheets(1) ' 첫 번째 시트
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) 활성화된 워크시트 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Set ws = ActiveSheet
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 선택된 시트(ActiveSheet)에 접근.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4) 현재 코드가 포함된 워크시트 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;Set ws = ThisWorkbook.Sheets(ActiveSheet.Name)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 워크시트 추가 및 삭제&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 새로운 워크시트 추가&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Dim newSheet As Worksheet
Set newSheet = ThisWorkbook.Sheets.Add
newSheet.Name = &quot;NewSheet&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 워크시트 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Application.DisplayAlerts = False ' 경고 메시지 방지
ThisWorkbook.Sheets(&quot;Sheet1&quot;).Delete
Application.DisplayAlerts = True
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 표(ListObject) 접근 및 객체 변수 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀의 **테이블(표)**은 ListObject로 관리되며, ListObjects 컬렉션을 통해 접근할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 특정 표(ListObject) 접근&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Dim tbl As ListObject
Set tbl = ThisWorkbook.Sheets(&quot;Sheet1&quot;).ListObjects(&quot;Table1&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Table1은 엑셀에서 지정한 테이블 이름 (디자인 탭에서 확인 가능).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 표의 모든 데이터 가져오기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Dim rng As Range
Set rng = tbl.DataBodyRange ' 표의 데이터만 선택
MsgBox &quot;테이블 범위: &quot; &amp;amp; rng.Address
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DataBodyRange는 표의 데이터 영역을 의미하며, 헤더 제외.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(3) 표에 데이터 추가하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;tbl.ListRows.Add
tbl.ListRows(tbl.ListRows.Count).Range.Cells(1, 1).Value = &quot;새 데이터&quot;
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(4) 특정 열의 데이터 가져오기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Dim col As Range
Set col = tbl.ListColumns(&quot;Column1&quot;).DataBodyRange
MsgBox &quot;첫 번째 열의 범위: &quot; &amp;amp; col.Address
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 차트(Chart) 접근 및 객체 변수 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 차트는 Chart 객체 또는 ChartObject 컬렉션을 사용하여 접근합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 특정 차트 접근&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Dim ch As Chart
Set ch = ThisWorkbook.Sheets(&quot;Sheet1&quot;).ChartObjects(1).Chart
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ChartObjects(1) &amp;rarr; 시트 내에서 첫 번째 차트.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 새로운 차트 생성&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Dim newChart As ChartObject
Set newChart = ThisWorkbook.Sheets(&quot;Sheet1&quot;).ChartObjects.Add(Left:=100, Top:=100, Width:=300, Height:=200)
newChart.Chart.ChartType = xlColumnClustered ' 묶은 세로 막대형 차트
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(3) 차트 데이터 변경&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;ch.SetSourceData Source:=ThisWorkbook.Sheets(&quot;Sheet1&quot;).Range(&quot;A1:B10&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SetSourceData를 사용하여 차트의 데이터 범위 변경.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(4) 차트 제목 변경&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;ch.ChartTitle.Text = &quot;매출 데이터&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 셀(Range) 접근 및 객체 변수 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셀에 접근하는 방법은 여러 가지가 있으며, Range 또는 Cells 속성을 사용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 특정 셀 접근&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) Range를 사용한 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Dim rng As Range
Set rng = ThisWorkbook.Sheets(&quot;Sheet1&quot;).Range(&quot;A1&quot;)
rng.Value = &quot;Hello&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) Cells를 사용한 접근&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Set rng = ThisWorkbook.Sheets(&quot;Sheet1&quot;).Cells(1, 1)
rng.Value = &quot;Hello&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cells(1, 1)은 Range(&quot;A1&quot;)과 동일.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 특정 범위 선택&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Set rng = ThisWorkbook.Sheets(&quot;Sheet1&quot;).Range(&quot;A1:B10&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(3) 마지막 행/열 찾기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Dim lastRow As Integer
lastRow = ThisWorkbook.Sheets(&quot;Sheet1&quot;).Cells(Rows.Count, 1).End(xlUp).Row
MsgBox &quot;마지막 데이터 행: &quot; &amp;amp; lastRow
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rows.Count는 최대 행(1048576)에서 xlUp으로 마지막 데이터 찾기.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(4) 특정 값이 있는 셀 찾기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;Set rng = ThisWorkbook.Sheets(&quot;Sheet1&quot;).Cells.Find(What:=&quot;검색할 값&quot;)
If Not rng Is Nothing Then
    MsgBox &quot;값이 &quot; &amp;amp; rng.Address &amp;amp; &quot;에 있습니다.&quot;
Else
    MsgBox &quot;값을 찾을 수 없습니다.&quot;
End If
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 객체 변수 생성 및 해제&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 객체 변수 선언 및 할당&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(&quot;Sheet1&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set 키워드를 사용하여 객체 변수 할당.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 객체 변수 해제 (메모리 관리)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Set ws = Nothing
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용이 끝난 객체 변수는 Nothing으로 설정하여 메모리를 해제.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 결론&lt;/b&gt;&lt;/h2&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;: Sheets(&quot;Sheet명&quot;) 또는 Sheets(1)을 사용하여 접근.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표(ListObject)&lt;/b&gt;: ListObjects(&quot;Table명&quot;)을 통해 접근.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차트(Chart)&lt;/b&gt;: ChartObjects(1).Chart를 사용하여 접근.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;셀(Range)&lt;/b&gt;: Range(&quot;A1&quot;), Cells(1,1), Find 등을 사용하여 접근.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 변수 생성 시 Set을 사용&lt;/b&gt;하고, 필요 없을 때 Nothing으로 해제.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방법을 사용하면 엑셀 VBA에서 데이터를 효율적으로 조작할 수 있습니다.  &lt;/p&gt;</description>
      <category>Excel을 활용한 알고리즘 개발</category>
      <category>VBA</category>
      <category>셀</category>
      <category>엑셀</category>
      <category>워크시트</category>
      <category>차트</category>
      <category>표</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/233</guid>
      <comments>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%EC%9B%8C%ED%81%AC%EC%8B%9C%ED%8A%B8-%ED%91%9C-%EC%B0%A8%ED%8A%B8-%EC%85%80-%EC%A0%91%EA%B7%BC-%EB%B0%8F-%EA%B0%9D%EC%B2%B4-%EB%B3%80%EC%88%98-%EC%83%9D%EC%84%B1#entry233comment</comments>
      <pubDate>Fri, 21 Mar 2025 23:22:12 +0900</pubDate>
    </item>
    <item>
      <title>[Excel을 활용한 알고리즘 개발] 함수와 루틴 선언 및 호출</title>
      <link>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%ED%95%A8%EC%88%98%EC%99%80-%EB%A3%A8%ED%8B%B4-%EC%84%A0%EC%96%B8-%EB%B0%8F-%ED%98%B8%EC%B6%9C</link>
      <description>&lt;h1&gt;&lt;b&gt;엑셀 VBA 절차적 프로그래밍 &amp;ndash; 함수와 루틴 선언 및 호출&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 VBA는 기본적으로 &lt;b&gt;절차적(Procedural) 프로그래밍&lt;/b&gt;을 기반으로 동작합니다. 절차적 프로그래밍에서는 프로그램을 &lt;b&gt;순차적으로 실행&lt;/b&gt;하며, 특정 기능을 수행하는 **함수(Function) 및 루틴(Sub)**을 사용하여 코드의 재사용성과 가독성을 높일 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 함수(Function)와 루틴(Sub)의 차이점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VBA에서 특정 작업을 수행하기 위해 두 가지 유형의 프로시저(절차)를 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;유형 선언 방식 반환 값 호출 방식&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Sub(서브 루틴)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Sub 이름()&lt;/td&gt;
&lt;td&gt;없음 (단순 실행)&lt;/td&gt;
&lt;td&gt;Call 또는 직접 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Function(함수)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Function 이름() As 데이터형&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;td&gt;값 반환 후 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Sub 프로시저(서브 루틴)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**서브 루틴(Sub)**은 특정 작업을 수행하지만 값을 반환하지 않습니다. 버튼 클릭, 이벤트 처리 등에서 주로 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) Sub 프로시저 선언&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;Sub HelloWorld()
    MsgBox &quot;안녕하세요, VBA입니다!&quot;
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MsgBox는 메시지 박스를 띄우는 기본 제공 함수입니다.&lt;/li&gt;
&lt;li&gt;HelloWorld는 호출되면 메시지 창을 띄우지만, 값은 반환하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) Sub 프로시저 호출 방법&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 직접 호출&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;HelloWorld
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) Call 키워드 사용&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;Call HelloWorld
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Call 키워드는 선택 사항이며, 사용해도 되고 안 해도 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) 매개변수가 있는 Sub 호출&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub GreetUser(name As String)
    MsgBox &quot;안녕하세요, &quot; &amp;amp; name &amp;amp; &quot;님!&quot;
End Sub
&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;pre class=&quot;nginx&quot;&gt;&lt;code&gt;GreetUser &quot;홍길동&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Function 프로시저(함수)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Function 프로시저&lt;/b&gt;는 값을 반환하는 기능을 하며, Function 키워드를 사용하여 선언합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) Function 프로시저 선언&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Function AddNumbers(a As Integer, b As Integer) As Integer
    AddNumbers = a + b
End Function
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 개의 정수 a와 b를 더한 후 그 값을 반환합니다.&lt;/li&gt;
&lt;li&gt;함수의 반환 값은 AddNumbers = 값과 같은 형태로 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) Function 호출 방법&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 셀에서 직접 호출&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VBA에서 작성한 함수는 Excel 셀에서 일반 함수처럼 사용 가능함.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;=AddNumbers(10, 20)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) VBA 코드에서 호출&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub TestFunction()
    Dim result As Integer
    result = AddNumbers(5, 7)
    MsgBox &quot;결과 값: &quot; &amp;amp; result
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;result = AddNumbers(5, 7) &amp;rarr; 함수 호출 후 결과를 변수에 저장.&lt;/li&gt;
&lt;li&gt;MsgBox를 통해 결과 값 표시.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. ByRef와 ByVal &amp;ndash; 매개변수 전달 방식&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VBA에서는 매개변수를 &lt;b&gt;ByRef(참조 전달)&lt;/b&gt; 또는 &lt;b&gt;ByVal(값 전달)&lt;/b&gt; 방식으로 전달할 수 있습니다.&lt;/p&gt;
&lt;p&gt;전달 방식 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ByVal(값 전달)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;함수 내에서 값을 변경해도 원본 변수는 유지됨 (기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ByRef(참조 전달)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;함수 내에서 값을 변경하면 원본 변수도 변경됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) ByVal 예제 (기본값)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub ChangeValue(ByVal num As Integer)
    num = num * 2
End Sub

Sub TestByVal()
    Dim x As Integer
    x = 10
    Call ChangeValue(x)
    MsgBox &quot;x 값: &quot; &amp;amp; x ' 여전히 10 (변경되지 않음)
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) ByRef 예제 (원본 변경)&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Sub ChangeValueByRef(ByRef num As Integer)
    num = num * 2
End Sub

Sub TestByRef()
    Dim x As Integer
    x = 10
    Call ChangeValueByRef(x)
    MsgBox &quot;x 값: &quot; &amp;amp; x ' 값이 20으로 변경됨
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ByRef를 사용하면 x의 값이 함수 실행 후 변경됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. VBA에서 Function과 Sub의 활용 예제&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) 두 수를 입력받아 합을 구하는 함수와 호출하는 Sub&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Function SumNumbers(a As Integer, b As Integer) As Integer
    SumNumbers = a + b
End Function

Sub CalculateSum()
    Dim num1 As Integer, num2 As Integer
    Dim result As Integer

    num1 = 10
    num2 = 20

    result = SumNumbers(num1, num2)
    
    MsgBox &quot;두 수의 합: &quot; &amp;amp; result
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) 특정 범위의 셀 값을 합산하는 함수&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;Function SumRange(rng As Range) As Double
    Dim cell As Range
    Dim total As Double
    total = 0

    For Each cell In rng
        total = total + cell.Value
    Next cell

    SumRange = total
End Function
&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;pre class=&quot;excel&quot;&gt;&lt;code&gt;=SumRange(A1:A10)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 결론&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Sub 프로시저&lt;/b&gt;는 특정 작업을 실행하지만 값을 반환하지 않음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Function 프로시저&lt;/b&gt;는 값을 반환하며, 엑셀 셀에서도 직접 호출 가능.&lt;/li&gt;
&lt;li&gt;매개변수 전달 방식은 기본적으로 ByVal이며, ByRef를 사용하면 원본 변수 값이 변경될 수 있음.&lt;/li&gt;
&lt;li&gt;VBA의 절차적 프로그래밍을 활용하면 반복 작업을 효율적으로 자동화할 수 있음.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Excel을 활용한 알고리즘 개발</category>
      <category>function</category>
      <category>VBA</category>
      <category>서브루틴</category>
      <category>엑셀</category>
      <author>코드수집가</author>
      <guid isPermaLink="true">https://nativepython.tistory.com/232</guid>
      <comments>https://nativepython.tistory.com/entry/Excel%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%B0%9C-%ED%95%A8%EC%88%98%EC%99%80-%EB%A3%A8%ED%8B%B4-%EC%84%A0%EC%96%B8-%EB%B0%8F-%ED%98%B8%EC%B6%9C#entry232comment</comments>
      <pubDate>Fri, 21 Mar 2025 23:13:35 +0900</pubDate>
    </item>
  </channel>
</rss>