Communitygithub.com

mathias-mrsn/skills

Python 코드 설계를 검토하고 단순화합니다.

skills란 무엇인가요?

이 스킬은 Python 코드의 가독성, 유지보수성 및 설계 품질을 향상시키는 데 초점을 맞춘 전문 가이드입니다. Java나 C++ 같은 다른 언어에서 직역된 코드를 Python다운 방식으로 리팩토링하거나, 복잡한 코드를 더 작고 명확한 구성 요소로 분해해야 할 때 유용합니다. 추상화의 적절성, 결합도(coupling), 응집도(cohesion)를 평가하고, 디자인 패턴을 불필요하게 강요하지 않으면서 의도를 명확히 전달하는 방법을 제시합니다. Claude Code, Cursor, Codex 등 다양한 AI 코딩 어시스턴트에서 활용할 수 있으며, SKILL.md 문서를 기반으로 Python의 참조, 값, 가변성(mutation)과 같은 핵심 개념을 명확히 이해하고 올바르게 사용하도록 돕습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mathias-mrsn/skills/tree/HEAD/skills/technical/python/python-code-quality

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Python 코드 품질 및 설계

사용 시기

  • 작동하지만 이해, 확장 또는 유지 관리가 어려운 Python 코드를 작성하거나 검토할 때
  • Java나 C++에서 직접 번역된 코드를 언어에 적합한 구조로 대체할 때
  • 추상화를 선택하거나, 결합도를 평가하거나, 새로운 요구사항 이후 리팩토링할 때
  • 패턴의 의도를 인식하되 그 이름을 아키텍처 의무로 만들지 않을 때
  • 이 범위는 코드 추론에 관한 것이며, 배포 환경이나 프레임워크를 규정하지 않습니다.

철학

가장 일반적인 설계를 상상하는 것이 아니라, 관찰된 문제를 해결하는 가장 작은 구성을 찾으십시오. Python이 이미 구조를 제공할 때 패턴은 의도를 유지합니다. 해당 구조를 제거하는 것은 정교함의 부족이 아니라 개선입니다. 좋은 추상화는 클라이언트가 필요로 하는 정보를 지우지 않으면서 변경 비용을 낮춥니다. Thinking in Python, Bruce Eckel 저의 종합적 적용; 말뭉치 a8feb860. 프로젝트에서 실제로 지원하는 Python 버전을 존중하십시오. 말뭉치의 최근 타겟은 암시적 버전 업그레이드를 허용하지 않습니다.

규칙

읽기 쉬운 구문과 예측 가능한 이름

  • 들여쓰기가 실제 블록 구조와 일치하도록 하고, 공백 네 칸을 사용하며 탭과 공백을 혼용하지 마십시오.
  • 블록 헤더는 콜론으로 끝내고, 세미콜론과 코드를 인위적으로 압축하는 여러 문장을 피하십시오.
  • 긴 문장의 경우, 따라가기 어려운 분할보다는 괄호, 대괄호 또는 중괄호 내에서 줄 연속을 사용하십시오.
  • 블록과 스코프를 혼동하지 마십시오. if나 for 내의 할당은 블록 이후에도 계속 보일 수 있습니다.
  • 이름이 사용되기 전에 모든 경로에서 할당이 실행되는지 확인하십시오. 들여쓰기만으로는 바인딩을 보장하지 않습니다.
  • 변수, 함수, 메서드 및 파일에는 snake_case를 사용하고, 클래스에는 PascalCase를 사용하며, 상수에는 대문자를 사용하십시오.
  • 함수처럼 이름이 지정된 클래스의 예외는 실제로 그렇게 사용되는 객체로 제한하십시오. 일반적인 스타일로 만들지 마십시오.
  • 대문자 이름으로부터 런타임 보호를 유추하지 마십시오. 이는 독자에게 의도를 알리는 신호입니다.
  • 프로젝트의 일관된 규칙을 유지하고, 임의의 로컬 규칙을 만드는 대신 기존 린터를 사용하십시오.

