In python, when does pass by reference occur? [duplicate] - python

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 2 years ago.
I have a code as below,
attractions = [[] for i in range(5)]
def add_attraction(attraction):
attractions_for_destination = attractions[2]
attractions_for_destination.append(attraction)
return
pass by reference occurs in 3rd line "attractions_for_destination = attractions[2]". The general idea of pass by reference that I have is that it happens between actual parameter and formal parameter. But the above line is a simple assignment code. Can pass by reference happen in a simple assignment code?
If so, if I write
attractions_for_destination = attractions[2] + ": best attraction site"
will altering the value force the newly made variable to use a new memory space?

Saying pass by reference or pass by value isn't really applicable to python. For example consider Java. Everything in Java is pass by value, everything. However the value of an object is the reference to the object. So it is, in a way, pass by reference since mutating the object will be reflected to the calling context. Calling it "pass by value" is a bit confusing since for people used to C-family (where this distinction is more straightforward) assume that pass by value means you won't modify the underlying argument passed.
So saying Java is "pass by value" is true but possibly confusing. It is a more relevant statement at much lower levels of the language (like when talking about how the compiler handles passing arguments but not at the level of application programmer).
Python is similar. The confusion about the Java example actually lead Python to not say if it is pass by value/reference. http://stupidpythonideas.blogspot.com/2013/11/does-python-pass-by-value-or-by.html
So for programming, it is save to assume that any object is "passed by reference" (technically no but essentially yes). It is more complicated than that but that link explains it in more depth.

Related

Checking argument values at runtime in python [duplicate]

This question already has answers here:
Obtaining closures at runtime [duplicate]
(1 answer)
How to open a closure in python?
(5 answers)
Closed 2 years ago.
I would like to know if there is any method to check whether two functions have the same arguments at runtime in python 3.
Basically, I have this function (func) that takes two arguments and perform some sort of computation. I want to check whether or not a and b have the same arguments' values at runtime
a = func(2, 3)
b = func(2, 3)
a.argsvalue == b.argsvalue
It is not feasible to run the code before and check the results because I am implementing a lazy framework. My main goal is to be able to understand what are the arguments of the function because there is one variable argument that I do not care but there is one static that is created before running the function.
##EDIT
I actually solved this problem using the inspect module (getclosure) for those who are interested. Thank you so much for the comments it helped me to familiarize myself with the terminology. I was actually looking for the closure, which I assigned dynamically.
when you do this - a.argsvalue == b.argsvalue you try to access a member of the value returned from the function.
so, if your "func" would return an object having the args you called it with (which sound like a weird thing to do) you would be able to access it.
anyway, if you need these values, just store them before sending them to the function, and then you can do whatever you want with them.

locals() defined inside python function do not work [duplicate]

This question already has answers here:
Dynamically set local variable [duplicate]
(7 answers)
Any way to modify locals dictionary?
(5 answers)
Closed 2 years ago.
Consider below code:-
dct = {'one':[2,3]}
Now the below works,
for key,val in dct.items():
locals()[key] = val
print(one)
Result:
[2, 3]
But When I use function which I really want doesn't work. Please help
def ff(dct):
for key,val in dct.items():
locals()[key] = val
print(one)
ff(dct)
Result:
NameError: name 'one' is not defined
The result of the locals() call inside a function is not one that you can use to actually update locals using your method. The documentation makes that clear:
locals()
Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. Note that at the module level, locals() and globals() are the same dictionary.
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
The reason why you cannot update locals using this method is that they are heavily optimised within the CPython source code(a). When you call locals(), it actually builds a dictionary (the "update and return" bit) based on these heavily optimised structures and that is what you get.
Writing a new key to that dictionary is not reflected back to the actual locals.
I believe the globals() return value does allow updates using this method because that's already a dictionary and it just gives you a reference to it, not a copy. That's why your code works outside of a function (see the clause above stating locals() and globals() are the same thing in that context).
From memory, Python 2 allowed you to do something like exec "answer = 42" and that would affect the locals. But, as with print, this was changed from a statement to a library call in Python 3, so the execution engine really has no idea what it does under the covers, meaning it cant magically bind locals with exec("answer = 42").
I suppose someone could request this as a feature since it would make dynamic programming a little easier. Whether it would get through the gauntlet, I have no idea, since the fact that you can provide your own locals dictionary to exec() means that you already have a way to detect variables that were bound by arbitrary code. They'll just be in a separate dictionary rather then in the actual locals area.
(a) Access to locals is via known indexes into the stack-frame local variable area, computed at compile time and embedded into the actual bypte code. Being able to add/change variables dynamically would break this optimisation.
This problem was raised as an issue back in early 2009 and the outcome was that it was too difficult without losing a lot of performance.

Why does constructing a new object potentially alter the field of *every* instance of that class? [duplicate]

