GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add `.take_bytes([n])` a zero-copy path from `bytearray` to `bytes` · Issue #139871 · python/cpython

Add .take_bytes([n]) a zero-copy path from bytearray to bytes #139871

New issue
Copy link
New issue
Copy link
Closed
Closed
Add .take_bytes([n]) a zero-copy path from bytearray to bytes#139871
Copy link
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancementA feature request or enhancement

Description

@cmaloney
cmaloney
opened on Oct 9, 2025
Issue body actions

Feature or enhancement

Proposal:

Update bytearray to have its internal buffer always be a PyBytesObject and add a new method, .take_bytes([n]) which extracts that buffer.

.take_bytes([n]) adds a way to go from a "mutable" buffer of bytes to an immutable one without requiring a memcpy.

This creates a path to resolve gh-60107

When would I use this?

Any code which makes a ba = bytearray(), modifies it, then calls bytes(ba). Other common patterns are bytes(ba); ba.clear() or bytes(ba[:n]); del ba[:n]. Note that if you want to discard data past a point, the most efficient pattern becomes ba.resize(n); ba.take_bytes() so that take_bytes([n]) doesn’t need to keep around the soon to be discarded extra bytes.

Has this already been discussed elsewhere?

I have already discussed this feature proposal on Discourse

Links to previous discussion of this feature:

https://discuss.python.org/t/add-take-bytes-n-to-bytearray-providing-a-zero-copy-path-to-bytes/103804/5
https://discuss.python.org/t/add-zero-copy-conversion-of-bytearray-to-bytes-by-providing-bytes/79164 -- edit: added

Linked PRs

  • gh-139871: Add bytearray.take_bytes([n]) to efficiently extract bytes #140128
  • gh-139871: Add _PyByteArray_empty_string to the stable ABI #140770
  • gh-139871: Optimize small takes in bytearray.take_bytes #141741
  • gh-139871: Optimize bytearray unique bytes iconcat #141862
  • gh-139871: Optimize bytearray construction with encoding #142243
  • gh-139871: Fix 3.15 bytearray.take_bytes example #149520
  • [3.15] gh-139871: Fix 3.15 bytearray.take_bytes example (GH-149520) #149622
Reacted by msmojtabafar