참조, 값 및 변경

  • 할당을 이름을 객체에 바인딩하는 것으로 읽으십시오. 객체를 복사하지는 않습니다.
  • 재할당과 변경을 명시적으로 구분하십시오. 이름을 재할당하면 이전 별칭은 변경되지 않지만, 객체를 변경하면 모든 별칭에 영향을 미칠 수 있습니다.
  • 값 동등성에는 ==를 사용하고, 의도된 식별, 특히 is None 및 기타 싱글톤에는 is를 사용하십시오.
  • 문자열이나 작은 정수의 식별을 값 테스트로 사용하지 마십시오. 공유 최적화는 해당 계약을 제공하지 않습니다.
  • 리스트의 슬라이스나 얕은 복사는 외부 구조를 재생성하지만 중첩된 요소는 재생성하지 않습니다. 어떤 객체가 공유된 상태로 남아 있는지 확인하십시오.
  • 포함된 객체도 복제해야 하는 경우에만 깊은 복사를 사용하십시오. 할당으로는 이 격리를 제공할 수 없습니다.
  • x += y를 x = x + y로 기계적으로 대체하지 마십시오. 리스트의 경우 첫 번째 형식은 내부에서 수정하고 두 번째 형식은 새 객체를 생성합니다.
  • 불변 숫자의 경우, 확장 할당이 공유된 숫자를 수정하는 대신 결과에 이름을 다시 바인딩한다는 점을 이해하십시오.
  • 진화할 필요가 없을 때 불변 데이터를 선호하되, 컨테이너의 불변성과 해당 내용물의 불변성을 혼동하지 마십시오.

숫자와 진릿값

  • /는 정수 피연산자에 대해 부동 소수점을 생성하는 나눗셈이고, //는 음의 무한대 방향으로 반올림된 나눗셈이라는 점을 구분하십시오.
  • 포팅 시 음수 경우를 테스트하십시오. 정수 몫은 0으로의 절삭이 아니며, 나머지 %는 제수의 부호를 따릅니다.
  • Python 정수에 고정 너비가 있다고 가정하지 마십시오. 다른 언어의 경계가 있는 정수처럼 오버플로되지 않습니다.
  • 정확한 정수 산술과 부동 소수점 산술을 분리하십시오. 한쪽의 보장을 다른 쪽으로 가져오지 마십시오.
  • round() 및 서식 지정 시 짝수로의 반올림(ties-to-even)을 고려하십시오. 반올림이 항상 0에서 멀어지는 것은 아니라고 가정하지 마십시오.
  • 리터럴에 _ 구분 기호를 사용하여 값 변경 없이 큰 숫자를 읽기 쉽게 만드십시오.
  • 증가 또는 감소에는 += 1 및 -= 1을 사용하십시오. Python에는 ++ 또는 -- 연산자가 없습니다.
  • 부울은 정수이기도 합니다. 조건을 합산하면 참인 경우를 셀 수 있지만, True는 int와 구별되는 숫자 유형을 구성하지 않습니다.
  • 단순히 컨테이너가 비어 있는지 묻는 경우 길이 테스트보다 if items:를 선호하십시오.
  • 객체의 진릿값은 __bool__() 또는, 실패 시 __len__()에 의해 정의될 수 있음을 기억하십시오.
  • and와 or는 단락 평가를 수행하고 반드시 부울이 아닌 피연산자를 반환합니다. 이름만으로 결과를 주석 처리하지 마십시오.
  • 모든 거짓 값을 대체해야 하는 경우에만 x or default를 사용하십시오. 명시적인 None 테스트로 0 또는 빈 텍스트를 보존하십시오.
  • 마스크의 경우 비트 연산자와 논리 연산자를 구분하십시오. ~x는 고정 너비 단어를 반전시키지 않습니다.
  • @가 기본 제공 숫자에 대해 곱을 수행할 것으로 기대하지 마십시오. 행렬 곱셈은 유형에 따라 달라지며 데코레이터 구문과 다릅니다.

