'분류 전체보기'에 해당되는 글 590건

  1. 2013.05.12 vim Regular Expression
  2. 2013.05.12 구간 지정
  3. 2013.05.12 반복 찾기(+, *) 와 '?' 메타 문자
  4. 2013.05.12 포직스(POSIX) 문자 클래스
  5. 2013.05.12 Multithread Process
  6. 2013.05.09 발생자(Generator)
  7. 2013.05.09 반복자(Iterator)
  8. 2013.05.08 xargs, find 명령어

vim Regular Expression

Vim/Tutorial 2013. 5. 12. 23:32 |


일반적인 정규 표현식(Regular Expression) 이랑 vim 에서 쓰이는 정규 표현식이랑 약간 다른 점이 있다. 

그 중에 가장 크게 다른 점만을 설명하겠다. 


일반적인 정규 표현식에서 탐욕적(greedy) 수량자와 게으른(lazy) 수량자가 있다. 

문법은 이렇게 탐욕적 수량자 뒤에 '?' 를 붙이면 된다. 

하지만 vim에서는 완전히 다른 문법이다. 



Regular Expression

vim Built-in Regular Expression 

  * (0 or more)

 greedy matching 

 * (0 or more) 

 greedy matching 

 + (1 or more) 

 greedy matching 

 \+ (1 or more) 

 greedy matching 

 *? (0 or more) 

 non-greedy matching 

 \{-} (0 or more)

 non-greedy matching 

 +? (1 or more)

 non-greedy matching  

 \{-n,} (1 or more)

 non-greedy matching 





'Vim > Tutorial' 카테고리의 다른 글

vim regular expression  (0) 2016.02.28
C++ code completion  (0) 2016.02.27
프로그래밍할 때 유용한 기능  (0) 2013.02.06
반복적인 작업 녹화하기  (0) 2013.02.06
자동화  (0) 2013.02.05
Posted by scii
:

구간 지정

Programming/RegEx 2013. 5. 12. 21:46 |


구간 지정하기

더하기, 별표, 물음표는 정규 표현식을 쓰면서 발생하는 많은 문제를 해결해 주지만, 충분하지 않을 때도 있다. 다음과 같은 상황을 생각해 보자.

# 더하기와 별표는 일치하는 문자 수에 제한이 없다. 문자가 최대 몇 개까지 일치하는지 정할 수 없다.

# 더하기, 별표, 물음표가 일치하는 문자 수의 최솟값을 0이나 1이다. 일치하는 문자 수의 최솟값을 명시적으로 정의할 수 없다.

# 정확히 원하는 만큼만 일치하도록 문자 수를 정의할 수 없다.


이런 문제들을 해결하고, 연속하는 문자를 찾을 때 검색 조건을 더 구체적으로 지정하고자 정규 표현식에서는 구간을 사용한다.

구간은 중괄호([]) 안에 표시한다.



정확한 구간 찾기

문자가 일치하는 수를 정확히 정하려면 여는 중괄호와 닫는 중괄호 사이에 숫자를 넣는다. 즉 {3} 은 바로 앞에 있는 문자나 문자 집합이 세 번 연속해서 일치하는지 확인한다. 만약 요소가 두 개만 있다면, 패턴이 일치하지 않는다.

RegEx: 

16진수 여섯개가 일치하는 것을 검색



범위 구간 찾기

일치시키려는 요소 수의 최솟값과 최댓값을 나타낼 때도 구간을 사용한다. 범위는  {2,4} 처럼 표현한다. 최소 두 번에서 초대 네 번까지 일치시킨다는 의미이다.

RegEx: 

이 예제에서 쓴 정규식은 슬래시(/) 문자를 \/ 로 이스케이프 하였다. 많은 정규식 구현에서는 이 작업이 필요 없지만, 어떤 정규 표현식 해석기에는 필요하다. 

따라서 상 슬래시(/) 를 이스케이프 하는 편이 좋다.


※ 구간은 0부터 시작하기도 한다. {0,3} 은 요소가 없는 경우나 요소가 한 번 또는 두 번이나 세 번 일치함을 의미한다.

물음표(?)는 물음표 앞에 주어진 요소가 없는 경우나 요소 한개와 일치한다. 즉, 물음표(?) 는 {0,1} 과 같은 기능을 한다.



최소 구간 찾기

예를 들어 {3,} 은 최소한 요소가 세 번 일치함을 의미한다. 

RegEx: 


※ 더하기(+) 는 {1,} 과 기능이 같다.


'Programming > RegEx' 카테고리의 다른 글

Greedy Quantifier & Lazy Quantifier  (0) 2013.05.12
반복 찾기(+, *) 와 '?' 메타 문자  (0) 2013.05.12
포직스(POSIX) 문자 클래스  (0) 2013.05.12
메타 문자 사용  (0) 2013.05.06
문자 집합으로 찾기  (0) 2013.05.06
Posted by scii
:


문자 하나 이상 찾기

문자나 집합에 속한 요소를 하나 이상 찾으려면 간단히 문자 뒤에 더하기(+) 문자를 붙이면 된다. 더하기(+)는 문자가 하나 이상일 때 일치한다. (최소한 하나와 알치하고, 없을 때는 일치하지 않는다)

a가 a를 찾는 데 반해, a+는 하나 이상 연속된 a를 찾는다. 비슷하게 [0-9] 는 자릿수가 하나인 숫자를 찾는 데 반해, [0-9]+ 는 한 자리 이상 연속된 숫자를 찾는다.


