assert라는 개념은 가정 설정문을 뜻하는 assertion에서 나오게 되었습니다. 프로그램 개발의 과정에서 '실수는 일어난다'고 가정하고, 참/거짓을 미리 가정하는 문을 배치하여 이를 방지하는 것입니다. 이것을 방어적 프로그래밍(defensive programming)이라고 부르며, 방어적 프로그래밍의 가장 일반적인 구현 방식은 여기서 말한 assert를 사용합니다.

assert

assert(가정 설정문)은 단순하게 프로그램의 특정 지점에서 항상 참이어야 하는 문장입니다. Python을 비롯해 assertion을 지원하는 프로그래밍 언어들은 대부분 assert의 조건을 확인하여 참이면 다음 문장으로 넘어가고, 거짓이면 프로그램을 정지시킵니다. Python에서는 assert의 조건이 거짓인 경우 AssertionError를 발생시킵니다. assert의 예는 다음과 같습니다.

assert [condition] 형태입니다. 조금 현실적으로 바꾼다면, 아래처럼 작성할 수 있습니다.

assert에 메시지를 작성할 수도 있습니다. assert [condition], [message] 형태입니다.

이는 raise AssertionError('Data should only contain positive values')와 같은 결과를 내보냅니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] Coroutines  (0) 2018.07.27
[Python] memoize  (0) 2018.07.26
[Python] Generator  (0) 2018.07.23
[Python] Iterable, Sequence, Iterator  (0) 2018.07.22
[Python] Decorator  (0) 2018.07.21

Generator는 iterator의 역할을 할 수 있는 generator 객체를 만들기 위한 함수입니다. 쉽게 말하면 iterator를 생성해 주는 함수입니다.(매직 메소드인 __next__()가 정의되어 있으므로) 다만 return 문을 통해 특정 값을 반환하고 호출 스택에서 제거되어 종료되는 일반적인 함수와 다르게, generator는 yield를 만나면 함수가 정지되며, next()가 호출될 때마다 하나의 값만을 반환하게 됩니다. 따라서 일반적인 iterator에 비해 아주 작은 메모리만을 사용합니다. 이를 프로그래밍 분야에서는 '게으른 연산'이라고 부릅니다.

Generator 함수

List의 모든 값을 제곱하여 반환하는 함수를 작성해 보겠습니다.

위의 square_numbers는 우리가 지금까지 봐왔던 일반적인 함수입니다. 한 번의 호출에 한 번의 반환을 하고, 그대로 함수는 종료됩니다.

아래의 square_numbers_generatorreturn 대신 yield라는 키워드를 통해 값을 반환하는 함수입니다. yield 구문은 해당 함수의 반환값에 대해 next()가 호출될 때마다 한 번씩 실행되며, 따라서 iterator와 거의 동일하게 동작합니다. 빌트인 함수 dir()을 이용해 객체에 담겨 있는 필드와 메소드를 확인해 보면, __next__() 메소드가 정의되어 있는 것도 확인할 수 있습니다.

Generator expression

위에서 함수 형태로 선언했던 generator 표현을 조금 더 쉽게 할 수 있도록, Python에서는 generator expression을 제공합니다. List comprehension의 대괄호를 소괄호로 바꾸기만 하면 됩니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] memoize  (0) 2018.07.26
[Python] Assert  (0) 2018.07.25
[Python] Iterable, Sequence, Iterator  (0) 2018.07.22
[Python] Decorator  (0) 2018.07.21
[Python] Closure  (0) 2018.07.20

Python에는 구분하기 애매한 세 가지의 개념이 존재하는데, 바로 IterableSequence, Iterator입니다.

Iterable

Iterable각각의 요소를 하나씩 반환할 수 있는 객체를 말합니다. 이전에 살펴봤던 List와 Tuple, Dictionary와 Set 등이 여기에 속합니다. 정확히는 iterator를 반환하는 빌트인 함수 iter()를 위한 매직 메소드인__iter__()를 구현하고 있는 객체를 iterable이라고 부릅니다.

list, tuple, str은 모두 __iter__()를 구현하고 있으므로 iterable이라고 할 수 있습니다. 해당 객체들 대해 __iter__() 메소드를 호출하니 ***_iterator 객체가 반환되었습니다.

Sequence

