자택경비대

MacOS Mojave 10.14 이상에서 pygame이 정상적으로 작동하지 않는 문제 해결방법

Programming

간단하게 설치하는 아래와 같은 방식으로는 예제 프로그램을 실행해보면 정상적으로 작동되지 않는다.
(화면이 검게 혹은 노이즈가 낀 화면으로 보이거나, 아예 화면이 보이지 않거나, 스프라이트가 깨지거나 보이지 않는 문제 등)


pip install pygame

python -m pygame.examples.aliens  # 비정상적 작동

아래와 같이 버전을 지정해주면 정상적으로 작동하는것을 확인할 수 있다.


pip install 'pygame==2.0.0.dev3'

Python scrapy 사용법

Programming

개요

기본적으로 scrapy crawler의 조작은 scrapy 명령어를 통해 이루어진다.

scrapy는 해당 모듈을 global이 아닌 virtualenv등을 이용하여 프로젝트 단위로 관리하는 것을 권장한다.

Spider class?

CrawlerRule, 즉 규칙을 구체화 시킬 수 있도록 만든 클래스이다. 디자인 패턴에서는 Template Method Pattern과 같이 scrapy.Spider 클래스 자체로는 특별한 일을 하지 않지만, 크롤러의 행동을 정의해 놓았기 때문에 이를 상속된 하위 클래스에서 구현해주는 패턴으로 생각하면 될 것 같다.

하위 클래스에서는 기본적으로 scrapy.Spider 클래스를 상속받도록 구현해야 한다. 흐름은 start_requests 함수에서 반환된 scrapy.Request객체를 시작으로, 각 응답 scrapy.http.Responsecallback 매개변수의 인자로서 넘겨주게 된다.
start_requests는 일련의 scrapy.Request객체들을 반환하는데, 이는 start_urls라는 URL을 모은 list타입의 Property로 대체할 수 있다. (이 때는, scarpy.Request처럼 callback 지정이 없기 때문의 자동으로 self.parsecallback으로 사용한다.)
callback 매개변수는 보통 parse 함수를 지정하게 되는데, 여기서 받아온 응답에 대한 처리를 진행하게 된다.
callback에서 인자로 받은 응답 값을 처리하여 직접 파일로 저장하게 하거나, 반환하여 scrapy에서 처리하도록 할 수 있다.
parse에서 반환된 객체들은 결과물로서 scrapy 옵션에 따라 파일에 저장되거나 stdout 으로 출력되게 할 수 있다.
parse 함수 또한 scrapy.Request객체를 돌려주도록 할 수 있는데, 이 경우 다시 start_requests로 흐름이 넘어가 응답을 받아오게 된다.
따라서 파싱 된 결과물에서 다음페이지로 이동 등의 링크를 추출하여 다시 start_requests로 넘겨주는 것이 가능하게 된다. 이 때는 보통 response.follow라는 축약 명령을 사용해서 가독성을 높이고, 불필요한 타이핑도 줄일 수 있다.

scrapy command

scrapy 프로젝트 생성하기
scrapy startproject [project_name]

구현한 spider를 실행
scrapy crawl [spider_name]

특정 URL의 spider구현을 위한 interactive 모드
scrapy shell [URL]

scrapy.Spider를 상속하는 템플릿 코드 생성
scrapy genspider [spider_name] [URL]

spider의 목록을 출력
scrapy list

파이썬의 GIL(Global Interpreter Lock)

Programming

GIL(Global Interpreter Lock)의 존재 이유

멀티스레딩 환경에서 CPython의 경우 메모리 관리목적으로 reference count를 측정하는데, 이때 race condition이 일어나서 메모리 누수가 일어나거나, 사용중인 객체의 해제등의 치명적인 문제가 발생할 수 있기 때문에 각 객체에 락을 거는 방안을 생각했으나, 이 또한 동시에 여러개의 객체에 락이 걸리게 되면서 데드락의 문제가 발생할 수 있어, 파이썬 바이트코드 단위에 락을 걸어 두가지의 문제를 해결 할 수 있지만 한편으로는 이로 인해서 싱글 스레드로 동작할 수 밖에 없는 환경이 만들어지게 되었다.

GIL이 최선의 방안이었을까? 혹은, 단순히 파이썬 개발진의 잘못된 선택은 아니었을까?

