Python: как проверить, является ли тип аргумента таким, что он будет передан по значению или по ссылке?

Кажется, что атомарные типы (int, string,...) передаются по значению, а все остальные (объекты, указатели на функции, указатели на методы,...) передаются по ссылке.

Как лучше всего проверить, будет ли переменная передаваться по значению или по ссылке?

isinstance(input_, float) or isinstance(input_, basestring) or <...>

выглядит очень некрасиво.

Причина, по которой мне это нужно, ниже: у меня есть класс, который обертывает wx.Button, если args/kwargs имеют типы, которые передаются по значению, обновление их значений в других объектах не будет учитываться. Так что некоторые проверки будут полезны

class PalpyButton(wx.Button):        
    def __init__(self, parent, btnLabel, handler, successMsg = None, args = (), kwargs = {}):
        super(PalpyButton, self).__init__(parent, -1, btnLabel)
        self.handler = handler
        self.successMsg = successMsg
        parent.Bind(wx.EVT_BUTTON, lambda event: self.onClick(event, *args, **kwargs), self)
    def onClick(self, event, *args, **kwargs):
        try:
            self.handler(*args, **kwargs)
            if self.successMsg != None:
                if hasattr(self.successMsg, '__call__'):
                    showInfoMessageBox(self.successMsg())
                else:
                    showInfoMessageBox(self.successMsg)
        except BaseException, detail:
            showErrorMessageBox(detail)

person Yulia V    schedule 28.11.2012    source источник
comment
См. раздел Python: как передать переменную по ссылке?. Вы не знаете.   -  person Martijn Pieters    schedule 28.11.2012
comment
Если вы сохраните одну и ту же переменную в двух местах, переменные, переданные по ссылке, не будут обновляться во втором месте, если они были изменены в первую очередь, и это вызовет проблему. Переменные, переданные по ссылке, будут обновлены, и все будет работать нормально. Так что проверка не помешала бы...   -  person Yulia V    schedule 28.11.2012
comment
Вам нужно будет проверить тип переданного объекта и посмотреть, является ли он изменяемым контейнером. Конечно, это может быть что-то, о чем ваш код ничего не знает..., но если это так, это скажет вам.   -  person martineau    schedule 28.11.2012
comment
@Martijn Pieters: мне это нужно для класса интерфейса, этот класс использует wx. Я думал, что упоминание wx сделает мой вопрос слишком узким.   -  person Yulia V    schedule 28.11.2012
comment
@martineau: да, это то, что я пытаюсь сделать, но есть много типов, которые будут обновлены: классы, последовательности, ... Я думал, что список атомов будет короче.   -  person Yulia V    schedule 28.11.2012
comment
Элегантным способом реализации того, что вы хотите, может быть использование идеи в этом ответьте и создайте свой собственный абстрактный метакласс для изменяемых контейнеров. Одна приятная вещь в этом заключается в том, что его легко расширять до дополнительных существующих или новых типов по мере необходимости.   -  person martineau    schedule 28.11.2012


Ответы (2)


Вопрос не возникает. Все передается одинаково, независимо от типа, значения, операционной системы, фазы луны и т. д.

