새소식

Programming/python

[python3] 동일 값으로만 채워진 객체 확인하기

  • -

동일한 값으로만 iterable 한 객체가 가득 채워진 경우를 확인할 필요가 있습니다.

 

예를 들면 C 언어로 초기화된 리눅스 공유메모리는 C 의 null 값인 0x00 으로 초기화 됩니다.

제가 사용하고 있는 프로그램은 4096 Byte의 공유메모리를 초기화 해서 사용하고 있었습니다.

 

공유 메모리 내용 검증을 하기 위해 특정 상황에 메모리 내용을 찍도록 해놓았는데, 초기화이 쓸데없이 0x00 이 4096개나 스크롤되는게 좀 짜증이 났습니다.

 

방법을 찾던 중 all 이라는 파이썬 내장(built-in)함수를 알게 되었습니다.

all(iterable) 과 같이 호출하고 iterable 값 중에 하나라도 비어 있는 값이 있으면 False 를 반환하고 모두 비어있지 않으면 True 를 반환합니다.

비슷한 함수로 any(iterable) 이 있습니다. 이 함수는 iterable 값 중에 하나라도 비어 있지 않으면 True 를 반환하고 모두 비어 있으면 False 를 반환합니다.

 

여기서 공유메모리 변수를 shm 이라 하고 shm = b'0x00' * 4096 하면 제 공유메모리 읽어온 거랑 같은 상황이 되는데요,

all(shm) 을 호출하든, any(shm) 을 호출하든 모두 False 가 반환되겠죠.

all 입장에서는 1개 이상 비어(0x00, 0, 공백 문자, 빈 문자열, None 객체, False 값 등등) 있으므로,

any 입장에서는 모두 비어 있어서 False 가 됩니다.

 

그래서 단순히 shm 을 넣은 것 만으로는 원 목적을 달성할 수가 없게 됩니다.

 

all(el == shm[0] for el in shm) 라고 하면 첫번째 항목과 값이 같은지 여부를 채운게 all 함수에 전달되고 한개라도 다르면 False 가 존재할테니 all() 호출 결과는 False 가 됩니다.

모두 첫번째 항목과 값이 같아야 모두 True 가 넘겨지고 all() 호출 결과는 True 가 됩니다.

if all(el == shm[0] for el in shm):
	print("ERROR:초기화되어 비어 있는 상태입니다.")
else:
	print(f"shm={shm}")

참고로 첫번째 값인 shm[0] 이 아니라 특정 리터럴 값을 바로 비교해도 됩니다. 원하시는 값으로요.

더보기

혹시나 성능이 궁금해서 위와 같은 목적을 가진 다른 방법들의 실행시간을 수집해봤습니다.

 

msg = b'\x00' * 4096
>>> result = None
>>> def checkList(lst):
     ele = lst[0]
     chk = True
     for item in lst:
             if ele != item:
                     chk = False
                     break
     if (chk is True):
             return True
     else:
             return False

>>> timeit.timeit('result = checkList(msg)', number = 100, globals=globals())
0.06590730700008862
>>> timeit.timeit('global result; result = checkList(msg)', number = 100, globals=globals())
0.06191983700000492
>>> timeit.timeit('global result; result = all(el == msg[0] for el in msg)', number = 100, globals=globals())
0.16510143899995455
>>> timeit.timeit('global result; result = msg.count(msg[0]) == len(msg)', number = 100, globals=globals())
0.0025154830000246875
>>> timeit.timeit('global result; result = len(set(msg)) == 1', number = 100, globals=globals())
0.040132068999810144
>>> timeit.timeit('global result; result = [msg[0]]*len(msg) == msg', number = 100, globals=globals())
0.0065764569999373634
>>> import operator
>>> from functools import reduce
>>> timeit.timeit('global result; result = reduce(operator.eq, msg)', number = 100, globals=globals())
0.09990671000014117

 

결론은 count, 리스트 생성 후 비교 등이 제일 빠른 것 같네요.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.