Ho scritto la seguente semplice classe come, effettivamente, un modo per emulare un puntatore in 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)
Ecco un esempio di utilizzo (da una pagina del taccuino 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]
Naturalmente, è anche facile farlo funzionare per elementi di comando o attributi di un oggetto. C'è anche un modo per fare ciò che l'OP ha richiesto, 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)
Verrà stampato 2, seguito da 3.
Pasticciare con lo spazio dei nomi globale in questo modo è una pessima idea in modo trasparente, ma mostra che è possibile (se sconsigliabile) fare ciò che l'OP ha chiesto.
L'esempio è, ovviamente, abbastanza inutile. Ma ho trovato questa classe utile nell'applicazione per la quale l'ho sviluppata: un modello matematico il cui comportamento è governato da numerosi parametri matematici impostabili dall'utente, di diverso tipo (che, poiché dipendono da argomenti della riga di comando, non sono noti in fase di compilazione). E una volta che l'accesso a qualcosa è stato incapsulato in un oggetto Parameter, tutti questi oggetti possono essere manipolati in modo uniforme.
Sebbene non assomigli molto a un puntatore C o C ++, questo risolve un problema che avrei risolto con i puntatori se stessi scrivendo in C ++.