CHAPTER 04

구조와 모듈

모듈

제어문

파일 처리

오류처리

4.1 모듈


파이썬에서 모듈(module)은 def를 사용하여 정의한다. def가 실행되면, 함수의 객체와 참조가 같이 생성된다.</br>

반환값을 정의하지 않으면, 파이썬은 자동으로 None을 반환한다. C언어와 마찬가지로, 아무런 값을 반환하지 않는 함수는 프로시저(procedure)라고 부른다.</br>


4.1.1 스택과 활성화 레코드

함수가 호출될 때마다 활성화 레코드(activation record)가 생성된다. 활성화 레코드에는 함수의 정보(반환값, 매개변수, 지역 변수, 반환값, 반환 주소 등)가 기록되며, 이를 스택(stack1)에 저장한다. 활성화 레코드는 다음과 같은 순서로 처리된다.

  1. 함수의 실제 매개변수를 스택에 저장(push)한다.
  2. 반환 주소를 스택에 저장한다.
  3. 스택의 최상위 인덱스를 함수의 지역 변수에 필요한 총량만큼 늘린다.
  4. 함수로 건너뛴다.(jump)

활성화 레코드를 풀어내는 unwinding 절차는 다음과 같다.

  1. 스택의 최상위 인덱스는 함수에 소비된 총 메모리양(지역 변수)만큼 감소한다.
  2. 반환 주소를 스택에서 빼낸다.(pop)
  3. 스택의 최상위 인덱스는 함수의 실제 매개변수만큼 감소한다.

4.1.2 모듈의 기본값

모듈을 생성할 때, 함수 또는 메서드에서 가변 객체를 기본값으로 사용해선 안된다. 나쁜 예와 좋은 예를 살펴보자. 먼저 나쁜예다.


  1. 역자주 여기서는 콜 스택, 실행 스택, 제어 스택, 런타임 스택, 기계 스택 등의 맥락에 해당하는 스택을 말한다. 주로 현재 실행중인 서브루틴을 실행한 다음 어디로 돌아가야할지등을 저장하는 데 쓰인다.(https://ko.wikipedia.org/wiki/콜_스택 참조)

코드

def append(number,number_list=[]):
    number_list.append(number)
    return number_list

print("예상결과[5]",append(5)) 
print("예상결과[5,2]",append(7)) 
print("예상결과[5,2,7]",append(2)) 

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py
예상결과[5] [5]
예상결과[5,2] [5, 7]
예상결과[5,2,7] [5, 7, 2]

좋은 예는 다음과 같다. 초기화 로직을 넣었다.

코드

# def append(number,number_list=[]):#     number_list.append(number)#     return number_list# print("예상결과[5]",append(5)) # print("예상결과[5,2]",append(7)) # print("예상결과[5,2,7]",append(2)) def append(number,number_list=None):    if number_list is None:        number_list = []    number_list.append(number)    return number_listprint("append[5]",append(5))print("append[7]",append(7))print("append[2]",append(2))

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.pyappend[5] [5]append[7] [7]append[2] [2]

4.1.3 __\__init\__.py 파일

패키지(package)는 모듈과 \__init\__.py 파일이 있는 디렉터리다. 파이썬은 \__init\__.py 파일이 있는 디렉터리를 패키지로 취급한다. 모듈 검색 경로 중 string과 같이 흔한 이름의 디렉터리에 유효한 모듈이 들어 있는 경우 이러한 모듈이 검색되지 않는 문제를 방지하기 위해서다.

import 폴더이름.파일모듈명

__\____init\___.py 파일은 빈 파일일 수도 있지만, 패키지의 초기화 코드를 실행하거나, \____all\__ 변수를 정의할 수도 있다.

__all__ = ["파일",....]

실제 파일 이름은 확장자가 .py겠지만, 여기서 작성할 때는 .py를 붙이지 않는다. 다음 명령문을 살펴보자.

from 폴더이름 import *

위 코드는 이름이 __\__ __로 시작하는 모듈을 제외한 모듈의 모든 객체를 불러온다. \____all\___ 변수가 있는 경우, 해당 리스트의 객체를 불러온다.

터미널에서 특정 모듈이 있는지 간단하게 확인하려면, **python -c import 모듈** 명령을 사용하면된다.

PS D:\Mastering-Python-Design-Patterns-Second-Edition> python -c "import astin"Traceback (most recent call last):  File "<string>", line 1, in <module>      ModuleNotFoundError: No module named 'astin'

4.1.4 \___name\___ 변수

파이썬은 모듈을 임포트(import) 할 때마다 __\__name\__이라는 변수를 만들고, 모듈 이름을 저장한다. 이해를 돕기 위해 다음과 같이 hello.py 파일을 저장한 후 , 그 위치에서 대화식 인터프리터를 실행하여 hello 모듈을 임포트해보자.

hello = "hello"def world():    return "World"if __name__ == "__main__":    print("{0} 직접 실행됨".format(__name__))else:    print("{0} 임포트됨".format(__name__))    
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit (Intel)] on win32Type "help", "copyright", "credits" or "license" for more information.>>> import hellohello 임포트됨>>> hello.hello'hello'>>>    >>> hello.world()'World'>>> __name__'__main__'