TIP

문자 집합에 더하기(+)를 사용할 때는, 더하기(+)를 집합 바깥에 두어야 한다. 즉 [0-9+] 가 아니라 [0-9]+ 가 맞는 표현이다.

[0-9+] 가 틀린 정규 표현식은 아니지만, 하나 이상의 숫자와 일치하지는 않는다. 더 정학히 말하면 숫자 0부터 9와 더하기(+)로 집합을 정의한 것이고, 따라서 아무 한 자리 숫자나 더하기 기호와 일치하게 된다. 

문법에는 맞지만, 원하는 결과는 아닐 것이다.



현재 블로그에 올리는 예제들은 vim에서 하고 있다. 그래서 본래의 정규식과 이스케이프되야하는 상황이 살짝 다르다. 

이를 테면, 정규식에서는 그냥 + 만 쓰지만, vim에서는 \+ 써야 한다.



이메일 주소를 검색하는 예제

RegEx: 


위의 예제에서 마지막에 \.\w\+ 이 부분을 주의해야 한다. 

이것은, 검색하는 문자열이 맨 마지막에 무조건 .(dot) 다음에 문자가 와야 한다는 것을 명시한 것이다. 저것을 빼면 이메일 주소 마지막에 .(dot) 까지 검색이 된다. 

하지만, 맨 마지막에 위와 같이 명시를 하면 정확히 이메일 주소만 검색을 할 수 있다. 


※ 이 패턴을 보고 집합 안에서는 마침표(.) 를 이스케이프 하지 않아도 마침표와 일치한다는 사실을 알 수 있다. 일반적으로 마침표나 더하기 같은 메타 문자들이 집합의 구성원일 때는 문자 그대로 취급하기 때문에, 굳이 이스케이프 할 필요가 없다. 

그러나 이스케이프 한다고 문제가 생기지는 않는다. [\w.] 는 [\w\.] 와 기능이 같다.




자가 없는 경우나 하나 이상 연속하는 문자 찾기

더하기는 하나 이상 연속된 문자를 찾는다. 문자가 없는 경우는 아예 찾지 못하고, 최소한 하나는 일치해야 한다. 

그래서 있을 수도 있고 없을 수도 있는 문자와 일치시키려면 메타 문자인 별표(*) 를 사용해야 한다.

따라서 B.* Forta 패턴은 B Forta, B. Forta, Ben Forta 같은 조합과 일치한다.


RegEx: 

위와 같은 이메일 주소는 없지만, 가상으로 만들어서 검색을 한 것이다.

맨 처음 \w\+는 처음에 오는 이메일 주소가 유효하고 그다음 . 이 있을 수도 없을 수도 있다는 것이다.




문자가 없거나 하나인 문자 찾기

별표(*) 처럼 물음표(?) 는 문자가 있는 경우 일치하고 문자가 없어도 일치하지만, 별표(*) 와 달리 문자나 집합이 없거나 하나만 있는 경우만 일치하며, 하나 이상은 일치하지 않는다.

즉, 물음표(?) 는 문자 묶음 안에서 있는지 없는지 확실하지 않은 특정한 문자를 하나만 찾을 때 매우 유용하다.


RegEx: 


이 패턴은 https?:// 로 시작한다. 물음표(?)는 자기 앞에 있는 문자가 없거나 그 문자가 하나만 있는 경우 일치한다. 여기서는 s인데, https?:// 는 http:// 나 https:// 와 일치하지만, 그 외에는 일치하지 않는다.


TIP:

집합([]) 은 일반적으로 문자 집합을 정의하는 데 쓰지만, 일부 개발자들은 혼란을 방지하고자 문자가 하나일 때도 집합을 사용한다. 바로 뒤에 나오는 메타 문자가 정확하게 어디에 적용되는지 확실하게 하려는 것이다.

즉, 위의 예제는 아래와 같이 확실하게 명시적으로 쓸 수 있다.

http[s]?://


'Programming > RegEx' 카테고리의 다른 글

Greedy Quantifier & Lazy Quantifier  (0) 2013.05.12
구간 지정  (0) 2013.05.12
포직스(POSIX) 문자 클래스  (0) 2013.05.12
메타 문자 사용  (0) 2013.05.06
문자 집합으로 찾기  (0) 2013.05.06
Posted by scii
:


포직스는 줄여 쓰기를 나타내는 또 다른 형태인데, 전부는 아니지만 많은 정규 표현식 구현에서 지원한다.


POSIX 문자 클래스

POSIX 문자

 [:alnum:]

 [A-Za-z0-9] 알파벳 문자와 숫자로 이루어진 문자열

 [:alpha:]

[A-Za-z] 알파벳 문자 

 [:blank:]

[ /x09] 스페이스와 탭(\t ]와 같다)

 [:digit:]

[0-9] 숫자 

 [:graph:]

[!-~] 공백이 아닌 문자 (스페이스, 제어 문자들을 제외한 문자) 

 [:lower:]

[a-z] 소문자 

 [:print:]

[-~] [:graph:] 와 유사하지만 스페이스 문자를 포함 

 [:punct:]

