-1

It seems that atomic types (int, string, ...) are passed by value, and all others (objects, pointers to functions, pointers to methods, ...) are passed by reference.

What is the best way to check if a variable will be passed by value or by reference?

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

seems to be very inelegant.

The reason why I need it is below: I have a class that wraps wx.Button, if args/kwargs are of types that are passed by value, updating their values in other objects will not be taken into account. So some checks will be beneficial

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)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Yulia V
  • 3,507
  • 10
  • 31
  • 64
  • 4
    [What are you actually trying to achieve with this?](http://meta.stackexchange.com/q/66377) –  Nov 28 '12 at 11:42
  • 2
    See [Python: How do I pass a variable by reference?](http://stackoverflow.com/q/986006). You don't. – Martijn Pieters Nov 28 '12 at 11:49
  • If you keep the same variable in 2 "places", variables passed by reference won't be updated in the 2nd "place" if they are changed in the first "place" and it will cause a problem. Variables passed by reference will be updated, and it will work fine. So some checking would be beneficial... – Yulia V Nov 28 '12 at 11:52
  • 1
    You'd have to check at the type of the object passed and see if it's a mutable container. Of course, it may be something your code knows nothing about..., but if it is that would tell you. – martineau Nov 28 '12 at 12:07
  • @Martijn Pieters : I need it for ain interface class, this class uses wx. I thought that mention of wx would make my question too narrow. – Yulia V Nov 28 '12 at 12:08
  • @martineau: yes, this is what I am trying to do, but there are many types that will be updated: classes, sequences, ... I thought that the list of atomics will be shorter. – Yulia V Nov 28 '12 at 12:11
  • An elegant way of implementing what you want might be to use the idea in [this](http://stackoverflow.com/questions/305359/correct-way-to-detect-sequence-parameter/306222#306222) answer and create your own custom abstract meta-class for mutable containers. One nice thing about it is that it's easily extensible to additional existing or new types as needed. – martineau Nov 28 '12 at 12:27

2 Answers2

11

The question does not arise. Everything is passed in exactly the same way, regardless of type, value, operating system, phase of the moon, etc.

Whether that style of argument passing is best described as pass by value, pass by reference, or something else, is up for debate (though note that using "pass by value/reference" requires non-standard definitions of "value"/"reference", which is the primary reasoning for other terms such as "pass by object"). It doesn't matter here. It's just always the same.

Edit: In terms of your example, the semantics of handler doesn't change based on the argument types. Either is assigns to the variables (AKA names):

def my_handler(x):
    x = <whatever>

... but then my_handler(<anything>) does not change what object the argument refers to (and it doesn't matter either if you pass in a local variable, an object attribute, the result of a more complex expression, or anything else). By the way, everything is an object, your artificial distinctions ("atomic", "pointers to functions") make no sense.

Alternatively, the function (tries to) change the value of the objects (e.g. add/remove items to a collection, change an object attribute, call a method that changes some state that can be observed indirectly). That may raise exceptions if the object does not support that (e.g. call a method that does not exist), but that happens for any access, not just for mutation. If the object's value is indeed changed, this is always visible through every reference to that object. As new references to existing objects are created in a number of cases (such as argument passing, variable assignment, attribute assignment, etc.) you can observe that objects are not copied by changing their value in one place and observing the change in another place. This is true for all objects (again, provided you can change the object's value).

Now, some objects are immutable, which (by definition) means you can't change their value, and hence can't observe the object "sharing" in this way (you can observe it in other ways though). That doesn't mean assignment has different semantics depending on mutability (it doesn't), it just means you can do things with mutable objects which you can't do with immutable objects. The operations you can perform on both work the same for both.

  • If you keep the same variable in 2 "places", variables passed by reference won't be updated in the 2nd "place" if they are changed in the first "place" and it will cause a problem. Variables passed by reference will be updated, and it will work fine. So some checking would be beneficial... I probably should have put more details in my initial question... – Yulia V Nov 28 '12 at 11:52
  • @delnan: yes I know, I need it for a different reason. – Yulia V Nov 28 '12 at 11:54
  • @YuccaV That is false. There is no such difference. If you believe you have proof, show it so we can point out the error. –  Nov 28 '12 at 11:58
  • @delnan: not sure what is false in my comment; I was just explaining the reason for asking my question, not making any statement. I have put more details in my initial question, hopefully it is clearer now. – Yulia V Nov 28 '12 at 12:07
  • @YuccaV Your assumption that there is a difference is false. I'll edit to address your specific example. –  Nov 28 '12 at 12:14
  • Well, I have run into a bug because there is a difference. I have an object with a field of type string, had args (myObject.myString, ), then, when I was changing myObject.myString dynamically, it was not getting updated in args. Changing myObject.myString to myObject.getMyString (a callable) helped. So there is a difference. – Yulia V Nov 28 '12 at 13:18
  • Well, this bug did happen, I do not drink vodka for breakfast. Will try to provide a reduced size example later (I have to do some work for my employer) – Yulia V Nov 28 '12 at 13:23
-1

If you really have the need to change the value of a variable passed to you, you can wrap it in an array to implement a passing-by-reference in the process:

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

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

In some cases this can be a (warty) solution to a problem like yours.

But in general, all values are passed by reference in Python (in the sense that no copies are created); some values are just immutable (like ints, strings, tuples, …). You might be confused by assigning a new value to the parameter variable — that definitely won't change the value which was in the parameter variable before, it just overwrites it with a new one (and thus removes additional reference to the original value). That is why the example above does not assign anything to i_var but something to i_var[0].

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • Any downvote should come with a comment which describes the reasons for the downvote (which should be different from the aspects already named in the solution itself). I know and wrote that this solution has drawbacks, but it definitely can of use in cases in which other options cannot be chosen, even if it is ugly and slightly C-ish. – Alfe Mar 05 '13 at 09:14