Sequence는 __len__()__getitem__() 메소드를 가지고 있는 객체입니다.

따라서, list와 tuple 등 Python의 기본 iterable 타입들은 __iter__(), __len__(), __getitem__() 메소드를 모두 구현하고 있으므로 sequence이자 iterable입니다.

Iterator

Iterator데이터 스트림을 표현합니다. 내부적으로 매직 메소드 __next__()가 구현되어 있어, next()의 인자로 넘겨 다음 데이터를 불러올 수 있다면 iterator라고 말할 수 있습니다.

결론적으로,

  • 빌트인 함수 iter()에 대응되는 매직 메소드 __iter__() 가 정의되어 있는 객체를 Iterable이라고 말할 수 있고
  • 빌트인 함수 len()에 대응되는 매직 메소드 __len__()__getitem__()이 정의되어 있는 객체를 Sequence라고 말하고
  • 빌트인 함수 next()에 대응되는 매직 메소드 __next__()가 정의되어 있는 객체를 Iterator라고 말할 수 있습니다.


'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] Assert  (0) 2018.07.25
[Python] Generator  (0) 2018.07.23
[Python] Decorator  (0) 2018.07.21
[Python] Closure  (0) 2018.07.20
[Python] 문자열의 메모리 할당 방식  (0) 2018.07.19

Python의 함수는 일급 객체라는 특성 상, Decorator라는 문법을 이용해 특정 함수에 미리 만들어 둔 함수를 전달해 기능을 추가할 수도 있습니다. Python 2.4에서 추가되었고, PEP 318에서 확인해볼 수 있습니다. 간단하게, 함수가 호출되기 전에 '함수가 실행됩니다'라는 문자열을 출력해 봅시다.

천천히 살펴봅시다.

  • decorator 함수는 인자로 fn이라는 함수를 받습니다.
  • decorator 함수는 '함수가 실행됩니다.'라는 문자열을 출력하며 fn을 호출하고 그 결과를 반환하는 내부 함수 wrapper를 가지고 있습니다.
  • decorator 함수는 내부 함수인 wrapper를 리턴합니다.

wrapper 함수는 클로저로 인해 decorator 함수가 가진 지역변수 fn에 접근할 수 있게 됩니다. 그럼 코드의 흐름을 살펴 봅시다.

  • decorator 함수에 'hello'라는 문자열을 출력하는 print_hello 함수를 전달했습니다.
  • decorator 함수는 wrapper 함수를 리턴합니다. 이를 decorated_print_hello라는 변수에 할당했습니다.
  • 해당 변수의 타입은 함수이므로, 그대로 호출하면 wrapper 함수가 호출되며 '함수가 실행됩니다.'라는 문자열이 출력되고, 전달했던 print_hello 함수가 호출되어 'hello'까지 출력되었습니다.

Decorator expression

일반적으로 위와 같이 함수를 넘겨주고, 함수를 받고, 그걸 다시 실행하는 복잡한 구조는 잘 사용하지 않습니다. Python은 데코레이터를 쉽게 사용할 수 있도록 @ 심볼을 제공하며, 이 부분은 Java의 어노테이션과 비슷합니다.

인자가 있는 함수 데코레이팅하기

인자를 가진 함수를 데코레이팅하고 싶다면, 내부(wrapper) 함수에 *args**kwargs를 추가하면 됩니다.

여기서 wrapper 함수는 데코레이팅과 함께 인자를 중계해주는 형태입니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] Generator  (0) 2018.07.23
[Python] Iterable, Sequence, Iterator  (0) 2018.07.22
[Python] Closure  (0) 2018.07.20
[Python] 문자열의 메모리 할당 방식  (0) 2018.07.19
[Python] 함수 인자의 기본값 평가  (0) 2018.07.14

Python의 함수는 값이며, 몇 가지 추가적인 특징(변수 할당, 매개변수 전달, 반환값으로 사용 가능 등) 때문에 일급 객체로 분류할 수 있습니다. Python은 함수 안에 함수를 정의할 수 있으며, 그렇게 정의된 내부 함수는 외부 함수의 문맥에 접근할 수 있습니다. 쉽게 말하면, 외부 함수가 가지고 있는 지역변수에 접근할 수 있다는 것입니다.

