How to create new closure cell objects?

前端 未结 3 1079
迷失自我
迷失自我 2021-01-15 01:41

I need to monkey-patch my library to replace an instance of a symbol, and it\'s getting referenced by some function closures. I need to copy those functions (since I also ne

相关标签:
3条回答
  • 2021-01-15 02:05

    If you want an empty cell (which is what I found this question for) (One where referencing it raises a NameError: free variable '...' referenced before assignment in enclosing scope and accessing it's cell.cell_contents raises a ValueError: Cell is empty), you can make a value a local variable, but never let it be assigned:

    def make_empty_cell():
        if False:
            # Any action that makes `value` local to `make_empty_cell`
            del value
        return (lambda: value).__closure__[0]
    

    You can combine them like this:

    _SENTINEL = object()
    
    def make_cell(value=_SENTINEL):
        if value is not _SENTINEL:
            x = value
        return (lambda: x).__closure__[0]
    

    So calling with no arguments returns an empty cell, and with any value, a cell with that value.

    If you don't care about empty cells, you can do:

    def make_cell(value):
        return (lambda: value).__closure__[0]
    

    Note that it is func_closure in older Python 2, instead of __closure__.

    0 讨论(0)
  • 2021-01-15 02:14

    The simple way to make a closure cell would be to make a closure:

    def make_cell(val=None):
        x = val
        def closure():
            return x
        return closure.__closure__[0]
    

    If you want to reassign an existing cell's contents, you'll need to make a C API call:

    import ctypes
    PyCell_Set = ctypes.pythonapi.PyCell_Set
    
    # ctypes.pythonapi functions need to have argtypes and restype set manually
    PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object)
    
    # restype actually defaults to c_int here, but we might as well be explicit
    PyCell_Set.restype = ctypes.c_int
    
    PyCell_Set(cell, new_value)
    

    CPython only, of course.

    0 讨论(0)
  • 2021-01-15 02:24

    in lambda:

    def make_cell(value):
        fn = (lambda x: lambda: x)(value)
        return fn.__closure__[0]
    

    got anwer from https://github.com/nedbat/byterun/blob/master/byterun/pyobj.py#L12

    0 讨论(0)
提交回复
热议问题