[!-/:-@[-{-~] 문장 부호 문자([:alnum:]이나 [:cntrl:]가 포함되지 않은 모든 문자

 [:space:]

[ \t\v\f] 모든 공백 문자(newline 줄바꿈, 스페이스, 탭) 

 [:cntrl:]

컨트롤 제어 문자 (아스키 0번부터 31, 127번)

 [:upper:]

[A-Z] 대문자 

 [:xdigit:]

[0-9a-fA-F] 16진수에서 사용할 수 있는 숫자 


※ POSIX

이식 가능 운영체제 인터페이스(portable operating system interface), 또는 포직스는 서로 다른 유닉스 os의 공통 api 를 정리하여, 이식성이 높은 유닉스 응용 프로그램을 개발하려는 목적으로 IEEE가 책정한 애플리케이션 인터페이스 규격이다. 



RegEx: [[:xdigit:]]\+


여기서 사용한 정규 표현식이 [[로 시작해서 ]] 로 끝남을 유의하자. 이는 포직스 클래스를 사용할 때 매우 중요하고 필수적이다. 포직스 클래스는 [:로 시작해 :] 로 끝나기 때문에 우리가 사용하는 포직스 문법은 :xdigit: 가 아니라 [:xdigit:] 이다. 

따라서 바깥에 있는 대괄호는 집합을 정의하고, 안에 있는 대괄호는 포직스 클래스 자체를 나타내는 부분이다.



'Programming > RegEx' 카테고리의 다른 글

구간 지정  (0) 2013.05.12
반복 찾기(+, *) 와 '?' 메타 문자  (0) 2013.05.12
메타 문자 사용  (0) 2013.05.06
문자 집합으로 찾기  (0) 2013.05.06
정규 표현식(Regualr Expression)  (0) 2013.05.05
Posted by scii
:


여기에서 설명할 모듈은 threading이다. 이 모듈은 thread 모듈의 고수준 인터페이스를 지니고 있다. 


가벼운 프로세스(Lightweight Process)라고 하기도 하는 쓰레드는 프로세스 안에서 실행되는 단위이다.

하나의 프로세스 안에 쓰레드는 여러 개 존재할 수 있다. 

하나의 프로세스에 하나의 쓰레드만 존재한다면 싱글 쓰레드 프로세스(Single Thread Process) 이고, 두 개 이상의 쓰레드가 존재한다면 멀티쓰레드 프로세스(Multithread Process) 라고 한다.


쓰레드는 하나의 프로세스 안에 있는 '작은 프로세스'라고 생각할 수 있다. 하나의 프로세스 안에 있는 쓰레드들은 각각 독립적인 스택을 가지고 수행되나, 코드와 자료를 공유한다. 

따라서 쓰레드 간에 자료를 공유, 교환하는 것이 (프로세스 간의 자원 공유에 비해서) 매우 쉽다. 

CPU가 하나이므로 쓰레드의 수행은 어느 시점에서라도 중단되고 다른 쓰레드로 실행권이 넘어갈 수 있다. 쓰레드의 수행은 독립적이어서 다른 쓰레드와의 실행 순서에 관한 어떠한 가정도 할 수 없다.


※ CPython 구현상의 세부사항: Global Interpreter Lock 때문에, 한 번에 하나의 쓰레드만이 실행된다. 따라서 멀티 프로세서에서 threading 모듈을 사용했을 때 성능상의 이점은 전혀 없다. 

병렬 프로그래밍으로 성능을 향상시키고 싶다면 multiprocessing 모듈을 사용해야 한다.

하지만, 성능상의 이점이 없다고 해도 많은 I/O 처리가 동시에 필요할 때 threading 으로 해결할 수 있다.





threading 모듈의 도구:

threading.activeCount()

현재 살아 있는 thread의 개수 반환.


threading.currentThread()

현재 thread 객체를 반환.


threading.enumerate()

현재 살아 있는 모든 thread 반환.


threading.Condition()

새로운 condition variable 객체 반환. condition variable은 내부에 하나의 쓰레드 대기 큐(Queue)를 가진다. wait() 를 호출하는 쓰레드는 이 대기 큐에 넣어지고 대기(Sleep) 상태에 들어간다. notify()를 호출하는 쓰레드는 이 대기 큐에서 하나의 쓰레드를 깨운다.


threading.Event()

Event 객체는 네 개의 메소드를 가지고 있다. ( set(), clear(), wait(), isSet() ) Event 객체는 내부에 하나의 이벤트 플래그를 가진다. 초기 값은 0이다.

set() 메소드는 내부 플래그를 1로 만들어 주고, clear() 메소드는 0으로 만든다.

wait() 메소드는 내부 플래그가 1이면 즉시 리턴되며, 0이면 다른 스레드에 의해서 1이 될 때까지 블록(대기) 상태에 들어간다. wait()는 내부 플래그 값을 바꾸지 않는다.


threading.Lock()

lock 객체를 생성. 하나의 스레드가 정보를 갱신하는 동안 다른 스레드가 그 변수에 접근하지 못하도록 해야 할 때 쓰인다.


threading.RLock()

RLock 클래스 객체는 Lock 객체와 같으나, 락을 소유하고 있는 스레드가 두 번 이상 acquire와 release를 호출 할 수 있다. acquire 한 만큼 release 해야 락이 해제된다.


threading.Semaphore([value])

semaphore 객체는 생성. 세마포어는 카운터로 관리한다. 카운터는 acquire() 메소드를 사용하면 -1 이 되고, release() 메소드를 사용하면 +1 이 된다. 

만약, acquire()를 실행할 때 카운터 값이 0이면 스레드는 세마포 변수 대기 큐에 넣어져 블럭 상태(Block, 실행을 멈추고 어떤 사건이 일어나기를 대기하는 상태. CPU를 점유하지 않는다.) 로 들어간다.

release() 는 우선 세마포 변수에 대기하고 있는 쓰레드가 있는지를 검사한다. 만일 스레드가 존재하면 그들 중 가장 오래 대기하고 있던 스레드 하나를 풀어 준다. 스레드가 대기 큐에 없으면 카운터 값을 단순히 1 증가한다.


threading.BoundedSemaphore([value])

bounded semaphore 객체를 생성. bounded semaphore 란 현재 값이 초기 값을 초과하지 않는지 검사하는 기능이 추가되어 있다. 초기 값을 초과할 경우 ValueError 예외가 발생한다. 제한된 자원을 관리할 때 사용된다.


threading.local -> Class

thread의 local data를 나타내는 class이다. thread local 데이터를 관리하기 위해서는 local로 인스턴스를 생성하면 된다.

data = threading.local()

data = 1

스레드마다, 인스턴스의 값이 다르다.


threading.Thread -> Class

thread를 조작할 때 사용하는 클래스이다.


threading.Timer -> Class

일정 시간 간격마다 스레드에서 특정 함수를 실행하도록 하기 위해 사용한다.


threading.stack_size([size])

새로운 스레드를 생성했을 때 스레드의 스택 크기를 반환한다.



Thread 객체

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

키워드로 인자를 전달하는 Thread의 생성자

group은 반드시 None, 차후확을 고려한 것이다.

target은 run() 메소드가 호출될 때 실행할 함수를 지정한다.  기본은 None이다.

name은 thread의 이름을 뜻한다. 기본으로 'Thread-N' 형태로 지어진다.

args는 target에 전달할 인자를 tuple형태로 받는다.

kwargs는 target에 전달할 인자를 dictionary 형태로 받는다.

subclass를 만들 때 생성자를 override 하려면, Thread.init() 를 가장 먼저 실행하도록 해야 한다.


start()

thread를 시작한다. 

thread마다 한번씩 실행해야 한다. 이 메소드는 run() 메소드를 실행하도록 해준다. 

동일한 thread에 한번 이상 실행하면 RuntimeError 예외 발생.


run()

run() 메소드는 target 함수를 호출한다. override 가능.


join([timeout])

thread 가 종료할 때까지 기다린다. join() 메소드가 실행된 지점에서 thread가 종료할 때까지 기다린다.

기본 timeout 인자는 None 이다. float point나 fraction 형으로 인자를 초 단위로 지정할 수 있다. join() 은 언제나 None 을 반환한다. 만약 join() 을 호출한 뒤 언제 timeout이  발생하는지 알고 싶다면, isAlive() 를 호출해야 한다. timeout이 지난 다음에 아직 thread가 살아 있다면 thread는 종료된다.

join은 여러번 호출 될 수 있다.

현재 thread가 deadlock을 유발하려고 하면 join()은 RuntimeError 를 발생시킨다. 또는 시작하지 않은 thread에서 join()을 호출해도 마찬가지 예외가 발생한다.


name

이 문자열은 식별하기 위한 용도로만 사용하고 특별한 의미는 없다. 여러 thread가 같은 이름을 가져도 상관 없다. 초기 이름은 생성자에 의해 지정된다.


ident

특정 thread의 식별자이다. thread가 시작하지 않았다면 None으로 되어 있지만 시작하면 0이 아닌 어떤 정수를 가진다. thread.get_ident() 함수로 읽어 올 수 있다. 새로운 thread가 생성되면 이미 종료된 thread의 ident 값이 재활용될 수 있다.


isAlive()

thread 가 살아 있는지 여부를 반환한다.

run() 메소드가 실행된 다음부터 run() 메소드가 종료되는 때까지 True 값을 반환한다. 모듈 함수 enumerate() 는 살아 있는 thread의 list를 반환한다.


daemon

현재 thread가 daemon thread인지 아닌지 boolean 값으로 표시되어 있다. daemon 일 경우 True이다. start() 메소드가 실행되기 전에 지정되어야 하며, 그렇지 않다면 RuntimeError가 발생한다. 초기값을 부모 thread로 부터 상속 받는다. 따라서 기본으로 False로 되어 있다. 

모든 python 프로그램은 daemon이 아닌 thread가 모두 종료되면 종료된다. daemon인 thread는 계속 실행되는 상태에서 프로그램은 종료된다.


각각 분리된 thread를 관리하기 위한 클래스이다. 쓰레드를 생성하는 방법은 두 가지가 있다.

1) 호출 가능한 객체(함수 등) 를 생성자에 직접 전달하는 방법

2) 서브 클래스에서 run 메소드를 중복하는 방법


thread 객체가 생성되고 나면 start() 메소드를 실행해야 thread가 실행된다. start() 메소드는 각각의 thread에서 run() 메소드를 호출한다.

thread 객체가 시작되면, thread는 'alive' 상태가 된다. 이것은 run() 메소드가 종료되거나 예외가 발생 했을 때 종료된다. is_alive() 메소드를 실행하여 살아 있는지 여부를 알 수 있다. 

join() 메소드를 호출하여 thread 가 종료될 때까지 기다리도록 할 수 있다. 





상호 배제

멀티쓰레딩을 하면, 값을 갱신하는 중간에 연산이 다른 쓰레드로 교체되면서 바르지 못한 정보가 유지되지 못할 수 도 있다. 

이 같은 문제점을 해결하려면 하나의 쓰레드가 정보를 갱신하는 동안 다른 쓰레드가 그 변수에 접근하지 못하도록 해야 한다. 모듈 threading은 락(Lock) 객체를 지원한다. 


락 객체는 다음의 세가지 메소드를 가진다.

threading.Lock().acquire()

락을 얻는다. 일단 하나의 스레드가 락을 얻으면 다른 스레드는 락을 얻을 수 없다. 락을 소유하고 있는 스레드가 release()를 호출할 때까지 대기한다. 락이 해제되면 락을 얻는다.


threading.Lock().release()

락을 해제한다. 만일 acquire()로 해당 락을 기다리는 스레드가 있으면 그 스레드 중 하나만 락을 얻을 수 있다. 


threading.Lock().locked()

락을 얻었으면 1, 아니면 0을 리턴한다.


전형적인 사용 예)

