Napisałem następującą prostą klasę jako skuteczny sposób na emulację wskaźnika w Pythonie:
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)
Oto przykład użycia (ze strony notatnika 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]
Oczywiście łatwo jest również wykonać tę pracę dla dyktowanych elementów lub atrybutów obiektu. Jest nawet sposób na zrobienie tego, o co prosił OP, używając 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)
Spowoduje to wydrukowanie 2, a następnie 3.
Majstrowanie w ten sposób z globalną przestrzenią nazw jest w pewnym sensie okropnym pomysłem, ale pokazuje, że można (jeśli jest to niewskazane) zrobić to, o co prosił OP.
Przykład jest oczywiście dość bezcelowy. Okazało się jednak, że ta klasa jest przydatna w aplikacji, dla której ją opracowałem: model matematyczny, którego zachowanie jest regulowane przez wiele ustawianych przez użytkownika parametrów matematycznych, różnego typu (które, ponieważ zależą od argumentów wiersza poleceń, nie są znane w czasie kompilacji). A gdy dostęp do czegoś zostanie zamknięty w obiekcie Parameter, wszystkimi takimi obiektami można manipulować w jednolity sposób.
Chociaż nie wygląda jak wskaźnik C lub C ++, jest to rozwiązanie problemu, który rozwiązałbym za pomocą wskaźników, gdybym pisał w C ++.