문자열 및 보간

  • 문자열은 불변입니다. 변환 결과를 재사용해야 하는 경우 유지하십시오.
  • 이스케이프를 제한하는 따옴표를 선택하고, 개행이 텍스트의 일부인 경우 삼중 따옴표를 사용하십시오.
  • 리터럴 백슬래시에는 원시 문자열을 사용하되, 해당 리터럴을 단일 백슬래시로 끝낼 수 없음을 고려하십시오.
  • 특별한 필요 없이 문자 조작 루프보다 기본 제공 검색, 분할, 대체 및 결합 연산을 사용하십시오.
  • 정확한 접두사를 제거하기 위해 strip, lstrip 또는 rstrip을 사용하지 마십시오. 해당 인수는 문자를 나타내며 분할할 수 없는 부분 문자열이 아닙니다.
  • 대상 버전이 지원하는 경우 정확한 선행 또는 후행 부분 문자열을 제거하려면 removeprefix() 및 removesuffix()를 사용하십시오.
  • +는 숫자를 문자열로 암시적으로 변환하지 않습니다. 명시적 변환이나 f-문자열을 사용하십시오.
  • 일반 텍스트를 생성하려면 f-문자열을 선호하십시오. 해당 표현식은 평가되고 결과는 즉시 렌더링됩니다.
  • 정밀도, 너비 및 정렬에는 형식 지정 사양을 사용하십시오. !r은 진단에 유용한 표현을 보여주고, =은 표현식에 레이블을 지정합니다.
  • 이전 % 또는 str.format() 사용이 존재한다는 이유만으로 다시 작성하지 마십시오. 여전히 유효하며, 마이그레이션은 해당 코드를 개선해야 합니다.
  • 대상 버전이 지원하고 소비자가 조립 전에 리터럴과 값을 구분해야 하는 경우에만 t-문자열을 고려하십시오.
  • t-문자열은 완성된 문자열이 아닌 구조화된 객체를 생성합니다. 소비자는 해당 도메인에 따라 실제로 보간을 인용, 이스케이프 또는 거부해야 합니다.
  • 보간 구문만으로 보안을 약속하지 마십시오. 또는 예시적인 문자 거부를 일반 보호로 오용하지 마십시오.
  • 템플릿 소비자는 텍스트와 값 사이의 엄격한 교대를 가정해서는 안 됩니다. 반복은 빈 리터럴을 생략할 수 있습니다.

추상화, 종속성 및 응집성

  • 새 클래스를 추가하기 전에 함수, 딕셔너리, 모듈 또는 언어 프로토콜로 충분한지 확인하십시오.
  • 단순히 메서드를 호스팅하는 클래스는 그 조직만으로 정당화되지 않습니다.
  • 실제 요구 사항을 기반으로 변경 축의 이름을 지정하십시오. 동일한 위치에서의 반복된 변경은 예상된 유연성보다 더 유용한 증거입니다.
  • 변경되는 것과 안정적으로 유지되는 것을 분리하십시오. 변하는 것이 없을 때 변형 메커니즘을 구축하지 마십시오.
  • 관용구, 특정 솔루션 및 일반 패턴을 가능한 단계로 취급하되, 반드시 거쳐야 하는 사다리로 취급하지 마십시오.
  • 각 추상화에 대해, 그것이 지우는 세부 사항을 식별하고 합법적인 클라이언트가 이를 복구해야 하는지 확인하십시오.
  • 또한 인터페이스 뒤에 숨겨진 작업(복사, 정렬 또는 간접 접근)을 검토하십시오. 실제 데이터 크기에서는 지배적이 될 수 있습니다.
  • 한 부분이 아는 내용(부모 세부 사항, 구체 클래스, 인터페이스, 호출 시그니처 또는 단순 값)으로 결합도를 평가하십시오.
  • 타입이 지정된 종속성과 종속성의 부재를 혼동하지 마십시오. Protocol은 선언된 상속을 피하지만, 해당 멤버는 여전히 계약입니다.
  • 클라이언트가 하나의 작업만 필요로 하는 경우 함수 시그니처를 선호하십시오. 사용처 없이 다중 메서드 인터페이스를 만들지 마십시오.
  • 패턴은 종종 종속성을 제거하기보다는 이동시킵니다. 여전히 구체 클래스의 이름을 지정해야 하는 부분을 찾으십시오.
  • 변경 비용이 저렴한 조립 지점에 의도적으로 배치된 경우 구체적인 종속성을 수용하십시오.
  • 간접적으로 얻은 객체의 내부 세부 사항에 접근하지 마십시오. 명시적 인터페이스를 통해 필요한 서비스를 요청하십시오.
  • 동일한 주제를 제공하는 요소를 하나의 구성 요소로 그룹화하고, 독립적으로 진화할 수 있는 아이디어를 분리하십시오.
  • 구현 세부 사항을 상속하지 않고 협력자를 변경하려면 구성을 선호하십시오. 실제 대체 가능성이 있는 경우 상속을 유지하십시오.
  • 하위 유형이 기본 유형의 클라이언트 기대치, 즉 메서드 이름뿐만 아니라 충족하는지 확인하십시오.
  • 동일한 의도를 동일한 이유로 표현하는 중복을 추출하십시오. 우연한 유사성만으로는 충분하지 않습니다.
  • 일반적인 경우는 단순하게, 드문 경우는 가능하게, 인터페이스는 일관되게 만드십시오. 동작 예외는 암기 비용을 부과합니다.
  • 필요한 동작이나 유용한 격리를 제거하지 않고 레이어를 제거할 수 있다면 제거하십시오. 두 가지 충분한 솔루션 중 단순성으로 선택하십시오.
  • 가능할 때 계산을 순수하게 만드십시오. 동일한 입력은 동일한 결과를 생성하고, 외부 세계에 관찰 가능한 변경이 없습니다.