대화식 인터프리터 또는 .py파일을 직접 실행하면 파이썬은 _\__name_\__\__main\__ 으로 설정하므로, 위 코드 조건문에서 참에 해당하는 코드를 실행한다. 이번에는 hello.py를 직접 실행해보자. 차이를 알 수 있을 것이다.

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\hello.py__main__ 직접 실행됨

4.1.5 컴파일된 바이트코드 모듈

컴파일러가 사용하는 바이트 컴파일 코드(byte-complied code)는 표준 모듈을 많이 사용하는 프로그램의 시작시간(로딩 시간)을 줄이기 위한것이다. -0 플래그를 사용하여 파이썬 인터프리터를 호출하면, 최적화된 코드가 생성되어 .pyo파일에 저장된다. (최적화 과정에서 assert문은 제거된다. 파이썬 3.5부터는 .pyo대신 .pyc를 사용한다. 이렇게 만든 파일은 리버스 엔지니어링이 까다로우므로 라이브러리로 배포하는 데에도 사용할 수 있다. 파이썬 플래그에 대한 정보를 확인하고 싶다면 다음과같이 --help를 붙여 파이썬을 실행해보자.)

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python --helpusage: C:\Program Files (x86)\Python37-32\python.exe [option] ... [-c cmd | -m mod | file | -] [arg] ...Options and arguments (and corresponding environment variables):-b     : issue warnings about str(bytes_instance), str(bytearray_instance)         and comparing bytes/bytearray with str. (-bb: issue errors)-B     : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x-c cmd : program passed in as string (terminates option list)-d     : debug output from parser; also PYTHONDEBUG=x-E     : ignore PYTHON* environment variables (such as PYTHONPATH)-h     : print this help message and exit (also --help)-i     : inspect interactively after running script; forces a prompt even         if stdin does not appear to be a terminal; also PYTHONINSPECT=x-I     : isolate Python from the user's environment (implies -E and -s)-m mod : run library module as a script (terminates option list)-O     : remove assert and __debug__-dependent statements; add .opt-1 before         .pyc extension; also PYTHONOPTIMIZE=x-OO    : do -O changes and also discard docstrings; add .opt-2 before         .pyc extension-q     : don't print version and copyright messages on interactive startup-s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE-S     : don't imply 'import site' on initialization-u     : force the stdout and stderr streams to be unbuffered;         this option has no effect on stdin; also PYTHONUNBUFFERED=x-v     : verbose (trace import statements); also PYTHONVERBOSE=x         can be supplied multiple times to increase verbosity-V     : print the Python version number and exit (also --version)         when given twice, print more information about the build-W arg : warning control; arg is action:message:category:module:lineno         also PYTHONWARNINGS=arg-x     : skip first line of source, allowing use of non-Unix forms of #!cmd-X opt : set implementation-specific option--check-hash-based-pycs always|default|never:    control how Python invalidates hash-based .pyc filesfile   : program read from script file-      : program read from stdin (default; interactive mode if a tty)arg ...: arguments passed to program in sys.argv[1:]Other environment variables:PYTHONSTARTUP: file executed on interactive startup (no default)PYTHONPATH   : ';'-separated list of directories prefixed to the               default module search path.  The result is sys.path.PYTHONHOME   : alternate <prefix> directory (or <prefix>;<exec_prefix>).               The default module search path uses <prefix>\python{major}{minor}.PYTHONCASEOK : ignore case in 'import' statements (Windows).PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.PYTHONHASHSEED: if this variable is set to 'random', a random value is used   to seed the hashes of str, bytes and datetime objects.  It can also be   set to an integer in the range [0,4294967295] to get hash values with a   predictable seed.PYTHONMALLOC: set the Python memory allocators and/or install debug hooks   on Python memory allocators. Use PYTHONMALLOC=debug to install debug   hooks.PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale   coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of   locale coercion and locale compatibility warnings on stderr.PYTHONBREAKPOINT: if this variable is set to 0, it disables the default   debugger. It can be set to the callable of your debugger of choice.PYTHONDEVMODE: enable the development mode.

4.1.6 sys 모듈

sys.path는 인터프리터가 모듈을 검색할 경로를 담은 문자열 리스트다. sys.path 변수는 PYTHONPATH 환경변수 또는 내장된 기본값 경로로 초기화된다. 환경변수를 수정하면 모듈 경로를 추가하거나 임시로 모듈 경로를 추가할 수 있다.

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit (Intel)] on win32Type "help", "copyright", "credits" or "license" for more information.>>> import sys>>> sys.path['', 'C:\\Program Files (x86)\\Python37-32\\python37.zip', 'C:\\Program Files (x86)\\Python37-32\\DLLs', 'C:\\Program Files (x86)\\Python37-32\\lib', 'C:\\Program Files (x86)\\Python37-32', 'C:\\Users\\smart\\AppData\\Roaming\\Python\\Python37\\site-packages', 'C:\\Program Files (x86)\\Python37-32\\lib\\site-packages']

sys.ps1과 sys.ps2 변수는 파이썬 대화식 인터프리터의 기본 및 보조 프롬프트(prompt) 문자열을 정의한다.(기본 값은 각각 >>> 및 ...이다.).

이미 앞에서도 사용했지만, sys.argv 변수를 사용하면 명령 줄에 전달된 인수를 프로그램 내에서 사용할 수 있다.

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py 로미오 줄리엣 로미오줄리엣

dir() 내장 함수는 모듈이 정의하는 모든 유형의 이름(모듈, 변수, 함수)을 찾는 데 사용된다. 이름 기준으로 정렬된 문자열 리스트를 반환한다.

