1

This probably fits more a discussion group, but I'm not proficient in the innards of the language (or even the language itself). In any case, what's bugging me is:

If python is allowing interference (side effects) with outer scope using the nonlocal keyword, then why does it not allow a similar interference with function arguments by permitting passing arguments by reference:

Possible right now:

>>> def outer():
       x = 1
       def inner():
           nonlocal x
           x = 2
           print("inner:", x)
       inner()
       print("outer:", x)

>>> outer()
inner: 2
outer: 2

Why not - or what could go wrong if we had:

>>> def outer():
       x = 1
       def inner(byref x):
           x = 2
           print("inner:", x)
       inner(x)
       print("outer:", x)

>>> outer()
inner: 2
outer: 2

(using some keyword like 'byref' or 'nonlocal, just for illustration).

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Basel Shishani
  • 7,735
  • 6
  • 50
  • 67

4 Answers4

2

Python always passes parameters using reference value. Refer to this link here and especially rad the detailed response provided by the user pepr

Also this link has pretty detailed discussion on how exactly parameters are passed within python and also pass-by-reference can be simulated - refer to the EDIT of the accepted answer to this question.

In case, you want to delve deeper - please refer to this Effbot article that also contains some debate/discussions around the same topic.

Community
  • 1
  • 1
Prahalad Deshpande
  • 4,709
  • 1
  • 20
  • 22
  • 1
    **Why** did Python designers consider it not a good idea to provide a standard mechanism to allow the function to change the reference target of the outer name. – Basel Shishani Aug 20 '13 at 07:24
  • That's a good question, and my guess is that it was whiners coming from Java(Script) who couldn't handle programming without access to namespace fudging that convinced them to go that route. Note that in real Python (2.7), it definitely is not allowed. I should mention that the lack of keywords in function args is probably aesthetic as much as anything. It's been avoided thus far, Guido's not going to put it in for something as trivial as symmetry across from something as dumb as `nonlocal`. – a p Aug 20 '13 at 07:43
  • @ap Python is older than both Java and JavaScript: its first release was in 1991 (Java and JS were released in 1995). And its semantics are even older, dating back to ABC in the 1980s. – Daniel Roseman Aug 20 '13 at 08:15
  • @Daniel That's true! And my suspicion is that, were it not for the relative rise in popularity of these and other languages since that original inception date, 3.x (which came decidedly after them) might not have incorporated the in-my-mind-ugly-and-mostly-useless `nonlocal`. *edit* I'm losing internet points over this! help! – a p Aug 20 '13 at 08:32
1

This is not possible because Python does not have a concept of "variable" at all. All the names in a Python program are references to objects. So you can only pass a reference to an object when calling a function or method. This is called passing by reference value.

However, it is not possible to obtain a reference to an existing reference. In this respect, references are the only "non first class" citizens in the Python world.

There are two kinds of objects referenced by names in a program: immutable (e.g. string, int, tuple) an mutable (e.g. list, set, most user classes).

You can call methods on mutable objects that in fact modify the objects state, and this looks similar to passing a reference to the object in a language such as C++. Beyond that, the passing by reference does not make much sense in Python.

See Prahalad Deshpande's answer for some links.

Ber
  • 40,356
  • 16
  • 72
  • 88
  • "Python does not have a concept of "variable" at all." Of course it does. Same as in Java, C, Smalltalk, Ruby, pretty much all other languages. – newacct Aug 20 '13 at 22:49
  • @newacct No, it does not. It only has reference to objects on the heap. This is fundamental to Python's dynamic type system. If you write `x=2` and later `x='abc'` the reference `x` will refer to two distinct objects of different types, which may exist independent of the reference and by be referred to by other references. – Ber Aug 21 '13 at 09:52
  • So? How does this make it not have variables? `x` is a variable. Its value is a reference, because all values in Python are references. In Java, you can also write `Object x = 2;` and later `x = "abc";` and `x` will point to two distinct objects of different types. Does that make `x` in Java not a variable? – newacct Aug 22 '13 at 10:37
1

Suppose you do allow reference arguments. What happens, then, when you do the following?

def f(byref x):
    print x
    print x
    x = 3

class Foo(object):
    def __init__(self):
        self.count = 0
    @property
    def x(self):
        count += 1
        return count

f(Foo().x)

When is the getter called? How many times is it called? Does this print 1 twice, or does it print 1, then 2, or 2, then 3? Since there's no setter, what happens when you try to assign to x?

In another language, where variables are places to put things instead of names for values, this wouldn't be a problem. Foo().x would have a memory location once evaluated, and f would use that memory location for its x argument. In Python, it doesn't work like that. You can't pass in the memory location of 1 and change its contents, because then other code will find that 1 is magically 2 all of a sudden. Python's name semantics and attribute/item getter/setters make reference arguments even more confusing than in languages like C++, where they're already confusing and bug-prone.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Byrefs can be limited (in concept) to immutable types because that's where they are useful. This will cut the convoluted side effects and unnecessary semantics (e.g refs to lists and dicts). Can't say though if such a check is possible/reasonable according to Python internals. – Basel Shishani Aug 20 '13 at 08:56
  • 2
    @BaselShishani: The problem there is that variables don't have types. Values have types. If you pass `3` by reference, that offers no benefits over what Python already does, since you can't turn that `3` into a `4`. If you pass an lvalue that evaluates to `3` by reference, then you either have to restrict all reference arguments to simple variables (and lose much of the power of reference arguments), or you have to deal with nasty getter/setter semantics. – user2357112 Aug 20 '13 at 09:56
  • "In another language, where variables are places to put things instead of names for values," There are other languages with both properties and pass-by-reference. For example, C#. C# disallows you to pass a property by reference. The difference between C# and Python is that in C#, attributes and properties are declared so you know when you see a dot syntax whether it's a property; whereas Python is much more dynamic and all attribute access is through methods like `.__getattr__()` and `.__setattr__()`, so it is much harder to check. I think that's really what you're trying to say. – newacct Aug 20 '13 at 23:03
0

In Python int objects are immutable. When you think you are changing the value of x, you are really creating a new int at a different memory location and getting x to reference that.

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • okay fine, so this is the internal working of it, and there are few questions here on SO discussing that. But what's preventing us from using the same technique to simulate passing by reference - i.e create a new object and let the inner function alter the reference of the outer name? Similar to what nonlocal is doing. – Basel Shishani Aug 20 '13 at 06:47
  • @BaselShishani, nothing. For example you can pass `x = [1]`, and then say `x[0] = 2`, but you can't hide the fact that `x` isn't really an int anymore – John La Rooy Aug 20 '13 at 06:53
  • @BaselShishani This is much more than an implementation detail. It's the fundamental concept of how Python treats references to its objects. This is very different from the concept in languages such as C++ or Java. – Ber Aug 20 '13 at 07:25
  • In java you also always pass references by value. In C too. My feeling is that the number of languages that allow pass by modifiable references are actually in minority – Antti Haapala -- Слава Україні Aug 20 '13 at 07:46
  • @downvoter. You can downvote all you like but it's not going to change how Python references work. I save my downvotes for answers that are wrong. – John La Rooy Aug 20 '13 at 23:46
  • @AnttiHaapala In C there is no such thing as a reference. You have variables which may be pointers to other variables. You can pass any such variable by value or you can pass a pointer to simulate "by reference". In C++ you gain a way to pass a reference, but this is not a proper type as it works only in method parameter lists. So in C++ you also do not have a reference like in Python. So here is a very string distinction between Python an the C family of languages. – Ber Aug 21 '13 at 09:47