calculator라는 함수를 정의했고, 이 함수는 두 개의 인자를 받아 처리하는 함수 fn, 두 정수 a, b를 받습니다. 함수 내부에는 sum함수가 정의되어 있습니다.

  • 만약 fn이 전달되었다면(if fn) 인자 a와 b를 전달하며 해당 함수 fn을 호출하고, fn의 반환값을 반환합니다.
  • 만약 fn이 전달되지 않았다면(else) 내부 함수인 sum을 호출합니다.

함수의 인자로 함수를 전달하는 일은 낯설지 않지만, calculator 함수의 내부 함수인 sum 함수는 아무 인자를 받지 않았음에도 변수 a와 b에 접근할 수 있습니다. 이처럼 내부 함수가 외부 함수의 지역변수에 접근할 수 있는 것을 클로저(Closure)라고 하며, 데코레이터와 같은 Python의 고급 개념들을 위해 필수적으로 사용됩니다.

Java에서는, 문자열 객체가 생성될 때마다 새로운 주소를 할당하는 방식을 사용합니다. 그러나 Python의 경우 문자열 객체 생성 시 매번 새로운 객체를 만드는 대신 기존에 선언되어 있던 immutable 객체를 사용합니다. 이는 CPython의 최적화 기법string interning에 의한 동작입니다. 따라서 둘 이상의 변수메모리의 동일한 문자열 객체를 가리킬 수 있고, 메모리를 절약하게 됩니다.

string interning의 규칙

string interning 최적화에는 몇가지 규칙이 있습니다.

  • 길이가 0 또는 1인 문자열은 intern
  • 컴파일 타임에만 intern : 동적으로 문자열을 만들어내는 경우(포맷팅 등) intern되지 않음
  • ASCII 문자, 숫자 또는 언더스코어가 아닌 문자가 속해 있는 경우(!, ? 등) intern되지 않음

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] Decorator  (0) 2018.07.21
[Python] Closure  (0) 2018.07.20
[Python] 함수 인자의 기본값 평가  (0) 2018.07.14
[Python] @property와 setter  (0) 2018.07.13
[Python] Keyword exclusive argument  (0) 2018.07.11

Python에서 함수의 인자는 아래처럼 4가지로 나뉩니다.

  • 필수 인자
  • 선택 인자
  • 가변 위치 인자 튜플
  • 가변 키워드 인자 딕셔너리

여기서 알아보고자 하는 건, 인자의 기본값입니다. Python에서 함수의 인자에는 기본값을 설정할 수 있고, 꽤 유용하게 사용할 수 있습니다.

그러나 Python에서 함수 인자의 기본값은 단 한 번만 평가됩니다. 따라서, 아래와 같은 함수는 예상 외의 결과를 만들어 냅니다.

log 함수에 at 인자가 전달되지 않을 경우 '현재 시간'으로 인자를 채우도록 하려는 의도였으나, 두 번의 함수 호출에 대한 at 인자의 값이 동일합니다. Python의 함수는 인자의 기본값 평가를 최초 한 번만 수행하기 때문입니다. 따라서 아래와 같이 함수를 작성하는 것이 좋습니다.

기본값을 None으로 두고, 함수 내부의 if문에서 값을 채워주는 방식입니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] Closure  (0) 2018.07.20
[Python] 문자열의 메모리 할당 방식  (0) 2018.07.19
[Python] @property와 setter  (0) 2018.07.13
[Python] Keyword exclusive argument  (0) 2018.07.11
[Python] 입출력  (0) 2018.07.10

객체지향 프로그래밍 패러다임에는 캡슐화라는 개념이 있습니다. 객체가 가진 속성들에 대한 접근을 제한하는 것인데, Java의 경우에는 private같은 접근 지정자와 getter/setter를 예로 들 수 있습니다. Python도 객체지향을 지원하며, 요소에 대한 접근 제한도 언더스코어를 통해 간접적으로 지원합니다.

그러나 이는 언어 자체(인터프리터 단위)에서 제약하는 진정한 의미의 접근 제한은 아니며, 컨벤션에 의한 표현법에 불과합니다. 객체의 필드에 대한 별도의 제약이 필요하면 property를 사용할 수 있습니다.

Python 함수의 인자는 아래처럼 4가지 종류가 있습니다.

  • 위치 인자
  • 키워드 인자
  • 가변 위치 인자 튜플
  • 가변 키워드 인자 딕셔너리

