20 바이트의 문자열이 있는데 ctypes.c_ubyte
비트 필드 조작을 위해 배열 로 변환하고 싶습니다 .
import ctypes
str_bytes = '01234567890123456789'
byte_arr = bytearray(str_bytes)
raw_bytes = (ctypes.c_ubyte*20)(*(byte_arr))
캐스트를 위해 str에서 bytearray 로의 깊은 복사를 피하는 방법이 있습니까?
또는 딥 카피없이 문자열을 바이트 배열로 변환 할 수 있습니까? (memoryview와 같은 기술로?)
Python 2.7을 사용하고 있습니다.
성능 결과 :
eryksun 과 Brian Larsen 의 제안을 사용하여 Ubuntu 12.04 및 Python 2.7을 사용하는 vbox VM의 벤치 마크는 다음과 같습니다.
결과 :
암호:
import ctypes
import time
import numpy
str_bytes = '01234567890123456789'
def method1():
result = ''
t0 = time.clock()
for x in xrange(0,1000000):
byte_arr = bytearray(str_bytes)
result = (ctypes.c_ubyte*20)(*(byte_arr))
t1 = time.clock()
print(t1-t0)
return result
def method2():
result = ''
t0 = time.clock()
for x in xrange(0,1000000):
result = (ctypes.c_ubyte * 20).from_buffer_copy(str_bytes)
t1 = time.clock()
print(t1-t0)
return result
def method3():
result = ''
t0 = time.clock()
for x in xrange(0,1000000):
result = ctypes.cast(str_bytes, ctypes.POINTER(ctypes.c_ubyte * 20))[0]
t1 = time.clock()
print(t1-t0)
return result
def method4():
result = ''
t0 = time.clock()
for x in xrange(0,1000000):
arr = numpy.asarray(str_bytes)
result = arr.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte*len(str_bytes)))
t1 = time.clock()
print(t1-t0)
return result
print(method1())
print(method2())
print(method3())
print(method4())
나는 당신이 생각하는 방식으로 작동하지 않습니다. bytearray
문자열의 복사본을 만듭니다. 그런 다음 인터프리터는 bytearray
시퀀스를 a로 압축을 풀고 다른 인수가있는 starargs
tuple
다른 새 항목에 병합합니다 tuple
(이 경우에는 없음에도 불구하고). 마지막으로, c_ubyte
배열 이니셜 라이저 는 배열 tuple
의 요소를 설정하기 위해 args 를 반복 합니다 c_ubyte
. 배열을 초기화하기 위해서는 많은 작업과 복사 작업이 필요합니다.
대신 from_buffer_copy
문자열이 버퍼 인터페이스 (유니 코드 아님)가있는 바이트 문자열이라고 가정 하여 메서드 를 사용할 수 있습니다 .
import ctypes
str_bytes = '01234567890123456789'
raw_bytes = (ctypes.c_ubyte * 20).from_buffer_copy(str_bytes)
여전히 문자열을 복사해야하지만 한 번만 수행되고 훨씬 더 효율적입니다. 주석에서 언급했듯이 Python 문자열은 변경할 수 없으며 인턴 또는 사전 키로 사용할 수 있습니다. ctypes가 실제로 이것을 위반하도록 허용하더라도 불변성은 존중되어야합니다.
>>> from ctypes import *
>>> s = '01234567890123456789'
>>> b = cast(s, POINTER(c_ubyte * 20))[0]
>>> b[0] = 97
>>> s
'a1234567890123456789'
편집하다
불변의 CPython 문자열을 수정하기 위해 ctypes를 사용하는 것을 권장하지 않는다는 점을 강조해야합니다. 필요한 경우 최소한 sys.getrefcount
참조 횟수가 2 이하인지 미리 확인하십시오 (호출에 1이 추가됨). 그렇지 않으면 결국 이름 (예 :) "sys"
및 코드 객체 상수에 대한 문자열 인터 닝에 놀라게 될 것 입니다. 파이썬은 적절하다고 생각되는대로 변경 불가능한 객체를 자유롭게 재사용 할 수 있습니다. '불변'개체를 변경하기 위해 언어를 벗어나면 계약이 깨졌습니다.
예를 들어 이미 해시 된 문자열을 수정하면 캐시 된 해시가 더 이상 내용에 맞지 않습니다. 그것은 dict 키로 사용하기 위해 그것을 깨뜨립니다. 새 내용이있는 다른 문자열이나 원래 내용이있는 문자열은 dict의 키와 일치하지 않습니다. 전자는 다른 해시를 가지며 후자는 다른 값을 갖습니다. 그런 다음 dict 항목을 얻는 유일한 방법은 잘못된 해시가있는 변경된 문자열을 사용하는 것입니다. 이전 예에서 계속 :
>>> s
'a1234567890123456789'
>>> d = {s: 1}
>>> d[s]
1
>>> d['a1234567890123456789']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'a1234567890123456789'
>>> d['01234567890123456789']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '01234567890123456789'
이제 열쇠가 수십 곳에서 재사용되는 인턴 문자열이라면 혼란을 고려하십시오.
성능 분석을 위해 timeit 모듈을 사용하는 것이 일반적입니다. 3.3 이전 버전 timeit.default_timer
은 플랫폼에 따라 다릅니다. POSIX 시스템 time.time
에서는이고 Windows에서는 time.clock
.
import timeit
setup = r'''
import ctypes, numpy
str_bytes = '01234567890123456789'
arr_t = ctypes.c_ubyte * 20
'''
methods = [
'arr_t(*bytearray(str_bytes))',
'arr_t.from_buffer_copy(str_bytes)',
'ctypes.cast(str_bytes, ctypes.POINTER(arr_t))[0]',
'numpy.asarray(str_bytes).ctypes.data_as('
'ctypes.POINTER(arr_t))[0]',
]
test = lambda m: min(timeit.repeat(m, setup))
>>> tabs = [test(m) for m in methods]
>>> trel = [t / tabs[0] for t in tabs]
>>> trel
[1.0, 0.060573711879182784, 0.261847116395079, 1.5389279092185282]
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다