Хотя передача по ссылке - это не то, что хорошо вписывается в python и должно использоваться редко, есть некоторые обходные пути, которые действительно могут работать, чтобы получить объект, в настоящее время назначенный локальной переменной, или даже переназначить локальную переменную внутри вызываемой функции.
Основная идея состоит в том, чтобы иметь функцию, которая может осуществлять такой доступ и может быть передана как объект в другие функции или сохранена в классе.
Одним из способов является использование global
(для глобальных переменных) или nonlocal
(для локальных переменных в функции) в функции-обертке.
def change(wrapper):
wrapper(7)
x = 5
def setter(val):
global x
x = val
print(x)
Та же идея работает для чтения и del
создания переменной.
Для простого чтения существует даже более короткий способ использования lambda: x
, который возвращает вызываемый объект, который при вызове возвращает текущее значение x. Это что-то вроде «звонка по имени», используемого в языках далекого прошлого.
Передача 3-х оболочек для доступа к переменной немного громоздка, поэтому их можно обернуть в класс с атрибутом proxy:
class ByRef:
def __init__(self, r, w, d):
self._read = r
self._write = w
self._delete = d
def set(self, val):
self._write(val)
def get(self):
return self._read()
def remove(self):
self._delete()
wrapped = property(get, set, remove)
# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15
Поддержка «отражения» Pythons позволяет получить объект, который способен переназначать имя / переменную в заданной области, не определяя функции явно в этой области:
class ByRef:
def __init__(self, locs, name):
self._locs = locs
self._name = name
def set(self, val):
self._locs[self._name] = val
def get(self):
return self._locs[self._name]
def remove(self):
del self._locs[self._name]
wrapped = property(get, set, remove)
def change(x):
x.wrapped = 7
def test_me():
x = 6
print(x)
change(ByRef(locals(), "x"))
print(x)
Здесь класс ByRef
оборачивает доступ к словарю. Таким образом, атрибут доступа к wrapped
переводится на доступ к элементу в переданном словаре. Передав результат встроенного locals
и имя локальной переменной, вы получите доступ к локальной переменной. Документация Python от 3.5 советует, что изменение словаря может не сработать, но мне кажется, что оно работает.