전역 변수로 한 번만 lock을 얻는다. 

lock = threading.Lock()             # 여기서 얻어진 lock 객체는 모든 스레드가 공유해야 한다.


각 스레드는 다음과 같은 코드를 수행한다.

lock.acquire()                        # 락을 얻고 들어 간다. 이미 다른 스레드가 들어 가 있으면 락을 얻을 때까지 여기서 자동적으로 대기한다.

g_cnt += 1                             # 필요한 코드를 수행한다. 상호 배제 영역(Critical Section)

lock.release()                       # 락을 해제한다. 다른 스레드가 이 코드 영역으로 들어 갈 수 있도록 허락한다.


이와 같이 상호 배타적으로 코드를 수행해야 할 영역을 임계 영역(Critical Section) 이라고 한다. 

이러한 상호 배제는 락 객체로 구현 가능하다. 


위의 코드를 클래스로 작성함. 똑같은 결과.



Semaphore 객체

세마포는 가장 오래된 동기화 프리미티브이다. 세마포는 내부에 정수형의 카운터 변수를 가지고 있으며, 이 값은 세마포 변수를 생성할 때 초기화된다.

acquire()에 의해 1씩 감소하고, release()에 의해 값이 1씩 증가한다. 카운터는 0보다 작은 값을 가질 수 없다.


