파이썬 코딩 실력을 향상시키고 싶으신가요? 파이썬의 선(Zen of Python)은 그 첫걸음을 내딛는 데 매우 유용한 지침이 될 수 있습니다.
파이썬은 배우기 쉬운 언어이지만, 유지보수가 용이하고 파이썬다운 코드를 작성하는 것은 특히 초보 프로그래머에게 어려울 수 있습니다. PEP-20은 파이썬 코드를 작성할 때 모범 사례를 따르는 것이 얼마나 중요한지 보여주는 Tim Peters의 시 “파이썬의 선”을 소개합니다.
파이썬의 선을 읽어보려면 파이썬 REPL을 시작하고 다음을 입력하면 됩니다.
>>> import this
The Zen of Python, by Tim Peters 아름다운 것이 추한 것보다 낫다. 명시적인 것이 암시적인 것보다 낫다. 단순한 것이 복잡한 것보다 낫다. 복잡한 것이 꼬인 것보다 낫다. 평면적인 것이 중첩된 것보다 낫다. 희소한 것이 밀집된 것보다 낫다. 가독성은 중요하다. 특별한 경우는 규칙을 어길 만큼 특별하지 않다. 비록 실용성이 순수함을 이길지라도. 오류는 결코 조용히 지나가서는 안 된다. 명시적으로 침묵시키지 않는 한. 모호함에 직면했을 때는 추측하려는 유혹을 거부하라. 무언가를 하는 명확한 방법은 하나, 가급적이면 단 하나여야 한다. 비록 그 방법이 네덜란드인이 아니라면 처음에는 명확하지 않을 수 있지만. 지금 하는 것이 결코 안 하는 것보다 낫다. 비록 안 하는 것이 종종 *지금 당장* 하는 것보다 나을 때도 있지만. 구현이 설명하기 어렵다면 그것은 나쁜 생각이다. 구현이 설명하기 쉽다면 좋은 생각일 수 있다. 네임스페이스는 정말 멋진 아이디어 중 하나이다 -- 더 많이 사용하자!
보시다시피, 파이썬의 선에 담긴 대부분의 격언은 자명합니다. 어떤 격언은 다른 격언과 결합하여 해석해야 하며, 어떤 격언은 이전 격언과 모순됩니다. 그럼에도 불구하고 파이썬의 선은 재미있고 매력적이며 실용적입니다!
파이썬의 선 해석
파이썬의 선은 파이썬 프로그래밍을 위한 20가지 기본 원칙을 제시합니다. 하지만 현재까지는 19개의 격언만 존재합니다. 하나씩 살펴봅시다.
아름다운 것이 추한 것보다 낫다.
이 격언은 우아하고 파이썬다운 코드를 작성하는 것의 중요성을 강조합니다.
다음 코드 스니펫에는 코드 냄새가 있습니다.
def square(num): squares = [] for i in range(num): squares.append(i*i) return squares
이 함수는 다음과 같은 과정을 거칩니다.
- 빈 리스트를 초기화합니다.
- 리스트 끝에 요소를 추가합니다.
- 마지막으로 리스트를 반환합니다.
이 코드는 기능적으로는 올바르지만 (파이썬답지 않으며) 유지보수하기가 어렵습니다.
제너레이터를 사용하면 훨씬 더 우아하게 작성할 수 있습니다. 다음은 위의 함수와 동일한 제너레이터 함수입니다.
def square(num): for i in range(num): yield i*i
더 좋은 방법은 제너레이터 표현식을 사용하는 것입니다:
num = ... squares = (i*i for i in range(num))
명시적인 것이 암시적인 것보다 낫다.
코드를 작성할 때는 다른 개발자와 사용자가 코드의 암시적 또는 기본 동작을 추측하도록 하지 마십시오. 명확하게 표현해야 합니다. 와일드카드 임포트의 예를 살펴보겠습니다.
from some_module import * # 와일드카드 임포트 from some_other_module import * result = some_function() # 어디서 온 함수일까요?
와일드카드 임포트는 최대한 피해야 합니다. 이는 명시적이지 않고 비효율적이기 때문입니다. 다른 모듈에서 함수나 클래스를 가져올 때는 구체적이어야 합니다.
from some_module import this_function # 명시적 임포트 result = this_function() # 이제 알 수 있습니다.
단순한 것이 복잡한 것보다 낫다.
이 격언은 코드를 단순하게 유지하고 불필요한 복잡성을 피해야 함을 의미합니다. 예를 들어 문자열을 뒤집는 기능을 구현할 때 다음의 재귀적 해결책을 사용할 수 있습니다.
def reverse_string(my_string): if my_string == "": return my_string else: return reverse_string(my_string[1:]) + my_string[:1]
이 방법도 작동하지만, 더 간단하고 파이썬다운 방법이 있다는 점을 고려할 때 과도하게 설계된 해결책이라고 볼 수 있습니다.
문자열 슬라이싱을 사용하는 방법은 다음과 같습니다:
>>> rev_string = my_string[::-1] >>> rev_string 'nohtyP'
내장 메서드와 함수를 사용하는 방법은 다음과 같습니다:
>>> rev_string = ''.join(reversed(my_string)) >>> rev_string 'nohtyP'
복잡한 것이 꼬인 것보다 낫다.
그렇다면 파이썬의 선에서 제시하는 다음 격언은 무엇을 의미할까요?
파이썬에서 문자열을 뒤집는 것은 매우 간단한 작업입니다. 하지만 실제로는 더 복잡한 논리가 필요할 수 있습니다. 다음은 간단한 예입니다.
데이터베이스에 연결해야 한다고 가정해 보겠습니다.
- 데이터베이스의 설정 정보를 가져오려면 먼저 toml 설정 파일을 분석해야 합니다.
- 데이터베이스 커넥터를 설치해야 합니다.
- 데이터베이스에 연결하고, 연결 오류를 예상하고, 오류 처리를 구현하는 등의 기능을 정의할 수 있습니다.
- 마지막으로 데이터베이스에 연결한 후 쿼리를 실행할 수 있습니다.
이것은 여전히 간단하지만 문자열을 뒤집는 것에 비해 더 복잡한 논리가 필요합니다. 그러나 이것이 꼬여야 한다는 의미는 아닙니다. 여전히 내장 모듈의 기능을 효과적으로 사용하고 다른 개발자가 코드를 읽고 이해하고 기여할 수 있도록 코드를 구성해야 합니다.
평면적인 것이 중첩된 것보다 낫다.
평면적인 구조는 중첩된 구조보다 분석하고 이해하기가 쉽습니다. 프로젝트를 진행할 때 기능을 분리하기 위해 별도의 모듈을 만들고 싶은 유혹을 느낄 수 있습니다. 하지만 너무 많은 세분성은 과할 수 있습니다.
물론 평면적인 구조에서 벗어나야 하는 경우도 많습니다. 하지만 중첩이 필요하더라도 최소한으로 유지하십시오.
다음은 예시입니다:
from db_info.config.actions.parse.parse_config import parse_toml # 이해하기 너무 어렵습니다! ... from db_config.parse_config import parse_toml # 훨씬 좋습니다! ...
희소한 것이 밀집된 것보다 낫다.
개발 여정을 막 시작했다면 언어의 특정 기능을 남용하고 싶은 유혹을 느낄 수 있습니다. 예를 들어, 리스트 컴프리헨션은 파이썬스럽지만 필요한 경우에만 사용해야 합니다.
다음과 같은 리스트 컴프리헨션을 살펴보세요:
prices_dict = {'melons':40,'apples':70,'berries':55} items = [(fruit,price) for fruit in prices_dict.keys() if fruit.startswith('m') for price in prices_dict.values() if price < 50] print(items) # 출력: [('melons', 40)]
리스트 컴프리헨션이 너무 밀집되어 있고 분석하기 어렵습니다. 이 경우 조건문과 동등한 for 루프를 사용하면 더 읽기 쉬울 것입니다. 즉, 이해하기가 어렵다는 것입니다. 🙂
가독성은 중요하다.
항상 읽기 쉬운 코드를 작성해야 합니다. 다음은 코드 가독성을 향상시키는 몇 가지 간단한 방법입니다.
- 설명적인 변수 이름을 사용하세요.
- 함수 및 클래스에 독스트링을 추가하세요.
- 필요한 곳에 코드 주석을 추가하세요.
- 함수의 인수 및 반환 유형에 대한 타입 힌트를 추가하세요.
특별한 경우는 규칙을 어길 만큼 특별하지 않다.
언어의 규칙과 권장되는 모범 사례를 최대한 따라야 합니다.
하지만 이것이 항상 가능할까요? 그렇지 않습니다. 그래서 다음 격언이 있습니다.
실용성이 순수함을 이기지만.
이것은 이전 격언에 대한 연속적인 내용입니다. 언어의 규칙을 따르는 것이 좋지만 때로는 몇 가지 원칙을 따르지 않아도 괜찮습니다.
오류는 결코 조용히 지나가서는 안 된다.
파이썬 런타임 오류는 매우 흔합니다. 오류를 처리하고 단순히 빠른 해결책으로 오류를 숨기려고 하지 않는 것이 좋습니다.
다양한 오류 유형에 대해 적절한 오류 처리를 예상하고 구현해야 합니다.
try: # 이 작업을 수행합니다. except ErrorType1: # 무언가를 수행합니다. except ErrorType2: # 다른 것을 수행합니다. ...
기본적으로 모든 예외를 잡으려는 시도는 피해야 합니다. 최신 버전의 파이썬(파이썬 3.11 이상)은 더 정교한 예외 처리를 가능하게 하는 예외 체이닝 및 예외 그룹을 지원합니다.
명시적으로 침묵시키지 않는 한.
이것은 이전 격언의 연속입니다. 디자인상 오류를 침묵시켜야 하는 경우 명시적으로 그렇게 해야 합니다.
예를 들어 데이터베이스에 연결할 때 잘못된 설정 정보로 인해 OperationalError가 발생할 수 있습니다. 사용자 정의 설정을 사용하여 연결을 시도하고, OperationalError가 발생하면 기본 설정을 사용하여 데이터베이스 연결을 시도할 수 있습니다.
try: # 사용자 정의 설정을 사용하여 연결을 시도합니다. except OperationalError: # 기본 설정을 사용하여 연결합니다.
모호함에 직면했을 때는 추측하려는 유혹을 거부하라.
파이썬의 선에 담긴 이 격언은 자명합니다. 의심스러울 때는 추측하지 마십시오. 대신 코드를 실행하고 결과를 확인하십시오. 그런 다음 원하는 동작이 발생하는지 확인한 다음 가독성을 개선하거나 필요에 따라 논리를 수정하십시오.
부울 튜플을 사용한 다음의 간단한 예시를 살펴보겠습니다:
>>> True, True == (True, True) (True, False) >>> True, (True == (True, True)) (True, False) >>> (True, True) == (True, True) True
무언가를 하는 명확한 방법은 하나, 가급적이면 단 하나여야 한다.
특정 작업을 수행하는 데 권장되는 파이썬 방법은 단 하나여야 합니다. 하지만 모든 문제에는 여러 가지 해결책이 있을 수 있습니다.
간단한 문자열을 뒤집는 예에서도 재귀적 방법, 문자열 슬라이싱, 그리고 join() 메서드를 확인했습니다.
이것은 또한 엠대시의 일관성 없는 사용을 고려했을 때 내부적으로 농담일 수도 있습니다. 우리는 일반적으로 전각 대시를 앞뒤 공백 없이 사용하거나, 앞뒤 공백 모두와 함께 사용합니다.
여기서 추론할 수 있는 것은 다음과 같습니다. 작업을 처리하는 파이썬 방식은 하나만 있어야 한다고 강조하는 격언 자체가 두 가지 이상의 방식으로 작성될 수 있다는 것입니다.
네덜란드인이 아니라면 처음에는 그 방법이 명확하지 않을 수 있지만.
가벼운 마음으로 작성된 이 격언은 파이썬의 창시자인 네덜란드인 Guido Van Rossum을 가리킵니다. 특정 작업을 수행하는 (가장) 파이썬다운 방법은 파이썬 작성자에게만 자연스럽게 떠오르는 것일 수 있습니다.
따라서 개발자가 언어의 기능을 더 잘 활용하려면 경험과 학습을 통해 익숙해져야 합니다.
지금 하는 것이 결코 안 하는 것보다 낫다.
파이썬의 선에 담긴 다른 격언과 마찬가지로 이것도 여러 가지 다른 방식으로 해석될 수 있습니다.
한 가지 해석은 개발자로서 프로젝트 코딩 시작을 미루는 것이 매우 일반적이라는 것입니다. 프로젝트의 세부 사항을 계획하기 위해 기다리기보다는 지금 시작하는 것이 더 나은 생각입니다.
또 다른 가능한 해석은 다음과 같습니다. 유한한 수의 단계에서 실행되고 종료되는 코드가 종종 무한 루프에 빠지는 코드보다 낫다는 것입니다.
결코 지금보다 더 나은 경우는 없습니다.
이 격언은 이전 격언과 모순되는 것처럼 보입니다. 미루지 않는 것이 좋지만, 문제에 대해 충분히 생각하고 그에 따라 코드를 설계해야 합니다.
적절한 생각 없이 모듈을 코딩하는 것은 코드 냄새와 안티패턴으로 가득 찬 좋지 않은 생각입니다. 이러한 코드는 수정하고 리팩토링하기 어렵기 때문입니다.
구현이 설명하기 어렵다면 나쁜 생각이다.
모든 논리는 아무리 복잡하더라도 항상 설명하기 쉽고 이해하기 쉬운 형태로 구현할 수 있습니다.
구현을 설명하기 어렵다면 불필요한 복잡성이 있을 수 있습니다. 따라하기 쉽도록 코드를 수정하거나 리팩토링할 수 있습니다.
구현이 설명하기 쉽다면 좋은 생각일 수 있다.
이것은 이전 격언과 관련이 있으며 자명합니다. 구현을 간단한 용어로 설명할 수 있다면 그것은 좋은 생각일 가능성이 높습니다.
간단한 용어로 구현을 설명할 수 있는 코드는 복잡성이 최소화되어 읽고 따라하기 쉬울 가능성이 높기 때문입니다.
네임스페이스는 정말 멋진 아이디어 중 하나이다. 더 많이 사용하자!
파이썬에서 특정 범위의 객체는 네임스페이스의 이름을 사용하여 액세스할 수 있습니다. 예를 들어 클래스를 만들고 그것을 템플릿으로 사용하여 클래스의 인스턴스를 만들 수 있습니다. 이제 모든 인스턴스 변수는 해당 인스턴스의 네임스페이스에 속하게 됩니다.
이를 통해 충돌 없이 동일한 이름을 가진 객체를 사용할 수 있습니다. 하지만 필요한 경우에만 사용하고 코드의 단순성과 가독성을 해치지 않도록 해야 합니다.
결론
이것으로 튜토리얼을 마치겠습니다! 이 가이드가 파이썬의 선이 파이썬의 코드 스타일과 좋은 코딩 습관을 강조하는 데 어떻게 도움이 되는지 이해하는 데 도움이 되기를 바랍니다. 코딩을 많이 할수록 더 잘할 수 있습니다.
간결하고 읽기 쉬운 코드를 작성하는 방법에 관심이 있다면 파이썬 원라이너에 대한 이 기사를 읽어보세요.