This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 6 years ago.
Here's a simplified version of the code in question:
class thing:
def __init__(self, data1, data2={'foo': 1}):
self.data2 = data2
self.data2['bar'] = data1
datas = ['FIRST', 'SECOND']
things = [thing(x) for x in datas]
for p in things:
print p.data2['bar']
I would expect this code to return:
FIRST
SECOND
However, it actually returns:
SECOND
SECOND
Why?
My best guess is:
that I am creating a single dictionary ur_dict = {'foo': 1},
that when I initialize an object of class thing I am not creating a new dictionary self.data2={'foo': 1} but rather initializing a reference to ur_dict,
and that when, in the constructor, I add the key-value pair bar: data1 to self.data2, I'm actually adding that key and value to ur_dict itself. This would update the data2 field of every single object in the list.
I tested this hypothesis by appending the following snippet to the code above:
things[0].data2['bar'] = 'FIRST'
for p in things:
print p.data2['bar']
Sure enough, the result is:
FIRST
FIRST
So I think my hypothesis is probably correct, but it's still mysterious to me. My question seems very related to this question --- when I create a default value in a constructor, is this value a class variable instead of an instance variable? Why doesn't python create new objects for default values of arguments in an object? Is there a good way to conceptualize or to catch this kind of error in the future? What are some good references to learn about what's going on here?
(Apologies in advance if I mangled jargon; I'm a mathematician by formal education.)
Edit: #CrazyPython[::-1] mentioned this is a property of functions, not classes or objects. I created an example of a function with a mutable default argument and I'm trying to figure out how to break it in the manner I experienced with objects and classes above. Came up with this:
EXPONENT = 1
def fooBar(x, y=EXPONENT):
return x**y
print EXPONENT
print foo(5)
EXPONENT = 2
print EXPONENT
print foo(5)
However, it returns:
1
5
2
5
What's a good way to "break" this to illustrate why not to use a mutable default argument here?
self.data2={'foo': 1} is a mutable default argument. Never do that. 99% of the time it's a mistake.
def foo(a, b={}):
...
is not equivalent to
def foo(a, b=None):
if b is None:
b = {}
b is not reconstructed every time. It's the same object.
Is there a good way to conceptualize or to catch this kind of error in the future?
Use PyCharm or another good editor
when I create a default value in a constructor, is this value a class variable instead of an instance variable?
no no no no no no. It's tied to the function, not the class or instance. This is behavior applies to all functions. It has nothing to do with classes or your linked question.
Why doesn't python create new objects for default values of arguments in an object?
Performance and compatibility. Constructing an object is a potentially expensive operation.
Addendum
Please use CamelCase for classes. Not doing so is a PEP 8 violation, which is the Python official style guide.
Get a decent editor. Personally, I recommend PyCharm. (I'm no salesperson) It's free.
PyCharm can rename variables, highlight PEP 8 errors, perform advanced auto complete, type checking, spot mutable default arguments, and much more.
You aren't inheriting off of object. That's bad.*
Why does this python code alter the field of every object in a list?
Without context, that's a bad title. It asks about the code. When we read the title, we don't have the code.
Making it more clear
When a function is stated, the default arguments are evaluated. (not when it is executed, when it is stated) They are tied to the function. When a function is executed, a copy of the default arguments is not produced. You directly modify the default arguments. The next function that is called will receive the same object, with modifications.
*You seem to be a professor or the like. Please don't be offended by a meme. That's just the risk of getting advice from the internet.

Why doesn't python allow passing variables by reference [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 6 months ago.
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).
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.
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.
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.
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.

Trouble with the scope of variables in a class?

So I'm in the process of making a class in Python that creates a network (with pybrain) using solely the numeric input it's given {just a little process to get my feet wet in Pybrain's API}.
My problem is, I'm rather unfamiliar with how scopes work in classes, and while I basically have the program set up properly, it keeps returning a keyerror.
All the variables needed to be acted upon are created in the init function; the method I'm working on for the class is trying to call upon one of the variables, declared in the init function using the vars()[] method in Python. (you can actually see a portion of the code's...rough draft here:
Matching Binary operators in Tuples to Dictionary Items
Anyways, the method is:
def constructnetwork(self):
"""constructs network using gathered data in __init__"""
if self.recurrent:
self.network = pybrain.RecurrentNetwork
#add modules/connections here
elif self.forward:
self.network = pybrain.FeedForwardNetwork
else:
self.network = pybrain.network
print vars()[self.CONNECT+str(1)]
print vars()[self.CONNECT+str(2)]
print self.network
(pardon the bad spacing, it didn't copy and paste over well.) The part that's raising the KeyError is the "print vars()[self.CONNECT+str(1)], which should retreive the value of the variable "Connection1" (self.CONNECT = 'Connection'), but calls a keyerror.
How do I get the variables to transfer over? If you need more information to help just ask, I'm trying to keep the quesiton as short as possible.
vars() returns a reference to the dictionary of local variables. If you used vars() in your __init__ (as the code in the post you linked to suggests), then you just created a local variable in that method, which isn't accessible from anywhere outside that method.
What is it that you think vars() does, and what are you trying to do? I have a hunch that what you want is getattr and setattr, or just a dictionary, and not vars.
Edit: Based on your comment, it sounds like, indeed, you shouldn't use vars. You would be better off, in __init__, doing something like:
self.connections = {}
self.connections[1] = "This is connection 1"
then in your method, do:
self.connections[1]
This is just a vague guess based on your code, though. I can't really tell what you are intending for this "connection". Do you want it to be some data associated with your object?

Categories