Semaphore 변수 활용 예

어떤 임계 영역이 있다고 하자. 이 영역에 단지 몇 개의 스레드만이 진입할 수 있도록 허용하고 싶다. 다음 예는 100개의 스레드가 어떤 코드를 500회 반복한다. 반복하는 코드의 어떤 영역은 최대 3개의 스레드만이 진입할 수 있도록 허용한다.




Event 객체

Event 객체는 네 개의 메소드를 가지고 있다. (set(), clear(), wait(), isSet()) Event 객체는 내부에 하나의 이벤트 플래그를 가진다. 초기 값은 0이다.

set() 메소드는  내부 플래그를 1로 만들어 주고, clear()메소드는 0으로 만든다.

wait() 메소드는 내부 플래그가 1이면 즉시 리턴되며, 0이면 다른 스레드에 의해서 1이 될 때까지 블록(대기) 상태에 들어간다. wait()는 내부 플래그 값을 바꾸지 않는다.


Event 변수 활용 예

두가지 종류의 스레드가 있다고 하자. 하나는 뭔가를 준비하는 스레드(T1) 이고, 나머지는 준비된 환경 하에서 수행하는 스레드이다. 당연히 T1이 원하는 작업을 수행한 후에 나머지 다른 스레드가 진행되어야 할 것이다. 

이때 Event 동기화를 이용하면 쉽게 문제가 해결된다.


'Programming > Python' 카테고리의 다른 글

multiprocessing Module  (0) 2013.05.17
Regular Expression  (0) 2013.05.13
발생자(Generator)  (0) 2013.05.09
반복자(Iterator)  (0) 2013.05.09
class 메소드 관련  (0) 2013.05.08
Posted by scii
:


발생자

발생자는 icon이란 언어에서 영향을 받았다.

만일 함수가 호출된 후에 되돌아갈 때, 메모리가 해제되지 않고 그대로 남아 있다면 어떨까? 그리고 다시 그 함수가 호출될 때 이전에 수행이 종료되었던 지점 이후를 계속 진행한다면 어떨까?     =>     이것이 발생자이다.

발생자란 (중단된 시점부터) 재실행 가능한 함수라고 할 수 있다. 


def generate_ints(n):

for i in range(n):

yield i

yield 는 발생자를 위해서 파이썬 2.2에 새롭게 도입된 예약어이다. 어떤 함수이든 yield 를 가지고 있다면 발생자이다.

파이썬 컴파일러가 이 키워드를 검출하면 이 함수를 발생자로 만들기 위해 별도로 처리한다.

yield 는 return 과 유사하나 실행 상태를 보존한 상태에서 복귀한다. 

gen 발생자 객체는 반복자이다. 

generate_ints의 초기 스택 프레임이 만들어지나, 실행은 중단된 상태이다.

gen.next() 로 실행이 재개되며, yield 에 의해서 중단된다. 

