제어문, 모듈

return & yield

return은 함수의 결과 값을 한 번만 반환한다.

def test():
    for i in range(100):
        return i

print(test())
print(test())

>>> 0
>>> 0

반면, yield를 사용하면 generator를 쉽게 구현할 수 있다. (generator: iterator를 생성해주는 함수)

def test():
    for i in range(100):
        yield i


result = test()
print(next(result)) # test(): i == 0
print(next(result)) # test(): i == 1
print(next(result)) # test(): i == 2

>>> 0
>>> 1
>>> 2

함수가 yield를 만나면 멈추고 값을 반환하며, 멈췄을 때의 진행상태를 기억한다. iterator이기 때문에 next() 함수를 사용해 다음 함숫값을 가져온다. return과 다르게 yield는 next()를 호출할 때마다 부분적으로 함수를 동작시키기 때문에 모든 데이터를 한 번에 처리해야 하는 return에 비해 효율적이다. 


모듈

모듈은 함수클래스의 집합을 뜻한다. 함수는 def를 사용하여 정의하며, 함수의 객채와 참조가 같이 생성된다. 

* procedure: return 값이 없는 함수. 파이썬은 return 값이 없을 때, 기본으로 None을 반환한다. 

함수가 호출될 때는 활성화 레코드(activation record)가 생성되며, 스택 형태로 정보를 저장한다. 먼저 매개변수를 저장하고, 반환 주소를 저장하고, 함수의 지역변수를 저장한다. 함수를 실행할 때는 반대로 진행한다. 지역변수를 저장하는 과정에서 스택이 넘치는 경우를 stackoverflow라고 하며, Python에서는 MemoryError를 발생시킨다.

주의할 점은 함수의 매개변수 기본값은 함수를 호출할 때마다 생성되는 것이 아니라 생성해둔 값을 참조하는 방식으로 사용된다. 따라서, 매개변수의 기본값을 가변형으로 설정하면 값이 바뀔 수 있다.

def test(value, seq=[]):
    seq.append(value)
    print(seq)

test("a")
test("b")
test("c")


>>> ['a']
>>> ['a', 'b']
>>> ['a', 'b', 'c']

seq의 기본값을 가변형인 리스트로 설정하면, 값이 바뀐다는 것을 확인할 수 있다.


sys.path

sys.path는 모듈을 검색할 경로를 담고 있다. 환경변수편집을 통해 내용을 수정하거나 append를 이용해 임시로 추가할 수 있다.

import sys

sys.path

매직 메서드

Magic Method는 두 개의 언더스코어로 이루어진 메서드로, python에서 기본으로 제공하는 메서드이다.

__init__.py

init은 패키지를 생성할 때 사용된다. python은 __init__. py가 있는 파일을 하나의 패키지로 취급한다. 3.3 버전부터는 init파일을 생성하지 않아도 되지만 하위 버전 호환을 위해 생성하는 것을 권장한다. 

__all__

*을 이용해 모듈을 호출할 때, import 할 모듈이나 객체를 리스트 형태로 저장한다.

|-- main.py
|-- package
       |-- __init__.py
       |-- module1.py
       |-- module2.py
       |-- module3.py
# __init__.py
__all__ = ["module1", "module2"] # .py 생략
# __main__.py
from package import *
# module1, module2 사용 가능

__name__

모듈을 import 할 때, 파이썬은 __name__변수를 만든다. 현재 실행한 파일은 __main__이 된다. 따라서, 모듈을 import 할 때 실행되지 않을 코드는 아래와 같이 작성한다. 

def func():
    # module을 import할 때 실행됨
    pass


if __name__ == "__main__":
    # module을 import할 때 실행 안 됨
    pass

.pyc

.pyc 파일은 컴파일러가 사용하는 바이트 컴파일 코드가 작성된 파일이다. 파이썬 코드(.py)는 PVM(Python Virtual Machine)이 이해할 수 있는 바이트 코드 형태로 컴파일한 후, PVM에서 실행된다. 이때 컴파일된 코드를 pyc에 저장하면 재실행할 때 컴파일하는 과정을 생략해 빠르게 실행할 수 있다. (파이썬 3.4이하는 .pyo를 사용한다.)

.py 파일을 import 하게 되면 py가 pyc로 저장된다. __pycache__ 파일이 생성되고, "파일 이름. cpython-버전. pyc" 형태로 파일이 저장된다. 만약 수동으로 pyc 파일을 생성하려면 아래 코드를 사용할 수 있다.

import py_compile

py_compile.compile("파일이름.py")

pickle

피클링(pickling)은 파이썬 객체를 문자열이 아닌 파이썬이 이해할 수 있는 문자열 표현(representaion)으로 저장한다. pkl파일을 다룰 때는 바이너리 모드로 읽고 써야 한다. 

import pickle

var = {}

with open("filename.pkl", "wb") as f:
    # 피클링: 파일 저장
    pickle.dump(var, f)

with open("filename.pkl", "rb") as f:
    # 언피클링: 파일 읽기
    var = pickle.load(f)

pkl로 객체를 저장하면 txt 파일을 사용하는 것보다 빠르다. 


struct

C언어의 자료형을 파이썬에서 사용할 수 있다. struct는 이진 표현으로 된 바이트 객체를 뜻한다. (자세한 내용은 struct 문서를 참고.)

import struct

var = struct.pack(">hl", 1, 2)
# 파이썬 객체를 struct 형식으로 변환
print(f"struct: {var}")

unpacked = struct.unpack(">hl", var)
# struct 형식을 파이썬 객체로 변환
print(f"unpack struct: {unpacked}")

length = struct.calcsize(">hl")
# 차지할 바이트 수 측정
print(f"Expected length: {length}")


>>> struct: b'\x00\x01\x00\x00\x00\x02'
>>> unpack struct: (1, 2)
>>> Expected length: 6