해당 내용은 ‘파이썬 알고리즘 인터뷰’ 책의 일부를 발췌하여 정리한 내용입니다.

코딩 스타일

좋은 코드에 정답은 없다. 하지만, 많은 사람들이 선호하는 방식은 있다.

두 가이드가 좀 더 실용적인 관점에서 좋은 파이선 코드를 작성하는데 많은 도움이 된다. 좋은 코드란 모두가 이해할 수 있을 때 더 높은 가치를 발휘한다. 또한, 파이썬이 지향하는 방식인 스네이크 케이스(변수명 사이에 ‘_’ 활용 ex: python_snake)를 사용하도록 한다(실제, 연구 결과 스네이크 방식이 인지하기 더 쉽다는 결과가 있다).

변수명과 주석

# Number 1
def numMatchingSubseq(self, S: str, words: List[str]) -> int:
	a = 0

	for b in words:
		c= 0
		for i in range(len(b)):
			d = S[C:].find(b[i])
			if d <0 :
				a -= 1
				break
			else:
				c += d + 1
		a += 1
	
	return a
# Number 2

def numMatchingSubseq(self, S: str, words: List[str]) -> int:
	matched_count = 0

	for word in words:
		pos= 0
		for i in range(len(word)):
		# Find matching position for each character.
			found_pos = S[pos:].find(word[i])
			if found_pos <0 :
				matched_count -= 1
				break
			else: # If found, take step position forward.
				pos += found_pos + 1
		matched_count += 1
	
	return matched_count

1번과 2번은 같은 내용의 코드이다. 1번은 임의의 변수를 지정한 것이고 2번은 PEP 8문서 기준에 따라서 변수명을 작성해주고 주석을 달아놓은 코드이다. 확연히 2번 코드가 눈으로 보고 이해하기 더 쉬운 코드임을 한눈에 알 수 있다. 저자의 경우, 코드에 주석을 상세히 달아놓는 것을 선호한다고 언급하였다.

리스트 컴프리헨션

리스트 컴프리헨션은 파이썬의 매우 강력한 기능 중 하나이지만, 지나치게 남발할 경우 가독성을 떨어뜨릴 수 있다.

str1s = [str[i:i + 2].lower() for i in range(len(str1) - 1) if re.findall('[a-z]{2}', str1[i:i + 2].lower())]

줄이 너무 길어서 벌써부터 피로도가 올라간다. 줄바꿈을 통해 아래와 같이 간결하게 코드를 정리해보자.

str1s = [
		str[i:i + 2].lower() for i in range(len(str1) - 1)
		if re.findall('[a-z]{2}', str1[i:i + 2].lower())
]

첫 번째 코드보다는 보기는 좋아졌지만 그래도 풀어쓰는 것보단 가독성이 떨어져보인다. 가독성을 위해 아예 풀어서 작성을 해보자.

str1s = []
for i in range(len(str1) - 1):
	if re.findall('[a-z]{2}', str1[i:i + 2].lower()):
			str1s.append(str1[i:i + 2].lower())

경우에 따라서 가독성을 위해 모두 풀어쓰는 것도 검토해볼만 하다. 리스트 컴프리헨션은 대체로 표현식이 2개를 넘지 않아야 한다. 다만, 아래와 같이 작성하면 가독성이 지나치게 떨어지므로 주의가 필요하다.

return [(x, y, z)
				for x in range(5)
				for y in range(5)
				if x != y
				for z in range(5)
				if y != z]

구글 파이썬 스타일 가이드

  • 함수의 기본값으로 가변 객체(Mutable Object) 가 아닌 불변 객체(Immutable Object)를 사용한다. None을 명시적으로 할당하는 것도 좋은 방법이다.

      # Not a good function
        
      def foo(a, b = []):
      ...
      def foo(a, b: Mapping = {}):
        
      # Good function
        
      def foo(a, b = None):
      		if be is None:
      			b = []
      ...
      def foo(a, b: Optional[Sequence] = None):
      		if b is None:
      				b = []
    
  • True, False를 판별할 때는 암시적(Implict)인 방법을 사용하는 편이 간결하고 가독성이 좋다.

      # Good example
        
      if not users:
      		print('no users')
        
      if foo == 0:
      		self.handle_zero()
        
      if i % 10 == 0:
      		self.handle_multiple_of_ten()
        
      # Bad example
        
      if len(users) == 0:
      		print('no users')
        
      if foo is not None and not foo:
      		self.handle_zero()
        
      if not i % 10:
      		self.handle_multiple_of_ten()
    
  • 최대 줄 길이는 80자로 한다. 또한, 줄의 가로길이는 길어서 안된다는 암묵적인 약속이 있다.