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)
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
handlerdoesn’t change based on the argument types. Either is assigns to the variables (AKA names):… 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.