yield 는 일반 함수의 return 문과 같이 값을 호출 측에 돌려주나, 실행 상태와 지역 변수들을 보존한 상태로 값을 출력하는 것이 차이점이다.

발생자 객체의 next() 메소드 호출로 yield 다음 문장부터 다시 수행을 계속한다.


따라서 발생자를 다음과 같이 for 루프에 직접 사용하는 것이 가능하다.

일반 함수와 발생자의 가장 큰 차이점:

일반 함수는 호출되면, 종료할 때까지 모든 일을 마친 결과를 넘겨야 한다.

발생자는 정보를 생성하는 중간에 결과를 넘길 수 있다.


이것은 어떤 작업의 중간 결과를 다른 코드에서 참조해야 할 경우에 유용하게 활용된다. 모든 결과를 한꺼번에 받아서 처리하기보다는 중간 중간에 나오는 결과를 사용한다면 발생자가 효고적으로 활용될 수 있다.

병행 프로세스나 혹은 멀티 쓰레드로 처리해야 할 일부 작업들을 발생자로 대치할 수도 있다. 

트리 탐색이나 토큰 분석기 등이 대표적으로 적용 가능한 예가 될 것 같다.


발생자 구문

파이썬 2.2에서 도입된 반복자(Iterator)로 많은 양의 자료를 처리할 때 자료를 모두 메모리에 올리지 않고 순차적으로 반복 처리하는 것이 가능하게 되었다.

리스트 내장은 리스트 객체를 새로 생성하므로 메모리를 낭비하는 문제가 있다.

리스트 내장의 대부분의 경우는 발생자 구문으로 대치될 수 있다.

중간 리스트를 생성, 저장해야 하는 경우가 아니면 발생자 구문이 대부분 더 좋은 성능을 발휘한다.



발생자의 활용

피보나치 수열


홀수 집합 만들기

※ 위의 두 개를 테스 해 본 결과, class로 만든 것이 0.5초 더 빨랐다.

list(odds(20)) 같은 경우, 가장 느렸다.


하나씩 건너뛰어서 값 취하기


혹은 itertools 모듈을 이용하면 다음과 같은 코딩도 가능하다.


트리 탐색

이진 트리에서 깊이 inorder 탐색 기법으로 모든 노드들을 탐색하는 메소드를 구현.

파이썬에서 트리를 표현하는 것은 매우 간단하다. __init__ 메소드에서처럼 좌우 노드(left, right) 그리고 데이터를 가지는 멤버로 충분히 표현된다. Iorder 탐색은 inorder 메소드로 구현된다. 이 메소드는 생성자로 구현되었다. 

한 가지 주의할 것은 __iter__ 메소드이다. 이 메소드는 inorder 를 즉, inorder 생성자를 반복자로 리턴하고 있다. 트리에 대한 반복자는 곧 inorder 발생자가 된다.

따라서 마지막 두 줄처럼 마치 트리를 리스트나 튜플과 같이 수비게 for루프에서 활용할 수 있게 된다. 이ㅓㅅ으로 아주 일반화된 트리 탐색 방법을 가지게 된다. 이것은 생성자의 큰 장점이다.


중첩 리스트를 단일 리스트로 만들기

1) 발생자를 이용하지 않은 재귀적인 방법


2) 발생자를 이용한 방법


※ 발생자는 시퀀스 연산이 적용되는 곳이면 어디나 사용할 수 있다. 


'Programming > Python' 카테고리의 다른 글

Regular Expression  (0) 2013.05.13
Multithread Process  (0) 2013.05.12
반복자(Iterator)  (0) 2013.05.09
class 메소드 관련  (0) 2013.05.08
협동적 메소드와 super()  (0) 2013.05.07
Posted by scii
:


순차적으로 참조는 하나, 인덱싱에 의한 순서적인 참조가 의미 없는 경우를 보완하기 위해 반복자(Iterator)가 만들어졌다.


반복자 객체의 특성

# 반복자 객체는 iter() 내장 함수로 만들어진다.

# 반복자 객체는 next() 메소드를 가진다. next() 메소드를 가지는 객체가 반복자 객체이다.

# 반복자 객체가 next() 메소드로 더 이상 자료를 넘겨줄 수 없는 경우에는 StopIteration 예외를 발생한다.


클래스에 반복자 구현하기

이와 같이 순차적으로 참조되어야 할 정보는 반복자로 구현되는 것이 타당하다.



사전의 반복자

iterkeys, itervalues, iteritems 메소드는 키, 값 혹은 (키, 값) 튜플의 반복자를 리턴한다.

keys(), values(), items() 메소드를 이요해서 리스트로 된 자료를 얻은 후에 for 루프를 돌릴 수도 있지만 iterkeys(), itervalues(), iteritems() 메소드를 이용하면 요구된 시점에서 원하는 자료를 그때 그때 만들어서 넘겨주므로 리스트를 미리 구성해야 하는 부담이 없다. 

또 언제든지 루프를 중단할 때는 나머지 데이터에 대한 참조를 하지 않아도 되므로 더 효율적인 수행이 가능하다.



파일 객체의 반복자

파일 객체가 라인 단위의 반복자를 지원한다. 앞서 Seq 와 같은 클래스를 만들 필요가 없다.



호출 가능한 객체에 반복자 적용하기

호출 가능한 객체(callable) 에 반복자를 적용할 수 있다.


C언어에는 다음과 같은 구조가 있다. (엔터 키만 입력 받으면 Null을 리턴)