역설적으로 GIL로 인해서 파이썬이 추구하던 쉽고 빠른 개발의 디자인을 완성할 수 있게 되었다. C로 작성된 많은 확장 프로그램들이 파이썬으로 옮겨질때 양측의 조화를 위해 thread-safe한 메모리의 제공이 필요했는데 GIL이 이 역할에 제격이었던 것이다. 이로써 thread-safe하지 않은 C 프로그램들이 python으로 쉽게 확장 될 수 있었다.

Reference

'Programming' 카테고리의 다른 글

XPath 사용방법  (0) 2020.04.21
Python scrapy 사용법  (0) 2020.04.21
pre-emptive multitasking vs cooperative multitasking  (0) 2020.04.12
Python2 pwntools SyntaxError: invalid syntax 해결방법.  (0) 2020.04.03
Bash 매개변수 확장  (0) 2020.03.31

pre-emptive multitasking vs cooperative multitasking

Programming
  • pre-emptive multitasking (i.e. threading)

    • 운영체제가 언제든지 태스크에 개입하여 switch 가능
    • 시간기반으로 스케줄러에 의해 관리됨"
  • copperative multitasking (i.e. asyncio)

    • 코드 상에서 어디에서 태스크가 끝나고 switching이 되는지 조절 가능
    • 프로세스가 자발적으로 주도권을 양보한다

Python2 pwntools SyntaxError: invalid syntax 해결방법.

Programming
...
pygments/formatters/html.py", line 554
    file=sys.stderr)
SyntaxError: invalid syntax

Pygments 패키지가 2.6 버전부터 python2 지원을 중단하면서 발생한 문제다.

아래와 같이 pwntools 제거 후 Pygments 다운그레이드를 진행하고 재설치 하면 된다.

sudo pip uninstall pwntools
sudo pip install 'pygments==2.5.1'
sudo pip install pwntools

파이썬 argparse 모듈에서 버전 옵션과 필수 옵션 혼용하는법

Programming

Pythonargparse모듈은 Cgetopt.h 처럼 명령 인자를 받아서 옵션으로 해석할 수 있도록 돕는 모듈이다.

기본적인 사용방법은 다음과 같다.


import argparse



parser = argparse.ArgumentParser()

parser.add_argument('--foo')

args = parser.parse_args()

문제는, --version 같은 옵션은 별 다른 옵션 없이 progname --version 형태로 전달하게 되면 일반적으로 정상적으로 버전을 출력하고 끝나는데, 항상 요구되는 Required 인자, 혹은 옵션이 전달되지 않은 경우 에러를 발생시키는 Positional argument와 함께 사용하려하면 --version 옵션을 붙이고도 다른 요구사항을 만족시키지 못해 에러를 발생시키게 된다.


import argparse



parser = argparse.ArgumentParser()

parser.add_argument('foo')  # `foo` 가 제공되지 않으면 에러가 발생한다.

parser.add_argument('--version')

args = parser.parse_args()  # 다음의 `version` 옵션 체크 이전에 에러가 발생하기 때문에 버전이 정상적으로 출력되지 못한다.

if args.version:

    print(__version__)

이런 경우의 해결 방법은 action 어트리뷰트를 action='version' 으로 설정하고, version=__version__ 처럼 version 어트리뷰트를 추가로 지정해주면 위와 같은 상황에서 에러를 발생시키지 않고, 버전을 정상 출력 한 뒤, 종료된다.


import argparse



parser = argparse.ArgumentParser()

parser.add_argument('foo')

parser.add_argument('--version', action='version', version=__version__)

args = parser.parse_args()  # "1.0.0"

# 아래 옵션 검사, 버전 출력 구문은 더 이상 필요없다

# if args.version:

#    print(__version__)

Python timeit 모듈 사용법 (성능 측정)

Programming
# 기본적인 사용법
# import timeit
# timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
#
# stmt: 성능을 측정할 코드를 뜻한다.
#         '''code''', """code""" 등의 멀티라인 스트링을 이용해서 작성할 수도 있다.
# e.g.)
# >>> timeit('''\
# ... for i in range(100):
# ...     n += i
# ... ''', setup='n=0')
#
# setup: 측정 전 필요한 코드를 나타낸다. 유닛 테스트의 setup, teardown 과 같은 개념이라고 봐도 무방하다.
# timer: 측정에 사용할 타이머 함수를 지정한다. 이는 파이썬을 실행하는 플랫폼에 따라 달라질 수 있다.
# number: 테스트를 몇 번 시행할 지 나타낸다.

>>> from timeit import timeit
>>> timeit('"number is " + str(n)', setup='n=123')
0.26701879501342773
>>> timeit('"number is %d" % (n,)', setup='n=123')
0.6445150375366211