이들 중 키워드 인자를 의무로 사용하도록 강제할 수 있으며, 이를 키워드 전용 인자(Keyword exclusive argument)라는 Python 3의 특별한 문법을 사용합니다. 이를 통해 함수 호출자로 하여금 명시성을 강조할 수 있습니다.

asterisk(*) 뒤의 키워드 인자들을 키워드 전용 인자라고 부르며, 이렇게 선언된 인자들에 위치 인자 형태로 값을 넘기려고 하면 TypeError가 발생합니다. Python 2에서는 문법적으로 키워드 전용 인자 문법을 지원하지 않으며, **kwargsraise문을 사용하는 방식으로 키워드 전용 인자를 흉내낼 수 있습니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] 함수 인자의 기본값 평가  (0) 2018.07.14
[Python] @property와 setter  (0) 2018.07.13
[Python] 입출력  (0) 2018.07.10
[Python] Comprehension  (0) 2018.07.09
[Python] PEP  (0) 2018.07.08

프로그래밍에 있어 입출력은 매우 중요합니다. 여기서는 콘솔에서의 사용자 입출력파일 입출력을 다룹니다.

사용자 입출력

콘솔에서 사용자의 입력을 받기 위해 input 함수를 사용합니다. Python 2에는 raw_input이라는 함수도 있으나, Python 3에서 제거되었습니다. 사용자에게서 enter가 들어오기 전까지 제어는 멈춰 있습니다.

위처럼 input 함수에 문자열을 넘겨주며 hint를 제공할 수 있습니다. input의 반환값은 문자열이며, 따라서 1을 입력받더라도 문자열인 '1'로 처리됩니다. 정수를 받아 처리하고 싶다면 타입 캐스팅을 사용해야 합니다.

파일 입출력

파일을 열기 위해 open 함수를 사용합니다. 읽기, 쓰기, 추가 모드가 있습니다.

파일에 문자열 쓰기(w)

open 함수에 넘겨주는 첫 번째 인자는 파일의 이름이고, 두 번째 인자는 열기 모드입니다. 여기서는 쓰기(w) 모드로 열어 파일 객체의 write 메소드를 이용해 문자열을 쓰고, close 메소드를 이용해 파일을 닫았습니다. 기본적으로 쓰기 모드는 현재 경로에 해당 파일이 존재하지 않으면 파일을 만든 후 엽니다. 파일 열기 모드의 종류는 아래와 같습니다.

  • 읽기 : r
  • 쓰기 : w
  • 추가 : a

파일에 문자열 추가(a)

쓰기(w) 모드로 열린 파일에 write 메소드를 사용해 데이터를 쓸 경우, 파일에 적혀 있던 것들을 모두 지우고 해당 문자열을 기록하므로 기존의 파일 내용에 데이터를 추가한다면 추가(a) 모드로 파일을 열어야 합니다.

파일 읽기(r)

파일을 읽기(r) 모드로 열어 파일의 내용을 읽어 봅시다. 파일 열기 모드를 따로 넘겨주지 않으면 읽기(r) 모드로 파일을 엽니다. 문자열과 개행이 포함된 파일을 열어서 내용을 읽어 보겠습니다.

각각의 메소드를 테스트할 때마다 파일을 새로 열었는데, 이는 open에 의해 반환된 파일 객체는 파일을 순차적으로 읽어가기 때문입니다. 읽기 모드로 열린 파일 객체에 대해 파일의 내용을 조회하는 방법은 대표적으로 read, readline, readlines가 있습니다.

  • read : \n과 같은 이스케이핑 문자가 포함된 파일의 내용 전체를 가져옵니다.
  • readline : 메소드가 호출될 때마다 파일의 한 줄을 읽습니다.
  • readlines : 파일의 내용을 개행 기준으로 나눠 list로 반환합니다.

바이너리 파일 다루기

바이너리 파일도 읽기, 쓰기, 추가 모드로 나누어 열 수 있으며, 똑같이 open 함수에 각각 rb, wb, ab를 넘겨주면 됩니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] @property와 setter  (0) 2018.07.13
[Python] Keyword exclusive argument  (0) 2018.07.11
[Python] Comprehension  (0) 2018.07.09
[Python] PEP  (0) 2018.07.08
[Python] 패키지  (0) 2018.07.07

+ Recent posts