while((line = readline()) != NULL)

{

printf(line);

}

이러한 구조를 파이썬으로 구현하기는 쉽지 않은데, 다음과 같이 하면 가능하다.

for line in iter(raw_input, ''):

print line

호출되는 함수가 인수를 받을 경우에는 위와 같은 방법으로는 안된다. 이 경우는 람다 함수를 이용하면 쉽게 해결 된다.

lambda:accum(sum, 2) 와 같이 lamda: 다음에 원하는 함수를 호출해 주면 된다. 매번 함수를 호출한 결과 값은 sum이 받을 것이며, 이 값은 40 과 비교되어 값이 같으면 루프를 종료한다.



itertools 모듈

이 모듈은 반복 가능한 객체(시퀀스, 반복자, 발생자등) 의 반복자(혹은 발생자)를 생성하는 몇 개의 함수로 구성되어 있다.

이들 함수는 메모리와 계산 시간에서 효과적인 연산이 가능하도록 많은 도움을 준다. 반복자가 효과적인 이유는 자료가 욕구될 때 필요한 시점에서 자료를 준비해서 리턴하기 때문이다.

기에 설명되는 함수들은 자료의 크기가 크면 클수록 더욱 그 효과를 발휘한다.


chain(*iterables) 함수는 객체에서 자료를 연속해서 하나씩 넘겨준다.

l1, l2에 대해 연속된 데이터를 넘겨준다.


이 방법은 새로운 리스트를 생성하므로 메모리를 낭비한다.



groupby(iterable[, key]) 는 자료를 그룹 단위로 묶는 데 사용된다. key 함수가 주어지지 않았을 경우는 요소 자료 자체가 키 값이 된다.

인수가 정렬되어야 인접한 자료를 한 그룹으로 묶는다.


두 번째 자료를 기준으로 그룹화하려면 다음과 같이 할 수 있다.

itemgetter(1) 은 어떤 객체의 [1] 요소 값을 취하는 함수이다. 즉, lambda x:x[1] 과 같은 함수이다.


다음 예는 문장의 단어가 몇 번 반복되는가를 출력한다.


'Programming > Python' 카테고리의 다른 글

Multithread Process  (0) 2013.05.12
발생자(Generator)  (0) 2013.05.09
class 메소드 관련  (0) 2013.05.08
협동적 메소드와 super()  (0) 2013.05.07
연산자 오버로딩  (0) 2013.05.02
Posted by scii
:

xargs, find 명령어

Linux/Common 2013. 5. 8. 01:58 |


xargs 

xargs 명령은 입력된 데이터를 라인 단위로 읽어서 argument화하는 명령이다.

find 명령을 사용하여 검색한 파일에 대한 처리를 위해 파이프로 연결하여 사용한다.


위의 명령은, which 명령에 의해 출력되는 bash 실행 파일의 경로가 /bin/bash인데, 이 결과 값이 파이트와 xargs에 의해 ls -l 아규먼트로 대입되어 결국 ls -l /bin/bash 명령을 수행한 결과를 출력하게 된다.



find

find 명령은 디렉토리 계층에서 파일을 검색하기 위한 명령이다. 

find 명령으로 검색한 결과 값은 하나의 라인에 하나의 파일명이 출력되는데, 이 결과 값을 파이프로 연결하여 여러가지 명령의 아규먼트로 전달하여 원하는 명령을 실행하고 그 결과 값을 얻어낸다.


형식

1) -exec를 사용하여 검색된 결과를 명령의 아규먼트 ({})로 사용한다.

# find ... -exec 명령 {} \;

2) xargs 명령을 사용하여 파이프로 전달된 결과를 표준 입력 아규먼트로 받아서 명령을 실행한다.

# find ... | xargs 명령


find 옵션


 find 옵션

의        미 

 -name 파일명 

 파일명으로 검색한다. 

 -user 유저명 

 유저명 또는 UID로 검색한다. 

 -group 그룹명 

 그룹명으로 검색한다. 

 -perm nnn 

 퍼미션이 nnn인 파일을 검색한다.

 예) -perm 755

 # find . -perm -100 -print

 실행 가능한 --x------ 파일을 찾는다.

 -perm 인자가 마이너스(-) 부호를 가지게 되면 setuid 설정 비트를 포함한 모든 퍼미션 비트들이 검사된다.

 -type x 

 파일 타입이 x인 파일을 검색한다.

 b(블럭 특수 파일), c(문자 특수 파일), d(디렉토리), p(파이프), f(정규표현 일반 파일), l(심볼릭 링크 파일), s(소켓) 

 -atime +n 

 접근 시간이 n일 이전인 파일을 검색한다. (access) 

 -atime -n 

 접근 시간이 n일 이내인 파일을 검색한다. (access) 

 -ctime +n 

 n일 이전에 변경된 파일을 검색한다.

  (change: 내용 수정이 아니라 모드 변경 또는 접근 시간 변경)

 -mtime +n 

 n일 이전에 내용이 수정된 파일을 검색한다. (modify) 

 -mtime -n 

 n일 이내에 내용이 수정된 파일을 검색한다. (modify) 

 -empty

 파일이 비어있고 (0 bytes) 일반 파일, 디렉토리를 검색한다. 

 -newer 파일명 

 파일명의 파일보다 최근에 수정된 파일을 검색한다. 

 -size n 

 파일 블록 크기가 n 이상인 파일을 검색한다.

 b(블럭 -기본값), c(bytes), k(kbytes), w(2바이트 단어) 

 -links n 

 링크된 개수가 n인 파일을 검색한다. 

 -print 

 표준 출력 

 -exec 명령

 검색된 파일을 찾으면 command 명령을 실행한다.

 명령 인자(검색된 파일)는 {}으로 사용하며, 이때 명령 끝은 \;(;이 아님)을 사용해야 한다.

 즉, 명령구분 문자인 ';'을 이스케이프(\) 시켜 주어야 한다.  

 -operator 

 -a: and 연산, -o: or  연산, !: not 연산 

 -path 패턴

 path가 패턴과 일치하는 path에 대해서 검색한다.  

 -regex 패턴 

 파일명이 패턴과 일치하는 정규 표현식에 대해서 검색한다. 