확장의 두 축을 따라 리팩토링

  • 유형 추가와 연산 추가를 구분하십시오. 설계는 종종 하나를 다른 것보다 선호합니다.
  • 개방형 패밀리의 모든 하위 클래스를 열거하는 match는 목록 유지 관리가 필요하며 새 유형을 조용히 무시할 수 있습니다.
  • 연산이 정확한 클래스로만 그룹화하는 경우, type(obj)로 인덱싱된 딕셔너리가 이 열거를 피합니다.
  • 이 대체를 순전히 구문적으로 취급하지 마십시오. 그러면 하위 클래스는 부모 클래스 패턴과 달리 자체 키를 얻습니다.
  • 첫 번째 발생 시 생성된 그룹의 경우 defaultdict(list)는 새 목록을 제공합니다. 딕셔너리 주석은 이 동작을 생성하지 않습니다.
  • 균일한 연산은 관련 속성을 읽는 일반 함수로 남겨두십시오. 알고리즘이 유형에 따라 변하지 않으면 디스패치는 아무것도 추가하지 않습니다.
  • 각 유형이 자연스럽게 응답을 전달하고 연산이 적게 유지되는 작고 제어된 계층 구조에 메서드를 유지하십시오.
  • 외부 계층 구조를 수정하거나 모든 클래스에 새 연산을 분산시키지 않고 유형에 따라 변하는 연산을 추가하려면 functools.singledispatch를 고려하십시오.
  • singledispatch를 사용하면 구현이 첫 번째 인수에서 선택되고 MRO에 따라 상속될 수 있습니다. 정확한 클래스 테이블이 아닙니다.
  • 기본 응답은 등록되지 않은 유형에 대해 진정으로 유효해야 합니다. 그렇지 않으면 NotImplementedError를 발생시켜 누락을 표시하십시오.
  • 임의의 모듈에서 메서드를 추가하지 마십시오. 독자가 클래스의 정의 외부에서 동작을 검색하도록 강제합니다.
  • 리팩토링을 제거된 코드 줄 수가 아니라 변경된 위치와 보존된 데이터로 측정하십시오.

