Проверить, поддерживает ли объект протокол протокола python

Я ищу эквивалент Python для Python C-API PyObject_CheckBuffer.

т.е. Я хотел бы проверить, поддерживает ли объект буферный протокол, но из Python.

Ответ 1

Я думаю, вы просто должны использовать стандартный метод try-it-and-see-if-it-works:

# New-style buffer API, for Python 2.7 and 3.x.
# PyObject_CheckBuffer uses the new-style API.
# 2.6 also has the new-style API, but no memoryview,
# so you can't use it or check compatibility from Python code.
try:
    memoryview(thing)
except TypeError:
    # Doesn't support it!

# Old-style API. Doesn't exist in 3.x.
# Not quite equivalent to PyObject_CheckBuffer.
try:
    buffer(thing)
except TypeError:
    # Doesn't support it!

Ответ 2

Работая с короткими фрагментами данных в критически важном для кода коде, мне пришлось попробовать разные подходы. В зависимости от вашего приложения, один может быть лучше, чем другие.

def ensure_bytes__try(data):
    try:
        # memoryview used only for testing type; 'with' releases the view instantly
        with memoryview(data):
            return data
    except TypeError:
        return data.encode()

def ensure_bytes__isinstance(data):
    # Explicitly test for some bytes-like types
    # - misses array.array, numpy.array and all other types not listed here
    return data if isinstance(data, (bytes, bytearray, memoryview)) else data.encode()

def ensure_bytes__hasattr(data):
    # Works as long as your bytes-like does not have 'encode'
    return data.encode() if hasattr(data, "encode") else data

def ensure_bytes__args(data=None, data_bytes=None):
    # Avoid autodetection by using explicit arguments
    return data_bytes if data is None else data.encode()

Следующий тест показывает время, используемое каждой реализацией в Python 3.7.4:

ensure_bytes__try(b"foo")             ▒▒▒▒█████████████████ 438 ns
ensure_bytes__try("foo")              ▒▒▒▒▒██████████████████████████████████ 797 ns
ensure_bytes__isinstance(b"foo")      ▒▒▒▒█████████ 277 ns
ensure_bytes__isinstance("foo")       ▒▒▒▒▒███████████████████ 489 ns
ensure_bytes__hasattr(b"foo")         ▒▒▒▒████ 171 ns
ensure_bytes__hasattr("foo")          ▒▒▒▒▒█████████ 287 ns
ensure_bytes__args(data_bytes=b"foo") ▒▒▒▒██ 121 ns
ensure_bytes__args(data="foo")        ▒▒▒▒▒█████ 216 ns

Более короткая полоса означает быстрее. Заштрихованная светлая часть каждого столбца представляет собой эталонное время, измеренное для ref_bytes(b"foo") (84 & # 8239; нс) и ref_str("foo") (100 & # 8239; нс):

def ref_bytes(data): return data
def ref_str(data): return data.encode()