2012-10-16 5 views
0

이 사이트에서 다양한 질문을 통해 파일에서 4 바이트 (32 비트 부호없는 리틀 엔디안) 정수를 읽는 3 가지 방법을 발견했습니다. 즉 :struct.unpack 대 Python의 합계를 사용하여 바이트를 정수로 변환

1) myInt, = struct.unpack('<I', bytes) 
2) myInt = struct.unpack('<I', bytes)[0] 
3) myInt = sum(bytes[i] << (i*8) for i in range(4)) 

다음 중 어느 것이 가장 좋습니까? 압축 해제를 사용하려면 struct 모듈을 가져와야하지만 다른 방법이나 장단점은 무엇인지 알아야합니다.

+1

* 최고 *는 무엇을 의미합니까? 더 효율적입니까? 더 휴대용? 좀 더 가독성? 더 우아한가? – Bakuriu

+0

@Bakuriu 하하 네가 거기에있어! 가장 빠르다는 것을 의미한다고 생각하지만, Python을 처음 접했을 때 나는 어떤 방법 으로든 위험이나 어려움이 있는지를 알고 싶었습니다. – Caltor

답변

2

을 가장 좋은 것으로 가정하면이 더 효율적이라는 것을 의미합니다. 처음 두 개를 말합니다.

이 마이크로 벤치 마크 세 번째에서 볼 수 있듯이이 훨씬 더 나쁘다 :

>>> bytes=b'\x10\x11\x12\x13' 
>>> import struct 
>>> import timeit 
>>> timeit.timeit('a,=struct.unpack("<I", bytes)', 'from __main__ import struct, bytes') 
0.16049504280090332 
>>> timeit.timeit('a=struct.unpack("<I", bytes)[0]', 'from __main__ import struct, bytes') 
0.1881420612335205 
>>> timeit.timeit('sum(bytes[i] << (i*8) for i in range(4))', 'from __main__ import bytes') 
1.2574431896209717 

는 또한 세 번째는 python2에서 작동하지 않는 동안 (그래서 그들은 또한 더 이식 제 1 및 제 2 DO).

세 번째는 읽기 쉽지 않지만 struct에 대한 약간의 지식이 있지만 처음 두 버전을 쉽게 이해할 수 있습니다.

첫 번째 문자가 약간 빠름에도 불구하고 두 번째 문자를 선택하는 편이 낫습니다. [0]은 첫 번째 요소를 사용하고 있음을 분명히 알리는 반면 쉼표만으로는 읽기가 쉽지 않기 때문에 두 번째 문자를 선택할 수 있습니다. 또한 속도의 차이는 실제로는 최소화되어 있으며 파이썬의 최신/이전 버전에서 변경되므로 속도 만 위해 첫 번째 버전을 사용하면 최적화가되지 않습니다.

업데이트 : sum이 (...보다) 훨씬 느린 이유

설명하려면 :

그냥 다른 마찬가지로 파이썬에서 정수 객체 것을 고려. 5 + 2 할 때 두 개의 정수 개체를 만들고 __add__ 메서드를 수행하십시오. 그래서 추가 작업은 하나의 기계 명령을 사용하지 않습니다.

비트 시프트 솔루션이 훨씬 느리고 중간 개체를 만들어야하며 메서드 호출을 수행해야합니다.이 메서드 호출은 인터프리터에서 인수를 압축하고 압축해야하기 때문에 비용이 들기 마련입니다.

C에서 효율적인 것은 파이썬에서 효율적이라고 가정하면 안됩니다.

CPython에서 코드를 최적화하는 황금률 (참고 : Python이 아닌 CPython. PyPy, Jython 등과 같은 공식 구현을 말하는 것이지)은 " C 수준 ". "C 수준"으로 I는 sum (주 사용 용액보다 인 "C 함수"struck.unpack이 경우에서는

C.

작성된 내부 기능을 의미한다 : 내부 sum는 "파이썬 레벨"루프가있는 "C 레벨"루프보다 느립니다.)

#python2 
>>> import timeit 
>>> L = ['1', '2', '3'] * 5 
>>> timeit.timeit('map(int, L)', 'from __main__ import L') 
5.549130916595459 
>>> timeit.timeit('[int(x) for x in L]', 'from __main__ import L') 
6.402460098266602 

내가 그것을가 당신을 위해 유익 할 수 있다고 생각 (여기에 더 이상 목록입니다, 빠른 map 솔루션 목록-이해에 관하여이다) :

타 예는지도이다 this 내 대답은 순수한 파이썬 O (n) 알고리즘이 "C 레벨"루프를 사용하는 O (n logn) 알고리즘에 의한 합리적인 입력 크기의 비트 톤을 얻는 방법을 보여줍니다. [참고 : [senderle 's answer] 이 python2에서 작동하지 않는 이유에

는 : python2 파일에서

[email protected]:~$ python2 
Python 2.7.3 (default, Aug 1 2012, 05:14:39) 
[GCC 4.6.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> bytes='\x10\x11\x12\x13' 
>>> import timeit 
>>> timeit.timeit('sum(bytes[i] << (i*8) for i in range(4))', 'from __main__ import bytes') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/timeit.py", line 230, in timeit 
    return Timer(stmt, setup, timer).timeit(number) 
    File "/usr/lib/python2.7/timeit.py", line 195, in timeit 
    timing = self.inner(it, self.timer) 
    File "<timeit-src>", line 6, in inner 
    File "<timeit-src>", line 6, in <genexpr> 
TypeError: unsupported operand type(s) for <<: 'str' and 'int' 

은 문자열과 문자열 요소는 문자열 반환, 그래서 당신은 교대 작업을 할 수 없습니다. 그것이 당신을 위해 일했다면 당신은 python3을 사용하고있었습니다.

+0

마이크로 벤치 마크에 감사드립니다. 어떻게해야 할 지 잘 모릅니다. 나는 비트 시프트가 더 빠를 것으로 예상하면서 놀랍다 고 생각한다. 과거에 C 프로그래밍을 살펴 보았을 때 빠른 연산을 수행하는 데 비트 시프트가 사용되기도했습니다. Python 2.7.3에서 세 번째 방법을 시도해 보았지만 제대로 작동했습니다. 파이썬 2에서 작동하지 않는 이유는 무엇입니까? – Caltor

+0

우수 답변. 최적화와 python2에 관한 최신 정보를 보내 주셔서 감사합니다. 나는 나의 시험을 다시 점검해야하고 그 차이점을 알아야 할 것이다. – Caltor