부과된 카탈로그 없이 패턴 어휘 사용

  • 먼저 문제를 설명하십시오: 생성, 인터페이스 적응, 알고리즘 선택, 알림, 트리 또는 상태 복원; 이름은 나중에 옵니다.
  • 함수를 전달하거나 저장하는 것으로 충분할 때 전략(Strategy)과 명령(Command)을 축소하십시오. 체인은 순서대로 시도되는 함수 목록이 될 수 있습니다.
  • 공유 모듈, 클래스 테이블 또는 반복 프로토콜이 이미 싱글톤(Singleton), 팩토리(Factory) 또는 반복자(Iterator)의 의도를 충족할 수 있음을 인식하십시오.
  • 인터페이스를 변환하는 어댑터(Adapter), 서브시스템을 단순화하는 퍼사드(Façade), 다른 객체에 대한 접근을 제어하는 프록시(Proxy)를 구분하십시오.
  • 상태에 따라 동작을 변경하는 상태(State)와 입력에 응답하여 전환을 선택하는 상태 머신을 구분하십시오.
  • 외부에서 협력자를 주입하는 것과 레지스트리에서 해당 협력자를 조회하는 것을 구분하십시오. 둘 다 종속성을 동일한 방식으로 노출하지 않고 제어를 이동시킵니다.
  • 아키텍처, 지속성, 메시징 및 클라우드 이름을 설명된 의도 수준으로 유지하십시오. 카탈로그에 있다고 해서 구현 레시피가 설정되는 것은 아닙니다.
  • 회로 차단기(Circuit Breaker), 사가(Saga), 리포지토리(Repository) 또는 이벤트 소싱(Event Sourcing)의 단순한 언급으로부터 배포, 복구 또는 일관성 권장 사항을 유추하지 마십시오.

절차

  1. 대상 Python, 규칙 및 이미 사용 중인 검사를 식별하고 보존할 동작을 기록합니다.
  2. 구체적인 요구 사항과 관찰된 변경 축을 명시하고 오늘 영향을 받는 구성 요소를 나열합니다.
  3. 관련된 공유 참조, 진릿값, 숫자 연산 및 문자열 변환을 확인합니다.
  4. 최소 솔루션을 작성한 다음 제안된 추상화(지워진 세부 사항, 숨겨진 작업 및 이동된 종속성)를 비교합니다.
  5. 유형 추가와 연산 추가를 별도로 테스트하고 각 변형에서 필요한 변경 사항을 기록합니다.
  6. 동작 테스트와 들어오고 나가는 데이터의 개수를 유지하면서 단계적으로 리팩토링합니다.
  7. 불필요해진 레이어를 제거한 다음 지원되는 버전에서 프로젝트의 테스트와 검사를 실행합니다.

함정

  • 프로그램은 새 유형을 잃은 후에도 그럴듯한 합계를 생성할 수 있습니다. 출력 표시뿐만 아니라 데이터 보존을 확인하십시오.
  • 대체 분기 또는 기본 구현은 잊혀진 확장을 숨길 수 있습니다. 중립적인 응답이 올바르지 않은 경우 명시적 실패를 선호하십시오.
  • 여러 실제 사례가 있기 전에 일반화하면 유용성에 대한 증거 없이 옵션을 만듭니다. 추측성 프레임워크를 거부하십시오.
  • 짧은 추상화는 높은 비용을 숨기거나 필수 세부 사항을 지울 수 있습니다. 줄 수를 세는 것만으로는 품질을 판단하기에 충분하지 않습니다.
  • 말뭉치의 최근 구문과 API가 이전 프로젝트에서 반드시 사용 가능한 것은 아닙니다. 이를 채택하기 위해 최소 Python 버전을 올리지 마십시오.

검증

  • 각 새 클래스 또는 인터페이스는 명명된 필요를 보호합니다. 패턴이 단지 이름을 위해 존재하지 않습니다.
  • 조건부 경로는 사용 전에 변수를 바인딩합니다. 식별, 변경 및 동등성이 혼동되지 않습니다.
  • 0, 빈 값, None, 음수 및 중첩 데이터는 그 차이가 중요할 때 실행되었습니다.
  • 새 하위 클래스는 조용히 사라지지 않으며, 정확한 클래스 또는 상속 기반 디스패치가 의도된 대로 작동합니다.

구성

가져오기: 이 스킬은 파일 끝에서 설명된 대로 적절히 가져올 때 로드됩니다.

관련 스킬