ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬 코딩의 기술 (브렛 슬라킨)
    Book Review 2021. 5. 29. 22:24

    Chapter 1 파이썬답게 생각하기

    Better Way 3 | bytes와 str의 차이를 알아두라

    - 파이썬은 bytes와 str 두 가지 타입을 이용해 문자열 데이터의 시퀀스를 표현한다. bytes에는 8비트 값의 시퀀스가 들어 있고, str에는 유니코드 코드 포인트의 시퀀스가 들어 있다.

     

    - 일반적으로는 UTF-8이 시스템 디폴트 인코딩 방식이다. (도우미 함수를 이용해서 문자 시퀀스 타입을 확실히 알 수 있다.)

     

    - 유니코드 데이터를 인코딩하거나 디코딩하는 부분을 인터페이스의 가장 먼 경계 지점에 위치시켜라. (= 유니코드 샌드위치)

     

    - 이진 8비트 값과 유니코드 문자열을 파이썬에서 다룰 때 꼭 기억해야 할 두 가지 문제점이 있다.

    첫 번째 문제점은 bytes와 str이 똑같이 작동하는 것처럼 보이지만 서로 호환되지 않기 때문에 전달 중인 시퀀스가 어떤 타입인지 잘 알고 있어야 한다.

    + 연산자를 이용해 같은 타입끼리 더할 수 있지만 bytes와 str은 더할 수 없다. 

     

    >>> print(b'one'+b'two')
    b'onetwo'
    >>> print('one'+'two')
    onetwo
    >>> print(b'one'+'two')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can't concat str to bytes

     

    두 번째 문제점은 파일 핸들과 관련한 연산들이 디폴트로 유니코드 문자열을 요구하고 있어서 코드가 실행되지 않을 수도 있다. (디폴트 인코딩이 의심스러운 경우 명시적으로 open에 encoding 파라미터를 전달해야 한다.)

     

    Better Way 4 | f-문자열을 통한 인터폴레이션을 사용하라

    • %연산자를 사용하는 C스타일 형식화 문자열은 여러 가지 단점과 번잡성이라는 문제가 있다.
    • str.format 메서드는 형식 지정자 미니 언어에서는 유영한 개념을 제공한다. 하지만 이를 제외하면 str.format 메서드도 C스타일 형식 문자열의 문제점을 그대로 가지고 있으므로, 사용을 피해야 한다. 
    • f-문자열은 값을 문자열 안에 넣는 새로운 구문으로, 형식 문자열의 표현력을 극대화하고, 키와 값을 불필요하게 중복 지정해야 하는 경우를 없애준다.  f-문자열은 형식화 식 안에서 현재 파이썬 영역에서 사용할 수 있는 모든 이름을 자유롭게 참조할 수 있도록 허용함으로써 간결함을 제공한다.
    •  
    • key = 'my_var'
      value = 1.2345
      
      formatted1 = f'{key} = {value}'
      formatted2 = f'{key!r:<10} = {value:.2f}'

     

    Better Way 5 | 복잡한 식을 쓰는 대신 도우미 함수를 작성하라

    • 파이썬 문법을 사용하면 복잡하고 읽기 어려운 한 줄짜리 식을 쉽게 작성할 수 있다.
    • 복잡한 식을 도우미 함수로 옮겨라. 특히 같은 로직을 반복해 사용할 때는 도우미 함수를 꼭 사용하라.
    • boolean연산자 or나 and를 식에 사용하는 것보다 if / else식을 쓰는 것이 더 가독성이 좋다.

     

    Better Way 6 | 인덱스를 사용하는 대신 대입을 사용해 데이터를 언패킹하라

    • 파이썬 언패킹은 일반화돼 있으므로 모든 이터러블에 적용할 수 있다. 그리고 이터러블이 여러 계층으로 내포된 경우에도 언패킹을 적용할 수 있다.
    • 인덱스를 사용해 시퀀스 내부에 접근하는 대신 언패킹을 사용해 시각적인 잡음을 줄이고 코드를 더 명확하게 만들라.

     

    Better Way 7 | range보다는 enumerate를 사용하라

    • -enumerate를 사용하면 이터레이터에 대해 루프를 돌면서 이터레이터에서 가져오는 원소의 인덱스까지 얻는 코드를 간결하게 작성할 수 있다.
    • range에 대해 루프를 돌면서 시퀀스의 원소를 가져오기 보다는 enumerate를 사용하라.
    • enumerate의 두 번째 파라미터로 어디부터 원소를 가져오기 시작할지 지정할 수 있다. (인덱스 시작값을 정해줄 수 있다. 디폴트 값은 0이다.)

     

    Better Way 8 | 여러 이터레이터에 대해 나란히 루프를 수행하려면 zip을 사용하라 (again plz)

    • -zip 내장 함수를 사용해 여러 이터레이터를 나란히 이터레이션할 수 있다.
    • zip은 튜플을 지연 계산하는 제너레이터를 만든다. 따라서 무한히 긴 입력에도 zip을 쓸 수 있다.
    • 입력 이터레이터의 길이가 서로 다르다면 zip은 아무런 경고도 없이 가장 짧은 이터레이터 길이까지만 튜플을 내놓고 더 긴 이터레이터의 나머지 원소는 무시한다.
    • 가장 짧은 이터레이터에 맞춰 길이를 제한하지 않고 길이가 서로 다른 이터레이터에 대해 루프를 수행하려면 itertools 내장 모듈의 zip_longest 함수를 사용하라.

     

    Better Way 9 | for나 while 루프 뒤에 else 블록을 사용하지 말라

    • 파이썬은 for나 while 루프에 속한 블록 바로 뒤에 else 블록을 허용하는 특별한 문법을 제공한다.
    • 루프 뒤에 오는 else 블록은 루프가 반복되는 도중에 break를 만나지 않은 경우에만 실행된다.
    • 동작이 직관적이지 않고 혼동을 야기할 수 있으므로 루프 뒤에 else블록을 사용하지 말라.

     

    Better Way 10 | 대입식을 사용해 반복을 피하라

    • 대입식에서는 왈러스 연산자(:=)를 사용해 하나의 식 안에서 변수 이름에 값을 대입하면서 이 값을 평가할 수 있고, 중복을 줄일 수 있다.
    • 대입식이 더 큰 식의 일부분으로 쓰일 때는 괄호로 둘러싸야 한다.
    • 파이썬에서는 swiich/case 문이나 do/while 루프를 쓸 수 없지만, 대입식을 사용하면 이런 기능을 더 깔끔하게 흉내 낼 수 있다. 

     

    Chapter 2 리스트와 딕셔너리

     

    Better Way 11 | 시퀀스를 슬라이싱하는 방법을 익혀라

    • 슬라이싱할 때는 간결하게 하라. 시작 인덱스에 0을 넣거나, 끝 인덱스에 시퀀스 길이를 넣지 말라.
    • 슬라이싱은 범위를 넘어가는 시작 인덱스나 끝 인덱스도 허용한다. (매핑과 대조) 따라서 시퀀스의 시작이나 끝에서 길이를 제한하는 슬라이스(a[:20]이나 a[20:])를 쉽게 표현할 수 있다.
    • 리스트 슬라이스에 대입하면 원래 시퀀스에서 슬라이스가 가리키는 부분을 대입 연산자 오른쪽에 있는 시퀀스로 대치한다. 이때 슬라이스와 대치되는 시퀀스의 길이가 달라도 된다. 

     

    Better Way 12 | 스트라이드와 슬라이스를 한 식에 함께 사용하지 말라

    • 슬라이스에 시작, 끝, 증가값을 함께 지정하면 코드의 의미를 혼동하기 쉽다.
    • 시작이나 끝 인덱스가 없는 슬라이스를 만들 때는 양수 증가값을 사용하라. 가급적 음수 증가값은 피하라
    • 한 슬라이스 안에서 시작, 끝, 증가값을 함께 사용하지 말라.  세 파라미터를 모두 써야하는 경우, 두 번 대입을 사용(한 번은 스트라이딩, 한 번은 슬라이싱)하거나 itertools 내장 모듈의 islice를 사용하라.

     

    Better Way 13 | 슬라이싱보다는 나머지를 모두 잡아내는 언패킹을 사용하라

    • 언패킹 대입에 별표 식을 사용하면 언패킹 패턴에서 대입되지 않는 모든 부분을 리스트에 잡아낼 수 있다.
    • 별표 식은 언패킹 패턴의 어떤 위치에든 놓을 수 있다. 별표 식에 대입된 결과는 항상 리스트가 되며, 이 리스트에는 별표 식이 받은 값이 0개 또는 그 이상이 들어간다. (0개일 경우 빈 리스트 반환)
    • 리스트를 서로 겹치지 않게 여러 조각으로 나눌 경우, 슬라이싱과 인덱싱을 사용하기보다는 나머지를 모두 잡아내는 언패킹을 사용해야 실수할 여지가 줄어든다.

     

    Better Way 14 | 복잡한 기준을 사용해 정렬할 때는 key 파라미터를 사용하라(이해안됨)

    • 리스트 타입에 들어 있는 sort 메서드를 사용하면 원소 타입이 문자열, 정수, 튜플 등과 같은 내장 타입인 경우 자연스러운 순서로 리스트의 원소를 정렬할 수 있다.
    • 원소 타입에 특별 메서드를 통해 자연스러운 순서가 정의돼 있지 않으면 sort 메서드를 쓸 수 없다. 하지만 원소 타입에 특별 메서드를 정의하는 경우는 드물다.
    • sort 메서드의 key 파라미터를 사용하면 리스트의 각 원소 대신 비교에 사용할 객체를 반환하는 도우미 함수를 제공할 수 있다.
    • key 함수에서 튜플을 반환하면 여러 정렬 기준을 하나로 엮을 수 있다. 단항 부호 반전 연산자를 사용하면 부호를 바꿀 수 있는 타입이 정렬 기준인 경우 정렬 순서를 반대로 바꿀 수 있다.
    • 부호를 바꿀 수 없는 경우 여러 정렬 기준을 조합하려면 각 정렬 기준마다 reverse 값으로 정렬 순서를 지정하면서 sort 메서드를 여러 번 사용해야 한다. 이때 정렬 기준의 우선순위가 점점 높아지는 순서로 sort를 호출해야 한다.

     

    Better Way 15 | 딕셔너리 삽입 순서에 의존할 때는 조심하라

    • 파이썬 3.7부터는 dict 인스턴스에 들어 있는 내용을 이터레이션할 때 키를 삽입한 순서대로 돌려받는다는 사실에 의존할 수 있다.
    • 파이썬은 dict는 아니지만 딕셔너리와 비슷한 객체를 쉽게 만들 수 있게 해준다. 이런 타입의 경우 키 삽입 순서가 그대로 보존된다고 가정할 수 없다.
    • 딕셔너리와 비슷한 클래스를 조심스럽게 다루는 방법으로는 dict 인스턴스의 삽입 순서 보존에 의존하지 않고 코드를 작성하는 방법, 실행 시점에 명시적으로 dict 타입을 검사하는 방법, 타입 애너테이션과 정적 분석(static analysis)을 사용해 dict 값을 요구하는 방법이 있다.

     

    Better Way 16 | in을 사용하고 딕셔너리 키가 없을 떄 KeyError를 처리하기보다는 get을 사용하라

    • 딕셔너리 키가 없는 경우를 처리하는 방법으로는 in 식을 사용하는 방법, KeyError 예외를 사용하는 방법, get 메서드를 사용하는 방법, setdefault 메서드를 사용하는 방법이 있다.
    • 카운터와 같이 기본적인 타입의 값이 들어가는 딕셔너리를 다룰 때는 get 메서드가 가장 좋고, 딕셔너리에 넣을 값을 만드는 비용이 비싸거나 만드는 과정에 예외가 발생할 수 있는 경우에도 get 메서드를 사용하는 편이 낫다.
    • 해결하려는 문제에 dict의 setdefault 메서드를 사용하는 방법이 적합해 보인다면 setdefault 대신 defaultdict를 사용할지 고려해보라.

     

    Better Way 17 | 내부 상태에서 원소가 없는 경우를 처리할 때는 setdefault보다 defaultdict를 사용하라

    • 키로 어떤 값이 들어올지 모르는 딕셔너리를 관리해야 하는데 collections 내장 모듈에 있는 defaultdict 인스턴스가 여러분의 필요에 맞아떨어진다면 defaultdict를 사용하라.
    • 임의의 키가 들어 있는 딕셔너리가 여러분에게 전달됐고 그 딕셔너리가 어떻게 생성됐는지 모르는 경우, 딕셔너리의 원소에 접근하려면 우선 get을 사용해야 한다. 하지만 setdefaul가 더 짧은 코드를 만들어내는 몇 가지 경우에는 setdefault를 사용하는 것도 고려해볼 만하다.

     

    Better Way 18 | __missing__을 사용해 키에 따라 다른 디폴트 값을 생성하는 방법을 알아두라 (이해 안됨)

    • 디폴트 값을 만드는 계산 비용이 높거나 만드는 과정에서 예외가 발생할 수 있는 상황에서는 dict의 setdefault 메서드를 사용하지 말라.
    • defaultdict에 전달되는 함수는 인자를 받지 않는다. 따라서 접근에 사용한 키 값에 맞는 디폴트 값을 생성하는 것은불가능하다.
    • 디폴트 키를 만들 때 어떤 키를 사용했는지 반드시 알아야 하는 상황이라면 직접 dict의 하위 클래스와 __missing__ 메서드를 정의하면 된다.

     

    Chapter  3 함수

     

    Better Way 19 | 함수가 여러 값을 반환하는 경우 네 값 이상을 언패킹하지 말라

    • 함수가 여러 값을 반환하기 위해 값들을 튜플에 넣어서 반환하고, 호출하는 쪽에서는 언패킹 구문을 쓸 수 있다.
    • 함수가 반환한 여러 값을, 모든 값을 처리하는 별표 식을 사용해 언패킹할 수도 있다.
    • 언패킹 구문에 변수가 네 개 이상 나오면 순서를 혼동하기 쉽고, 가독성도 안좋아서 실수하기 쉬우므로 변수를 네 개 이상 사용하면 안된다. 대신 작은 클래스를 반환하거나 namedtuple 인스턴스를 반환하라.

     

     

    Better way 20 | None을 반환하기 보다는 예외를 발생시켜라

    • 특별한 의미를 표시하는 None을 반환하는 함수를 사용하면 None과 다른 값(0이나 빈 문자열)이 조건문에서 False로 평가될 수 있기 때문에 실수하기 쉽다.
    • 특별한 상황을 표현하기 위해 None을 반환하는 대신 예외를 발생시켜라. 문서에 예외 정보를 기록해 호출자가 예외를 제대로 처리하도록 하라. (raise error)
    • 함수가 특별한 경우를 포함하는 그 어떤 경우에도 절대로 None을 반환하지 않는다는 사실을 타입 애너테이션으로 명시할 수 있다. 

     

     

    Better way 21 | 변수 영역과 클로저의 상호작용 방식을 이해하라 (잘 모르겠음)

    • 클로저 함수는 자신이 정의된 영역 외부에서 정의된 변수도 참조할 수 있다.
    • 기본적으로 클로저 내부에 사용한 대입문은 클로저를 감싸는 영역에 영향을 끼칠 수 없다.
    • 클로저가 자신을 감싸는 영역의 변수를 변경한다는 사실을 표시할 때는  nonlocal 문을 사용하라.
    • 간단한 함수가 아닌 경우에는 nonlocal 문을 사용하지 말라.

     

     

    Better way 22 | 변수 위치 인자를 사용해 시각적인 잡음을 줄여라

    • def 문에서 *args를 사용하면 함수가 가변 위치 기반 인자를 받을 수 있다.
    • * 연산자를 사용하면 가변 인자를 받는 함수에게 시퀀스 내의 원소들을 전달할 수 있다.
    • 제너레이터에 * 연산자를 사용하면 프로그램이 메모리를 모두 소진하고 중단할 수 있다.
    • *args를 받는 함수에 새로운 위치 기반 인자를 넣으면 감지하기 힘든 버그가 생길 수 있다.

     

     

    Better way 23 | 키워드 인자로 선택적인 기능을 제공하라

    • 함수 인자를 위치에 따라 지정할 수도 있고, 키워드를 사용해 지정할 수도 있다.
    • 키워드를 사용하면 위치 인자만 사용할 때는 혼동할 수 있는 여러 인자의 목적을 명확히 할 수 있다.
    • 키워드 인자와 디폴트 값을 함께 사용하면 기본 호출 코드를 마이그레이션하지 않고도 함수에 새로운 기능을 쉽게 추가할 수 있다.
    • 선택적 키워드 인자는 항상 위치가 아니라 키워드를 사용해 전달돼야 한다.

     

     

    Better way 24 | None과 독스트링을 사용해 동적인 디폴트 인자를 지정하라

    • 디폴트 인자 값은 그 인자가 포함된 함수 정의가 속한 모듈이 로드되는 시점에 단 한 번만 평가된다. 이로 인해 동적인 값({}, [], datetime.now() 등)의 경우 이상한 동작이 일어날 수 있다.
    • 동적인 값을 가질 수 있는 키워드 인자의 디폴트 값을 표현할 때는 None을 사용하라. 그리고 함수의 독스트링에 실제 동적인 디폴트 인자가 어떻게 동작하는지 문서화해두라.
    • 타입 애너테이션을 사용할 때도 None을 사용해 키워드 인자의 디폴트 값을 표현하는 방식을 적용할 수 있다.

     

     

    Better way 25 | 위치로만 인자를 지정하게 하거나 키워드로만 인자를 지정하게 해서 함수 호출을 명확하게 만들라

    • 키워드로만 지정해야 하는 인자를 사용하면 호출하는 쪽에서 특정 인자를 (위치를 사용하지 않고) 반드시 키워드를 사용해 호출하도록 강제할 수 있다. 이로 인해 함수 호출의 의도를 명확히 할 수 있다. 키워드로만 지정해야 하는 인자는 인자 목록에서 * 다음에 위치한다.
    • 위치로만 지정해야 하는 인자를 사용하면 호출하는 쪽에서 키워드를 사용해 인자를 지정하지 못하게 만들 수 있고, 이에 따라 함수 구현과 함수 호출 지점 사이의 결합을 줄일 수 있다. 위치로만 지정해야 하는 인자는 인자 목록에서 / 앞에 위치한다.
    • 인자 목록에서 / 와 * 사이에 있는 파라미터는 키워드를 사용해도 되고 위치를 기반으로 전달해도 된다. 이런 동작은 파이썬 함수 파라미터의 기본 동작이다.

     

    Better way 26 | functools.wrap을 사용해 함수 데코레이터를 정의하라

    • 파이썬 데코레이터는 실행 시점에 함수가 다른 함수를 변경할 수 있게 해주는 구문이다.
    • 데코레이터를 사용하면 디버거 등 인트로스펙션을 사용하는 도구가 잘못 작동할 수 있다.
    • 직접 데코레이터를 구현할 때 인트로스펙션에서 문제가 생기지 않길 바란다면 functools 내장 모듈의 wraps 데코레이터를 사용하라.

     

     

    Chapter 4 컴프리헨션과 제너레이터

     

    Better way  27 | map과 filter 대신 컴프리헨션을 사용하라

    • 리스트 컴프리헨션은 lambda 식을 사용하지 않기 때문에 같은 일을 하는 map과 filter내장 함수를 사용하는 것보다 더 명확하다
    • 리스트 컴프리헨션을 사용하면 쉽게 입력 리스트의 원소를 건너뛸 수 있다. 하지만 map을 사용하는 경우에는 filter의 도움을 받아야만 한다.
    • 딕셔녀리와 집합도 컴프리헨션으로 생성할 수 있다.

     

    Better way 28 | 컴프리헨션 내부에 제어 하위 식을 세 개 이상 사용하지 말라

    • 컴프리헨션은 여러 수준의 루프를 지원하며 각 수준마다 여러 조건을 지원한다.
    • 제어 하위 식이 세 개 이상인 컴프리헨션은 이해하기 매우 어려우므로 가능하면 피해야 한다.

     

     

    Better way 29 | 대입식을 사용해 컴프리헨션 안에서 반복 작업을 피해라

    • 대입식(:=)을 통해 컴프리헨션이나 제너레이터 식의 조건 부분에서 사용한 값을 같은 컴프리헨션이나 제너레이터의 다른 위치에서 재사용할 수 있다. 이를 통해 가동성과 성능을 향상시킬 수 있다.
    • 조건이 아닌 부분에도 대입식을 사용할 수 있지만, 그런 형태의 사용은 피한다.

     

    Better way 30 | 리스트를 반환하기보다는 제너레이터를 사용하라

    • 제너레이터를 사용하면 결과를 리스트에 합쳐서 반환하는 것보다 더 깔끔하고 효율적이다.
    • 제너레이터가 반환하는 이터레이터는 제너레이터 함수의 본문에서 yield가 반환하는 값들로 이뤄진 집합을 만들어낸다.
    • 제너레이터를 사용하면 작업 메모리에 모든 입력과 출력을 저장할 필요가 없으므로 입력이 아주 커도 출력 시퀀스를 만들 수 있다.

     

    Better way 31 | 인자에 대해 이터레이션할 때는 방어적이 돼라 (다시 읽기)

    • 입력 인자를 여러 번 이터레이션하는 함수나 메서드를 조심하라. 입력받은 인자가 이터레이터면 함수가 이상하게 작동하거나 결과가 없을 수 있다.
    • 파이썬의 이터레이터 프로토콜은 컨테이너와 이터레이터가 iter, next 내장 함수나 for 루프 등의 관련 식과 상호작용하는 절차를 정의한다.
    • __iter__ 메서드를 제너레이터로 정의하면 쉽게 이터러블 컨테이너 타입을 정의할 수 있다.
    • 어떤 값이 (컨테이너가 아닌) 이터레이터인지 감지하려면, 이 값을 iter 내장 함수에 넘겨서 반환되는 값이 원래 값과 같은지 확인하면 된다. 다른 방법으로 collections.abc.Iterator 클래스를 isinstance와 함께 사용할 수도 있다.

     

    Better way 32 | 긴 리스트 컴프리헨션보다는 제너레이터 식을 사용하라

    • 입력이 크면 메모리를 많이 차지하기 때문에 리스트 컴프리헨션은 문제를 일으킬 수 있다.
    • 제너레이터 식은 이터레이터처럼 한 번에 원소를 하나씩 출력하기 때문에 메모리 문제를 피할 수 있다.
    • 제너레이터 식이 반환한 이터레이터를 다른 제너레이터 식의 하위 식으로 사용함으로써 제너레이터 식을 서로 합성할 수 있다.
    • 서로 연결된 제너레이터 식은 매우 빠르게 실행되며 메모리도 효율적으로 사용한다.

     

     

    Better way 33 | yield from을 사용해 여러 제너레이터를 합성하라

    • yield from 식을 사용하면 여러 내장 제너레이터를 모아서 제너레이터 하나로 합성할 수 있다.
    • 직접 내포된 제너레이터를 이터레이션하면서 각 제너레이터의 출력을 내보내는 것보다 yield from을 사용하는 것이 성능 면에서 더 좋다.

     

     

    Better way 34 | send로 제너레이터에 데이터를 주입하지 말라

    • send 메서드를 사용해 데이터를 제너레이터에 주입할 수 있다. 제너레이터는 send로 주입된 값을 yield 식이 반환하는 값을 통해 받으며, 이 값을 변수에 저장해 활용할 수 있다.
    • send와 yield from 식을 함께 사용하면 제너레이터의 출력에 None이 불쑥 나타나는 의외의 결과를 얻을 수도 있다.
    • 합성할 제너레이터들의 입력으로 이터레이터를 전달하는 방식이 send를 사용하는 방식보다 더 낫다. 가급적이면 send는 사용하지 말라.

     

    Better way 35 | 제너레이터 안에서 throw로 상태를 변화시키지 말라

    • throw 메서드를 사용하면 제너레이터가 마지막으로 실행한 yield 식의 위치에서 예외를 다시 발생시킬 수 있다.
    • throw를 사용하면 가독성이 나빠진다. 예외를 잡아내고 다시 발생시키는 데 준비 코드가 필요하며 내포 단계가 깊어지기 때문이다.
    • 제너레이터에서 예외적인 동작을 제공하는 더 나은 방법은 __iter__ 메서드를 구현하는 클래스를 사용하면서 예외적인 경우에 상태를 전이시키는 것이다.

     

    Better way 36 | 이터레이터나 제너레이터를 다룰 때는 itertools를 사용하라

    • 이터레이터나 제너레이터를 다루는 itertools 함수는 세 가지 범주로 나눌 수 있다. i) 여러 이터레이터를 연결함 ii) 이터레이터의 원소를 걸러냄 iii) 원소의 조합을 만들어냄
    • 파이썬 인터프리터에서 help(itertools)를 입력한 후 표시되는 문자를 살펴보면 더 많은 고급 함수와 추가 파라미터를 알 수 있으며, 이를 사용하는 방법도 알 수 있다.

     

     

    Chapter 5. 클래스와 인터페이스

     

    Better way 37 | 내장 타입을 여러 단계로 내포시키기보다는 클래스를 합성하라

    • 딕셔너리, 긴 튜플, 다른 내장 타입이 복잡하게 내포된(계속해서 재사용) 데이터를 값으로 사용하는 딕셔너리를 만들지 말라.
    • 완전한 클래스가 제공하는 유연성이 필요하지 않고 가벼운 불변 데이터 컨테이너가 필요하다면 namedtuple을 사용하라.
    • 내부 상태를 표현하는 딕셔너리가 복잡해지면 이 데이터를 관리하는 코드를 여러 클래스로 나눠서 재작성하라.

     

    Better way 38 | 간단한 인터페이스의 경우 클래스 대신 함수를 받아라

    • 파이썬의 여러 컴포넌트 사이에 간단한 인터페이스가 필요할 때는 클래스를 정의하고 인스턴스화하는 대신 간단히 함수를 사용할 수 있다.
    • 파이썬 함수나 메서드는 일급 시민이다. 따라서 (다른 타입의 값과 마찬가지로) 함수나 함수 참조를 식에 사용할 수 있다.
    • __call__ 특별 메서드를 사용하면 클래스의 인스턴스인 객체를 일반 파이썬 함수처럼 호출할 수 있다.

     

    Better way 39 | 객체를 제너릭하게 구성하려면 @classmethod를 통한 다형성을 활용하라 (잘 모르겠음)

    • 파이썬의 클래스에는 생성자가 __init__ 메서드 뿐이다.
    • @classmethod를 사용하면 클래스에 다른 생성자를 정의할 수 있다.
    • 파이썬에서는 객체뿐 아니라 클래스도 다형성을 지원한다. 
    • 클래스 메서드 다형성을 활용하면 여러 구체적인 하위 클래스의 객체를 만들고 연결하는 제너릭한 방법을 제공할 수 있다. (계층을 이루는 여러 클래스가 자신에게 맞는 유일한 메서드 버전을 구현할 수 있다.)                                                                           

     

    Better way 40 | super로 부모 클래스를 초기화하라

    • 자식 클래스에서 부모 클래스를 초기화, 오버라이딩할 때 자식 인스턴스에서 부모 클래스의 __init__ 메서드를 직접 호출하는 경우 기본적인 클래스 계층의 경우에는 잘 작동하지만 어떤 클래스가 다중 상속에 의해 영향을 받을 경우 예측 불가능(상속 순서를 위반하거나 무시하게 되는 경우)한 경우가 생길 수 있다. 
    • 파이썬은 표준 메서드 결정 순서(MRO)를 활용해 상위 클래스 초기화 순서와 다이아몬드 상속 문제를 해결한다. super를 사용하면 다이아몬드 계층의 공통 상위 클래스를 단 한 번만 호출하도록 보장한다.
    • 상속 다이아몬드의 정점에 도달하면 각 초기화 메서드는 각 클래스의 __init__이 호출된 순서의 역순으로 작업을 수행한다.
    • 부모 클래스를 초기화할 때는 super 내장 함수를 아무 인자 없이 호출하라, super를 아무 인자 없이 호출하면 파이썬 컴파일러가 자동으로 올바른 파라미터를 넣어준다.

     

    class MybaseClass:
        def __init__(self, value):
            self.value = value
    
    #잘못된 예시
    class Timeseven(MybaseClass):
        def __init__(self, value):
            MybaseClass.__init__(self, value)
            self,value *= 3
    #옳은 예시
    class ExpliciTrisect(MybaseClass):
        def __init__(self, value):
            super().__init__(value)
            self.value /= 3

     

     

    Better way 41 | 기능을 합성할 때는 믹스인 클래스를 사용하라

    • 파이썬은 객체지향 언어이기 때문에 다중 상속을 지원하고 다중 상속은 캡슐화 기능으로 편의성을 제공하지만, 많은 골치거리를 갖고 있기 때문에 자식 클래스가 사용할 메서드 몇 개만 정의하는 믹스인(mix-in) 클래스를 사용할지 고려해야 한다. 
    • 파이썬은 타입 상관없이 객체의 상태를 쉽게 알 수 있어서 믹스인 작성이 쉽고, 믹스인은 자체 애트리뷰트 정의가 없으므로 믹스인 클래스의 __init__메서드를 호출할 필요도 없다. 즉 제너릭 기능을 믹스인에 한번만 작성하면, 여러 클래스에서 믹스인을 합성하거나 계층화해서 반복적인 코드를 최소화하고 재사용성을 최대화할 수 있다.
    • 믹스인 클래스가 클래스별로 특화된 기능을 필요로 한다면 인스턴스 수준에서 끼워 넣을 수 있는 기능(정해진 메서드를 통해 해당 기능을 인스턴스가 제공하게 만듦)을 활용하라.
    • 믹스인에는 필요에 따라 인스턴스 메서드는 물론 클래스 메서드도 포함될 수 있다.

     

    Better way 42 | 비공개 애트리뷰트보다는 공개 애트리뷰트를 사용하라

    • 파이썬에서 클래스의 애트리뷰트에 대한 가시성은 Public, Private로 나눌 수 있다. 애트리뷰트 이름 앞에 밑줄 두개(__)를 붙이면 비공개 필드가 된다. 클래스 외부에서(특히 자식 클래스)에서 비공개 필드에 접근하면 예외가 발생한다. (but 엄격히 금지하지 않는다.)
    • 비공개 애트리뷰트의 동작은 접근하는 애튜리뷰트의 이름을 바꾸는 단순한 방식으로 구현되기 때문에 특별한 권한을 요청할 필요 없이 외부, 하위 클래스에서 쉽게 접근할 수 있다.
    • 비공개 애트리뷰트를 사용하면 확장이나 오버라이드를 귀찮게 한다. 특히 실수로 부모 클래스가 이미 정의한 애트리뷰트를 정의하면 충돌이 생길 수 있다.
    • 내부 API에 있는 클래스의 하위 클래스를 정의하는 사람들이 여러분이 제공하는 클래스의 애트리뷰트를 사용하지 못하게 막기보다는 더 많은 일을 할 수 있게 허용하라. 비공개 처리보다는 보호된 필드를 사용하면서 문서에 적절한 가이드를 남겨라
    • 코드 작성을 제어할 수 없는 하위 클래스에서 이름 충돌이 일어나는 경우를 막고 싶을 때만 비공개 애트리뷰트를 사용할 것을 권장한다.

     

    Better way 43 | 커스텀 컨테이너 타입음 collections.abc를 상속하라 (한번더~)

    • 간편하게 사용할 경우에는 파이썬 컨테이너 타입(리스트, 딕셔너리)을 직접 상속하라.
    • 커스텀 컨테이너를 제대로 구현하려면 수많은 메서드를 구현해야 한다는 점에 주의하라.
    • 커스텀 컨테이너 타입이 collections.abc에 정의된 인터페이스를 상속하면 커스텀 컨테이너 타입이 정삭적으로 작동하기 위해 필요한 인터페이스와 기능을 제대로 구현하도록 보장할 수 있다.

     

    Chapter 6. 매타클래스와 애트리뷰트

     

    Better way 44 | 세터와 게터 메서드 대신 평범한 애트리뷰트를 사용하라

    •  

    Better way 45 | 애트리뷰트를 리팩터링하는 대신 @property를 사용하라

    •  

    Better way 46 | 재사용 가능한 @property 메서드를 만들려면 디스크립터를 사용하라

    •  

    Better way 47 | 지연 계산 애트리뷰트가 필요하면 __getattr__, __getattribute__, __setattr__을 사용하라 

    •  

    Better way 48 | __init_subclass__를 사용해 하위 클래스를 검증하라

    •  

    Better way 49 | __init_subclass__를 사용해 클래스 확장을 등록하라

    •  

    Better way 50 | __set_name__으로 클래스 애트리뷰트를 표시하라

    •  

    Better way 51 | 합성 가능한 클래스 확장이 필요하면 메타클래스보다는 클래스 데코레이터를 사용하라

    •  

    'Book Review' 카테고리의 다른 글

    cs opensource book  (0) 2022.09.16
    린 소프트웨어 개발론 적용  (0) 2022.04.05
    모두의 네트워크 Lesson 정리  (0) 2021.05.30
    해커와 화가 (폴 그레이엄)  (0) 2021.05.29
Designed by Tistory.