find 명령에서 사용하는 -atime, -ctime, -mtime 옵션에서의 시간들은 일(하루 24시간) 단위이다. 

부호 없는 숫자, 예를 들어 3은 정확하게 3일 전에 끝난 24시간을 의미한다. 다시 말하면 96시간과 72시간 이전 사이를 의미하는 것이다.


마이너스(-) 부호를 가진 숫자는 그 시간 이후에 기간을 가리킨다. 예를 들어, -3은 지금과 3일 전 사이의 모든 시간을 의미한다. 

다시 말하면 0시간 이전과 72시간 이전 사이를 의미하는 것이다.


플러스(+) 부호를 가진 숫자는 그 시간 이전의 기간을 가리킨다. 예를 들면, +3은 3일 이상된 시간을 의미한다.

다시 말하면 72시간 이상 지난 파일을 의미하는 것이다.



# find . -type f -exec file '{}' \;

쉘이 위치한 현재 디렉토리 아래에서 모든 파일을 검색하고 file 명령을 실행한다. 

'{}', 작은따옴표로 둘러싸인 브레이스는 쉘 스크립트에 의해 해석되지 않도록 하기 위한 것이며, find 명령으로 찾은 파일을 의미한다.

세미콜론(;)은 쉘에서 해석되지 않기 위해 백슬래시(\)를 사용하고 있다. 

만약 현재 디렉토리 아래의 grep 디렉토리에서 검색하려면 ./grep 를 지정하면 된다.


# find $HOMe -mtime 0

현재 쉘에 접속해 있는 자신의 홈디렉토리 아래에서 24시간(-mtime 0) 안에 수정된 파일들을 검색하여 출력한다.


# find . -name 'fi*'

현재 디렉토리부터 모든 하위 디렉토리까지 파일명이 fi로 시작하는 모든 파일을 검색하여 출력한다.


# find . -perm 755

현재 디렉토리부터 모든 하위 디렉토리까지 퍼미션이 755인 파일과 디렉토리를 검색한다.

위의 명령은 모든 파일과 디렉토리를 검색하였지만, -type f 옵션을 추가하면 일반 파일만 출력할 수 있다.

# find . -type f -perm 755


# find /home -newer here.sh

/home 디렉토리 아래에서 here.sh 파일보다 최근에 수정된 파일을 검색하여 출력한다.


# find /home -size +1024 -print

/home 디렉토리 아래에서 파일의 블록 크기가 1024 이상인 파일을 검색하여 출력한다.


# find ~/ -type d -print

홈 디렉토리 아래에서 디렉토리들만 검색하여 출력한다.


# find /home \( -name a.out -o -name '*.o' \) -atime +7 -exec rm '{}' \;

/home 디렉토리 아래에서 파일명이 a.out 또는 .o로 끝나는 파일을 검색하고, 7일 동안 사용하지 않은 파일(생성/변경 날짜가 7일 이상된 파일)이면 rm 명령을 사용하여 삭제하도록 하는 명령이다.


# find /tmp -name core -type f -print | xargs /bin/rm -f

/tmp 디렉토리 아래에서 파일명이 core인 파일을 검색하여 출력한다. 이때 검색된 파일 목록은 하나의 라인에 하나의 파일명이 출력되는데, 파이프로 연결된 xargs 명령에 의해 라인 단위로 /bin/rm -f 명령의 아규면트로 전달되어 검색된 모든 파일들을 삭제하게 된다.


# find . -type f -mtime +1 | xargs -n 100 rm -f

find 명령을 사용하여 현재 디렉토리 아래에서 현재 시간보다 하루(+) 전(24시간 내에 작성/수정된 파일만 제외) 에 작성/변경된 파일을 찾으면 라인 단위로 파일 리스트가 쉘에 출력된다.

이 파일 리스트는 하나의 라인당 하나의 파일명이 출력되기 때문에 각 라인의 파일명을 아규먼트화하기 위해 xargs 명령을 파이프로 연결한 다음 -n 100, 즉 100라인 (100개의 아규먼트) 을 한 번에 읽어서 rm -f [아규먼트] 로 치환하여 100개 단위로 검색된 파일들을 삭제하는 명령이다.


'Linux > Common' 카테고리의 다른 글

vim 업데이트 및 gvim 설치  (0) 2014.02.01
분할 압축  (0) 2013.05.26
Linux Theme  (0) 2013.04.28
Linux Theme Settings  (2) 2013.04.07
터미널에서 멀티태스킹하기  (0) 2013.02.02
Posted by scii
: