Escribí la siguiente clase simple como, efectivamente, una forma de emular un puntero en Python:
class Parameter:
"""Syntactic sugar for getter/setter pair
Usage:
p = Parameter(getter, setter)
Set parameter value:
p(value)
p.val = value
p.set(value)
Retrieve parameter value:
p()
p.val
p.get()
"""
def __init__(self, getter, setter):
"""Create parameter
Required positional parameters:
getter: called with no arguments, retrieves the parameter value.
setter: called with value, sets the parameter.
"""
self._get = getter
self._set = setter
def __call__(self, val=None):
if val is not None:
self._set(val)
return self._get()
def get(self):
return self._get()
def set(self, val):
self._set(val)
@property
def val(self):
return self._get()
@val.setter
def val(self, val):
self._set(val)
Aquí hay un ejemplo de uso (de una página de cuaderno de jupyter):
l1 = list(range(10))
def l1_5_getter(lst=l1, number=5):
return lst[number]
def l1_5_setter(val, lst=l1, number=5):
lst[number] = val
[
l1_5_getter(),
l1_5_setter(12),
l1,
l1_5_getter()
]
Out = [5, None, [0, 1, 2, 3, 4, 12, 6, 7, 8, 9], 12]
p = Parameter(l1_5_getter, l1_5_setter)
print([
p(),
p.get(),
p.val,
p(13),
p(),
p.set(14),
p.get()
])
p.val = 15
print(p.val, l1)
[12, 12, 12, 13, 13, None, 14]
15 [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]
Por supuesto, también es fácil hacer que esto funcione para dict elementos o atributos de un objeto. Incluso hay una forma de hacer lo que pidió el OP, usando globals ():
def setter(val, dict=globals(), key='a'):
dict[key] = val
def getter(dict=globals(), key='a'):
return dict[key]
pa = Parameter(getter, setter)
pa(2)
print(a)
pa(3)
print(a)
Esto imprimirá 2, seguido de 3.
Jugar con el espacio de nombres global de esta manera es, de manera transparente, una idea terrible, pero muestra que es posible (si no es aconsejable) hacer lo que pidió el OP.
El ejemplo es, por supuesto, bastante inútil. Pero he encontrado que esta clase es útil en la aplicación para la que la desarrollé: un modelo matemático cuyo comportamiento se rige por numerosos parámetros matemáticos configurables por el usuario, de diversos tipos (que, debido a que dependen de argumentos de línea de comando, no se conocen en tiempo de compilación). Y una vez que el acceso a algo se ha encapsulado en un objeto de parámetro, todos esos objetos se pueden manipular de manera uniforme.
Aunque no se parece mucho a un puntero C o C ++, esto está resolviendo un problema que habría resuelto con punteros si estuviera escribiendo en C ++.