Activity

  1. cmaloney
    added
    type-featureA feature request or enhancementA feature request or enhancement
    on Oct 9, 2025
  2. StanFromIreland
    added
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    on Oct 9, 2025
  3. cmaloney
    added a commit that references this issue on Oct 14, 2025

    pythongh-139871: Update bytearray to contain PyBytesObject

    daf8e02
  4. vstinner
    added a commit that references this issue on Oct 29, 2025

    pythongh-139871: Add _PyByteArray_empty_string to the stable ABI

    cea1297
  5. serhiy-storchaka commented on Oct 29, 2025

    @serhiy-storchaka
    serhiy-storchaka
    on Oct 29, 2025
    Member
    More actions

    See my arguments against this idea: https://discuss.python.org/t/add-zero-copy-conversion-of-bytearray-to-bytes-by-providing-bytes/79164/15

    It will not work because it is not compatible with the C API.

    PyByteArray_AS_STRING() cannot return a reference to the bytes object returned by take_bytes(), because it can be mutated. PyByteArray_AS_STRING() cannot allocate a new bytes object, because it never fails, but a memory allocation can fail. The only solution is if take_bytes() allocates a new bytes object, but this kills its purpose.

  6. cmaloney commented on Oct 30, 2025

    @cmaloney
    cmaloney
    on Oct 30, 2025
    ContributorAuthor
    More actions

    The implementation for this issue is related to that initial discussion thread but iterated on with your feedback incorporated. The final form is in: https://discuss.python.org/t/add-take-bytes-n-to-bytearray-providing-a-zero-copy-path-to-bytes/103804. The initial post there still talks about PyBytesWriter but after further discussion consensus reached using PyBytesObject directly.

    In particular with the current design the bytes object inside bytearray is either the empty bytes constant or a uniquely referenced bytes object. That bytes object is only exposed if a user calls .take_bytes([n]) and it returns successfully. There is no __bytes__ function or similar which exposes the internal to bytearray PyObject*.

    For the particular points:

    1. re: PyByteArray_AS_STRING(): This is equivalent to .clear() and other operations that resize the bytearray. A pointer stashed from PyByteArray_AS_STRING() before a length-mutating operation (ex. .clear()) is not valid after. The implementation of take_bytes([n]) does the same checks as .clear(): Working inside a critical section / lock so only one resizing operation may be in progress at a time and checking ob_exports == 0. There is a free threading test added to help validate correctness.
    2. re: Allocation failures: The current implementation changes bytearray to always contain bytes, by default Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);. _PyBytes_Resize's existing implementation handles resizing from empty bytes to larger by allocating a new bytes, resizing to 0 by changing to the empty bytes constant, and resizing in other cases by ensuring the bytes is uniquely referenced before performing any in-place mutation. If a _PyBytes_Resize fails for any reason the bytearray is kept in a good state by re-initializing itself with the empty bytes object. For ba.take_bytes([n]) in particular ba will end in one of these states:
      a. pointing to a new bytes object with all the bytes after n (successfully completed)
      b. It errors before getting to the actual byte taking and is left unmodified (ex. ob_exports != 0 so it can't be resized)
      c. A mid-resizing error occurs and ba is set to the empty bytes constant, an exception is raised, and NULL is returned.
  7. vstinner commented on Oct 30, 2025

    @vstinner
    vstinner
    on Oct 30, 2025
    Member
    More actions

    PyByteArray_AS_STRING() cannot return a reference to the bytes object returned by take_bytes(), because it can be mutated.

    I'm not sure that I understand your concern. PyByteArray.ob_bytes_object is private and cannot be accessed (especially in Python). Yes, the ob_bytes_object object is mutated: bytes can be modified and its size can change via bytearray operation (bytearray += bytes, bytearray.resize(), etc.). But I don't see how this is an issue, mutating a bytes object is done by all functions using the soft deprecated PyBytes_FromStringAndSize(NULL, size). PEP 782 implementation uses PyBytesWriter in many cases to avoid that, but PyBytesWriter is implemented internally by ... mutating a bytes object :-)

    bytearray.take_bytes() replaces its ob_bytes_object object with a new (empty) one. The returned bytes object should now be treated as immutable.

  8. vstinner commented on Oct 30, 2025

    @vstinner
    vstinner
    on Oct 30, 2025
    Member
    More actions

    Links to previous discussion of this feature:
    https://discuss.python.org/t/add-take-bytes-n-to-bytearray-providing-a-zero-copy-path-to-bytes/103804/5

    That was in September. There is also the older discussion (February): https://discuss.python.org/t/add-zero-copy-conversion-of-bytearray-to-bytes-by-providing-bytes/79164

  9. encukou
    added a commit that references this issue on Nov 13, 2025

    gh-139871: Add `bytearray.take_bytes([n])` to efficiently extract `by…

    732224e
  10. cmaloney
    closed this as completedon Nov 13, 2025
  11. CuriousLearner
    added 3 commits that reference this issue on Nov 13, 2025

    Merge branch 'main' into fix-issue21914

    b9f473c

    Merge branch 'main' of github.com:python/cpython into fix-Issue18387

    c46ecc5

    Merge branch 'main' of github.com:python/cpython into fix-issue24255

    c240289
  12. cmaloney
    added 2 commits that reference this issue on Nov 19, 2025

    pythongh-139871: Optimize small takes in bytearray.take_bytes

    2394b6c

    pythongh-139871: Optimize small takes in bytearray.take_bytes

    783717c
  13. encukou
    added a commit that references this issue on Nov 20, 2025

    gh-139871: Optimize small takes in bytearray.take_bytes (GH-141741)

    e265ce8
  14. cmaloney
    added 3 commits that reference this issue on Nov 20, 2025

    pythongh-139871: Optimize bytearray unique bytes iconcat

    5ea2bf3

    pythongh-139871: Optimize bytearray unique bytes iconcat

    db4c09a

    pythongh-141863: Use bytearray.take_bytes in asyncio.streams

    0b150fc
  15. cmaloney
    added a commit that references this issue on Dec 3, 2025

    pythongh-139871: Optimize bytearray construction with encoding

    783c0b1
  16. StanFromIreland
    added 2 commits that reference this issue on Dec 6, 2025

    pythongh-139871: Add `bytearray.take_bytes([n])` to efficiently extra…

    324e322

    pythongh-139871: Optimize small takes in bytearray.take_bytes (python…

    5f6b0c3
  17. ashm-dev
    added a commit that references this issue on Dec 8, 2025

    pythongh-139871: Optimize small takes in bytearray.take_bytes (python…

    1b0326a
  18. vstinner
    added a commit that references this issue on Dec 15, 2025

    gh-139871: Optimize bytearray construction with encoding (#142243)

    14e6052
  19. fatelei
    added a commit that references this issue on Dec 16, 2025

    pythongh-139871: Optimize bytearray construction with encoding (pytho…

    7ca6d17
  20. cmaloney
    added 2 commits that reference this issue on May 7, 2026

    pythongh-139871: Fix 3.15 bytearray.take_bytes example

    f69ca1c

    pythongh-139871: Fix 3.15 take_bytes whats new example

    dbc225a
  21. JelleZijlstra
    added 2 commits that reference this issue on May 9, 2026

    gh-139871: Fix 3.15 bytearray.take_bytes example (#149520)

    cc5cf14

    [3.15] gh-139871: Fix 3.15 bytearray.take_bytes example (GH-149520) (#…

    6ba3ea4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancementA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.