Вопрос о том, лучше ли описать этот стиль передачи аргументов как передача по значению, по ссылке или как-то еще, подлежит обсуждению (хотя обратите внимание, что использование «передачи по значению/ссылке» требует нестандартных определений «значение»/«ссылка». ", что является основным аргументом в пользу других терминов, таких как "проход мимо объекта"). Здесь это не имеет значения. Просто всегда одно и то же.

Изменить. В вашем примере семантика handler не меняется в зависимости от типов аргументов. Либо присваивается переменным (именам AKA):

def my_handler(x):
    x = <whatever>

... но тогда my_handler(<anything>) не меняет, на какой объект ссылается аргумент (и не имеет значения, если вы передаете локальную переменную, атрибут объекта, результат более сложного выражения или что-то еще). Кстати, всё является объектом, ваши искусственные разграничения ("атомарные", "указатели на функции") не имеют смысла.

В качестве альтернативы функция (пытается) изменить значение объектов (например, добавить/удалить элементы в коллекцию, изменить атрибут объекта, вызвать метод, который изменяет некоторое состояние, которое можно наблюдать косвенно). Это может вызвать исключения, если объект не поддерживает это (например, вызов метода, который не существует), но это происходит для любого доступа, а не только для мутации. Если значение объекта действительно изменилось, это всегда видно через каждую ссылку на этот объект. Поскольку в ряде случаев создаются новые ссылки на существующие объекты (такие как передача аргументов, присвоение переменных, присвоение атрибутов и т. д.), вы можете наблюдать, что объекты не копируются, изменяя их значение в одном месте и наблюдая за изменением в другом месте. . Это верно для всех объектов (опять же, при условии, что вы можете изменить значение объекта).

Теперь некоторые объекты являются неизменяемыми, что (по определению) означает, что вы не можете изменить их значение и, следовательно, не можете наблюдать «совместное использование» объекта таким образом (хотя вы можете наблюдать это другими способами). Это не означает, что присваивание имеет различную семантику в зависимости от изменчивости (это не так), это просто означает, что вы можете делать с изменяемыми объектами то, что вы не можете делать с неизменяемыми объектами. Операции, которые вы можете выполнять на обоих, работают одинаково для обоих.

person Community    schedule 28.11.2012
comment
Если вы сохраните одну и ту же переменную в двух местах, переменные, переданные по ссылке, не будут обновляться во втором месте, если они были изменены в первую очередь, и это вызовет проблему. Переменные, переданные по ссылке, будут обновлены, и все будет работать нормально. Так что некоторая проверка была бы полезной... Вероятно, мне следовало указать больше деталей в моем первоначальном вопросе... - person Yulia V; 28.11.2012
comment
@delnan: да, я знаю, мне это нужно по другой причине. - person Yulia V; 28.11.2012
comment
@YuccaV Это неверно. Нет такой разницы. Если вы считаете, что у вас есть доказательства, покажите их, чтобы мы могли указать на ошибку. - person ; 28.11.2012
comment
@delnan: не уверен, что в моем комментарии ложь; Я просто объяснил причину моего вопроса, не делая никаких утверждений. Я добавил больше деталей в свой первоначальный вопрос, надеюсь, теперь это яснее. - person Yulia V; 28.11.2012
comment
@YuccaV Ваше предположение о том, что есть разница, неверно. Я отредактирую ваш конкретный пример. - person ; 28.11.2012
comment
Ну, я столкнулся с ошибкой, потому что есть разница. У меня есть объект с полем типа string, имел аргументы (myObject.myString,), затем, когда я динамически изменял myObject.myString, он не обновлялся в аргументах. Помогло изменение myObject.myString на myObject.getMyString (вызываемый). Так что есть разница. - person Yulia V; 28.11.2012
comment
Ну, этот баг все-таки случился, я водку на завтрак не пью. Позже постараюсь предоставить пример уменьшенного размера (мне нужно выполнить некоторую работу для моего работодателя) - person Yulia V; 28.11.2012

Если вам действительно нужно изменить значение переданной вам переменной, вы можете обернуть ее в массив, чтобы реализовать передачу по ссылке в процессе:

def increaseInt(i_var):
  i_var[0] += 1

i_ref = [42]
increase(i_ref)
print i_ref[0]  # will print 43

В некоторых случаях это может быть (бородавчатым) решением проблемы, подобной вашей.

Но в целом все значения в Python передаются по ссылке (в том смысле, что копии не создаются); некоторые значения просто неизменяемы (например, целые числа, строки, кортежи, …). Вы можете запутаться, присвоив новое значение переменной параметра — это точно не изменит значение, которое было в переменной параметра раньше, оно просто перезапишет его новым (и, таким образом, уберет дополнительную ссылку на исходное значение). Вот почему в приведенном выше примере ничего не присваивается i_var, а что-то присваивается i_var[0].

person Alfe    schedule 28.11.2012
comment
Любое отрицательное голосование должно сопровождаться комментарием, описывающим причины отрицательного голосования (которые должны отличаться от аспектов, уже названных в самом решении). Я знаю и писал, что у этого решения есть недостатки, но оно определенно может быть использовано в тех случаях, когда другие варианты не могут быть выбраны, даже если оно некрасиво и немного C-ish. - person Alfe; 05.03.2013