>>> import sys>>> dir (sys)['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_base_executable', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']

dir()함수는 내장 함수 및 변수의 이름까지는 나열하지 않는다. 객체의 모든 메서드나 속성을 찾는 데 유용하다.

4.2 제어문

4.2.1 if문

파이썬 if문은 다른 언어의 switch문 또는 case문을 대체한다. 다음 예제를 살펴보자.

x = int(input("숫자를 입력하세요:"))if x < 0:    x =0     print("음수를 입력하여 x를 0으로 변경했습니다.")elif x == 0:    print("0이 입력되었습니다.")elif x == 1:    print("1이 입력되었습니다.")else:    print("2이상의 숫자가 입력되었습니다.")

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py숫자를 입력하세요:11이 입력되었습니다.

4.2.2 for문

파이썬 for문은 C나 파스칼 언어와 다르다. 파스칼처럼 숫자의 산술 진행을 반복하거나, C처럼 사용자가 반복 단계와 조건을 모두 정의할 수 있도록 하는 대신, 파이썬의 모든 for문은 모든 시퀸스 항목(리스트, 문자열 등)을 순서대로 순회한다.

for name in names:    print(name)

4.2.3 참과 거짓

거짓(False)는 사전 정의된 상수 False 또는 숫자 0, 특수 객체 None, 빈 컬렉션 시퀸스(빈 문자열 '', 빈 리스트[], 빈 튜플() , 빈 딕셔너리{}에 의해 정의된다. 여기에 속하지 않은 값은 모두 참(True)이다.) 비교 또는 다른 불리언 표현식의 결과를 변수에 할당할 수 있다.

>>> string1, string2, string3 = '', '괴물', '외계인'>>> non_null = string1 or string2 or string3>>> non_null'괴물'>>> non_null'괴물'>>> non_null'괴물'>>> non_null'괴물'>>> non_null'괴물'>>> non_null'괴물'

구글 파이썬 스타일 가이드에서는 암묵적인(implicit) False 사용에 대해 다음과 같은 기준을 세워뒀다.

  • == 또는 != 연산자를 사용하여 내장 변수 None 같은 싱글턴(singleton)을 비교하지 않는다. 대신 is 또는 is not을 사용한다.
  • if x is not None과 if x 를 잘 구분해서 사용한다.
  • ==를 사용하여 불리언 변수를 False와 비교하지 않는다. 대신 if not x를 사용한다. None과 False를 구별할 필요가 있는 경우, if not x and x is not None과 같은 연결 표현식을 사용한다.
  • 시퀸스(문자열,리스트,튜플)의 경우, 빈 시퀸스는 False다. if len(시퀸스) 또는 if not len(시퀸스)보다는 if not 시퀸스 또는 if 시퀸스를 사용하는 것이 좋다.
  • 정수를 처리할 때 뜻하지 않게 None을 0으로 잘못 처리하는 것처럼 , 암묵적 False를 사용하는 것은 위험하다.

좋은 예와 나쁜 예를 살펴보겠다. 먼저 좋은 예다.

if not users:    print("사용자가 없습니다.")if foo ==0:    handle_zero()if i % 10 == 0:    handle_multiple_of_ten()

다음은 나쁜 예다.

if len(users) == 0:    print("사용자가 없습니다.")if foo is not None and not foo:    handle_zero()if not i % 10:    handle_multiple_of_ten()

4.2.4 return 대 yield

파이썬에서 제너레이터(**generator**)는 이터레이터(**iterator**)를 작성하는 편리한 방법이다. 객체에 \___iter_\___() 와 \___next\___() 메서드를 둘 다 정의하면 이터레이터 프로토콜을 구현한 셈이다. 이 때 yield 키워드를 사용하면 편리하다.

호출자가 메서드를 호출할 떄, return 키워드는 반환값을 반환하고 메서드를 종료한 후, 호출자에게 제어를 반환한다. 반면 yield 키워드는 각 반환값을 호출자에게 반환하고, 반환값이 모두 소진되었을 때에만 메서드가 종료된다.

이터레이터는 파이썬의 강력한 기능이다. 이터레이터는 이터레이터 프로토콜을 구현하는 컨테이너 객체라고 할 수 있는데, 컨테이너의 다음 값을 반환하는 \___next\___() 메서드와 이터레이터 자신을 반환하는 \___iter\___() 메서드를 기반으로 한다.

yield 키워드는 제너레이터 맥락에서 이터레이터를 만드는 아주 강력한 도구다. 제너레이터는 최종값을 반환하지만, 이터레이터는 yield 키워드를 사용하여 코드 실행 중에 값을 반환한다. 즉, \__next\___()메서드를 호출할 때마다 어떤 값 하나를 추출한 후 해당 yield 표현식의 값을 반환한다. 이렇게 이터레이터는 StopIteration 예외가 발생할 때까지 값을 반환한다.

a = [1,2,3]def f(a):    while a:        print("a.pop()",a.pop())        yield a.pop()

 

제너레이터는 매우 강력하고 효율적이다. 시퀸스를 반환하거나 반복문을 사용하는 함수를 다룰 때, 제너레이터를 고려할 수 있다. 다음 코드는 이터레이터를 사용하여 피보나치 수열을 구현한다.(출력 부분을 빼면 "1.7.4 피보나치 수열"에서 살펴봤던 코드와 같다.)

def fib_generator():    a,b = 0,1    while True:        yield b        a, b = b, a+bif __name__ == "__main__":    fib = fib_generator()    print(next(fib))    print(next(fib))    print(next(fib))    print(next(fib))    print(next(fib))    print(next(fib))    print(next(fib))

출력 결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py11235813

4.2.5 break 대 continue

반복문 (for 또는 while)에서 break 키워드를 만나면, 바로 반복문을 빠져나간다. 반복문에서 continue 키워드를 만나면, 반복문의 다음 단계로 전환한다. (반복문의 다음 반복을 계속한다.)

반복문에는 else 절을 사용할 수 있는데, 이는 반복문이 종료되었을 때(for문에서 리스트의 항목을 모두 순회했거나, while문에서 False가 되었을 때 실행된다. 다만 break문으로 반복문이 종료되는 경우에는 실행되지 않는다.)

코드

for i in range(10):    if i == 4:        break    print(i)else:    print("for 문 종료")

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py0123

코드

for i in range(10):    if i % 2 ==0:        continue    print(i)else:    print("for 문 종료!")

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.py13579for 문 종료!

4.2.6 range()

range()메서드는 숫자 리스트를 생성한다. 숫자 시퀸스를 순회할 떄 유용하다.

a = range(10)b = range(4,10)c = range(0,10,3)print("a",a)print("b",b)print("c",c)

결과

a range(0, 10)b range(4, 10)c range(0, 10, 3)

4.2.7 enumerate()

enumerate() 메서드는 반복 가능한 객체의 인덱스 값과 항목 값의 튜플을 반환한다. 예를 들어 파일을 가져와서 특정 단어가 나타나는 위치를 출력하는 나만의 **grep** 함수를 만들 수 있다. 명령 줄에서 실행 시 단어와 파일을 모두 지정해야 한다.

import sysdef grep_word_from_files():    word = sys.argv[1]    for filename in sys.argv[2:]:        with open(filename) as file:            for lino, line in enumerate(file,start=1):                if word in line:                    print("{0}:{1}:{2:.40}".format(                        filename, lino, line.rstrip()))if __name__ == "__main__":    if len(sys.argv) < 2:        print("Usage: python {0} [word] [file ...]".format(sys.argv[0]))        sys.exit()    else:        grep_word_from_files()

결과

PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\3_grep_word_from_files.py  for  .\3_grep_word_from_files.py.\3_grep_word_from_files.py:5:    for filename in sys.argv[2:]:.\3_grep_word_from_files.py:7:            for lino, line in enumerate( .\3_grep_word_from_files.py:9:                    print("{0}:{1}:{2:.4 .\3_grep_word_from_files.py:15:        print("Usage: python {0} [word] 

4.2.8 zip()

zip()메서드는 2개 이상의 시퀸스를 인수로 취하여, 짧은 길이의 시퀸스를 기준으로 각 항목이 순서대로 1:1 대응하는 새로운 튜플 시퀸스를 만든다.

>>> a = [1,2,3,4,5]>>> b = ['a','b','c','d']>>> zip(a,b)<zip object at 0x02333FA8>>>> list(zip(a,b))[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

4.2.10 map()

map(function, list) 메서드는 시퀸스의 모든 항목에 함수를 적용한 결과 리스트를 반환한다.

def cube(x): return x*x*xprint("a: ",list(map(cube,range(1,11))))seq = range(8)def square(x): return x*xprint("b:" ,list(zip(seq,map(square,seq))))

4.2.11 람다 함수

**람다(lambda)** 함수를 쓰면 코드 내에서 함수를 간결하게(compact) 동적으로 사용할 수 있다. 아래의 예제 코드를 살펴보자.

def area(b,h):    return 0.5 * b * hprint("Area",area(5,4))area2= lambda b,  h : 0.5 * b *hprint("Area2",area2(5,4))
PS D:\Mastering-Python-Design-Patterns-Second-Edition\algo\module_structure> python .\test.pyArea 10.0Area2 10.0

람다 함수는 defaultdict에서 키 생성 시 매우 유용하다.(누락된 키에 대한 기본 값 설정 시).

코드

import collections minus_one_dict = collections.defaultdict(lambda:-1)point_zero_dict =  collections.defaultdict(lambda: (0,0))message_dict = collections.defaultdict(lambda:"No message")print("minus_one_dict",minus_one_dict)print("point_zero_dict",point_zero_dict)print("message_dict",message_dict)

결과

minus_one_dict defaultdict(<function <lambda> at 0x01C208E8>, {})point_zero_dict defaultdict(<function <lambda> at 0x021AF390>, {})message_dict defaultdict(<function <lambda> at 0x021AF468>, {})   

4.3 파일 처리


파이썬에서 파일 처리는 매우 쉽고 편하다. 파일을 읽어서 모든 빈 줄을 제거하는 코드를 살펴보자.

from os import remove
import sys

def read_data(filename):
    lines = []
    fh = None
    try:
        fh = open(filename)
        for line in fh:
            if line.strip():
                lines.append(line)
    except (IOError,OSError) as err:
        print(err)
    finally:
        if fh is not None:
            fh.close()
    return lines

def write_data(lines,filename):
    fh = None
    try:
        fh = open(filename,"w")
        for line in lines:
            fh.write(line)
    except (EnvironmentError) as err:
        print(err)
    finally:
        if fh is not None:
            fh.close()

def remove_blank_lines():
    if len(sys.argv) < 2:
        print("Usage python {0} [file ...]".format(sys.argv[0]))
    
    for filename in sys.argv[1:]:
        lines = read_data(filename)
        if lines:
            write_data(lines,filename)

if __name__ == "__main__":
    remove_blank_lines()

빈 줄 제거 전 내용을 확인해보자. 사용할 파일은 "4.1.4 __name__ 변수"에서 작성한 hello.py다.

hello = "hello"

def world():
    return "World"

if __name__ == "__main__":
    print("{0} 직접 실행됨".format(__name__))
else:
    print("{0} 임포트됨".format(__name__))

빈 줄을 제거한 결과는 다음과 같다.

root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure# python3.6 4_remove_blank_lines.py  hello.py
root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure# cat hello.py
hello = "hello"
def world():
    return "World"
if __name__ == "__main__":
    print("{0} 직접 실행됨".format(__name__))
else:
    print("{0} 임포트됨".format(__name__))root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure#

코드에서 쓰인 함수

strip([chars]) : 인자로 전달된 문자를 String의 왼쪽과 오른쪽에서 제거합니다.lstrip([chars]) : 인자로 전달된 문자를 String의 왼쪽에서 제거합니다.rstrip([chars]) : 인자로 전달된 문자를 String의 오른쪽에서 제거합니다.아래는 write 함수를 쓸경우 파일에서 쓰기가 실행된다.# writedata.pyf = open("C:/doit/새파일.txt", 'w')for i in range(1, 11):    data = "%d번째 줄입니다.\n" % i    f.write(data)f.close()

다음과 같이 with문을 사용할 수도 있다. 명시적으로 close()로 연 파일을 닫지 않아도 되므로 더 선호되기도 한다,

import sysdef read_data(filename):    lines = []    with open(filename) as fh:        for line in fh:            if line.strip():                lines.append(line)        return linesdef write_data(lines, filename):    fh =None    with open(filename, "w") as fh:        for line in lines:            fh.write(line)def remove_blank_lines():    if len(sys.argv) < 2:        print("Usage: python {0} [file ...]".format(sys.argv[0]))    for filename in sys.argv[1:]:        lines = read_data(filename)        if lines:            write_data(lines, filename)if __name__ == "__main__":    remove_blank_lines()    

실행결과

root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure# cat hello.py hello = "hello"   def world():          return "World"if __name__ == "__main__":    print("{0} 직접 실행됨".format(__name__))else:    print("{0} 임포트됨".format(__name__))

4.3.1 파일 처리 메서드

**open()**

open(filename,mode,encoding) 메서드는 파일 객체를 반환한다. 모드와 인코딩 인수는 옵션이며, 생략하면 텍스트 읽기 모드와 시스템 기본형식 인코딩이 적용된다. 모드는 문자열로 지정하며 종류는 다음과 같다.

r: 읽기모드

w: 쓰기모드 (동명파일이 이미 있다면, 그 파일을 지운 후 내용을 새로 쓴다.)

a: 추가모드(동명 파일이 있다면 그 파일끝에 내용을 추가한다.)

r+:읽기와 쓰기 모드

t: 텍스트 모드

b:바이너리 모드

fin = open(filename,encoding="utf8")fout = open(filename, "w", encoding="utf8")

read(size) : 메서드는 파일에서 size만큼의 내용을 읽고 문자열을 반환한다. readline() : 파일에서 한줄을 읽는다. readlines() : 파일의 모든 데이터 행을 포함한 리스트를 반환한다. write() : 데이터를 파일에쓰고,None을 반환한다. tell(), seek() : tell()메서드는 파일의 현재 위치를 나타내는 정수를 반환한다. close() : 파일을 닫고, 열린 파일이 차지하는 시스템 자원을 해제한다. 파일을 성공적으로 닫으면 True를 반환한다. input() : 함수는 사용자의 입력을 받는다. peek() 메서드는 파일 포인터 위치를 이동하지 않고, n바이트를 반환한다. fileno() 파일 서술자를 반환한다.(파일 서술자를 가진 파일 객체에서만 사용 가능하다.)

4.3.2 shutil 모듈

shutil 모듈은 시스템에서 파일을 조작할 때 유용하다. 다음 코드는 터미널에서 파일 및 확장자를 지정하면 새 확장자의 이름으로 복사본을 만든다.

import os
import sys
import shutil

"""
root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure# python3.6 6_change_ext_file.py hello.py txt
hello.txt
"""

def change_file_ext():
    if len(sys.argv) < 2:
        print("Usage: python {0} filename.old_ext 'new_ext'".format(sys.argv[0]))
        sys.exit()

    name = os.path.splitext(sys.argv[1])[0] + "." + sys.argv[2]
    print(name)

    try:
        shutil.copyfile(sys.argv[1],name)
    except OSError as err:
        print(err)

if __name__ == "__main__":
    change_file_ext()

결과

root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo/module_structure# cat hello.txt 

hello = "hello"
def world():
    return "World"
if __name__ == "__main__":
    print("{0} 직접 실행됨".format(__name__))
else:
    print("{0} 임포트됨".format(__name__))

+ Recent posts