Python:如何检查参数的类型是否会通过值或引用传递?

时间:2012-11-28 11:37:46

标签: python types pass-by-reference pass-by-value

似乎原子类型(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)

2 个答案:

答案 0 :(得分:11)

问题不会出现。无论类型,价值,操作系统,月相等, Everything 都以完全相同的方式传递。

参数传递的风格是否最好被描述为按值传递,通过引用或其他方式传递,是有争议的(尽管注意使用“按值传递/引用”需要非标准的“值”定义/“reference”,这是其他术语的主要推理,例如“按对象传递”)。这没关系。它总是一样的。

编辑:就您的示例而言,handler的语义不会根据参数类型而改变。要么分配变量(AKA名称):

def my_handler(x):
    x = <whatever>

...但是my_handler(<anything>)不会更改参数引用的对象(如果传入局部变量,对象属性,更复杂表达式的结果,则无关紧要)或其他任何事情)。顺便说一句,所有都是一个对象,你的人为区别(“原子”,“函数指针”)是没有意义的。

或者,函数(尝试)更改对象的(例如,向集合添加/删除项目,更改对象属性,调用可以观察到某些状态的方法)间接地)。如果对象不支持这种情况(例如调用不存在的方法),则可能引发异常,但这种情况发生在任何访问中,而不仅仅是突变。如果对象的值确实已更改,则始终通过对该对象的每个引用可见。由于在许多情况下(例如参数传递,变量赋值,属性赋值等)创建了对现有对象的新引用,您可以通过在一个位置更改其值并在另一个位置观察更改来观察不会复制对象。这适用于所有对象(同样,只要您可以更改对象的值)。

现在,一些对象是不可变的,(根据定义)意味着你不能改变它们的值,因此不能以这种方式观察对象“共享”(你可以通过其他方式观察它)。这并不意味着赋值具有不同的语义,这取决于可变性(它没有),它只是意味着你可以使用不可变对象做事,而不能用不可变对象做。您可以执行的操作对两者都起作用。

答案 1 :(得分:-1)

如果您确实需要更改传递给您的变量的值,可以将其包装在一个数组中以实现流程中的传递引用:

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]分配内容。