Why wont this code work? - python

def chan(ref, let, mode):
if mode[0]=="d":
ref=-ref
a=ord(let)
a=a+ref
let=chr(a)
return let
ref=1
let="q"
chan(ref, let,"k")
print(let)
When I run this it comes out with "q" when i want it to come out with "r"
What have I done wrong and what do I need to do to make it work?

You need to assign the return value of the chan() function back to the let variable:
let = chan(ref, let,"k")

When you pass in a variable to a python function, it passes a copy of a pointer to the same memory location as the function argument that was passed into the function. What this means is that if you change properties on an object passed to a function, those changes persist (provided the object is mutable) outside the function. But re-assigning that pointer inside the function does not affect the argument outside of the function, as you are simply pointing that pointer copy (inside the function) to a different piece of memory, which does not affect the original variable. Python does neither pass by value nor pass by reference in the sense that other languages do this. There are many articles detailing this, such as:
http://stupidpythonideas.blogspot.com/2013/11/does-python-pass-by-value-or-by.html
So the code above does not change let as you are modifying a copy of the let pointer inside the function, not changing the original pointer itself.

Related

Cannot understand why python doesn't re-use the parameter when you repeatedly call the same function

I'm watching a tutorial on python and it uses this example:
def add_spam(menu=[]):
menu.append("spam")
return menu
If you call add_spam() repeatedly then the menu list increases in size. This is new to me since I am from a C# background. But OK, fair enough.
To get around this it says that you should set the menu parameter to None but I cannot understand why that works. Here is the code they use:
def add_spam(menu=None):
if menu is None:
menu = []
menu.append('spam')
return menu
If you call it the first time though menu will be set to [], and the second time surely if it's 'remembering' the parameter as in the first example, menu will be [] at that point and therefore it will just append spam to the list as in the first example.
The video neglects any explanation other than you should use an immutable type so I cannot understand how this works.
Edit cos I still don't get it:
What I'm seeing is that the function captures the variable, so it takes menu=[] and stores that secretly somewhere, imagine a private variable called _menu, so that if you call it again it doesn't re-evaluate it just continues to use _menu and thus it grows.
In the second example, I do not understand why it isn't simply taking menu=None and storing that secretly as _menu, so _menu = None and then when you call the 2nd function, it sets _menu=[] and it continues exactly as the first example and it grows.
The fact that None is immutable doesn't seem relevant to me, as you're not doing None=[] you're doing menu=[] so menu then stops being what it was before and becomes [] and you can modify it as you like.
Unless it's some hard-coded feature that if you put None it will not do the copying behaviour then I do not understand the difference between the two.
Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby).
https://docs.python-guide.org/writing/gotchas/
From Python's docs, some more detail:
Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.
https://docs.python.org/3/reference/compound_stmts.html#function-definitions
Lists are mutable objects, whereas None is immutable, hence the behavior you see.
Setting menu = [] inside the function is just rebinding the name menu to a new object inside the scope of that function call. It doesn't change the original menu object in the scope where the function was defined. Appending to menu within the function, on the other hand, actually modifies the object in memory associated with the name menu in the function definition (because lists are mutable). This object was created when the function was first defined, and is shared between calls of the function.
If you want to understand more, look into the python scoping/namespace behavior, of which default argument sharing is mostly just a subset. But basically,
def foo(bar=None): #executed once
bar = [] #executed every time the function is called

How to change function parameter values in a Python 3 C extension?

I can't figure out how to change the value of a parameter passed from Python to C.
PyArg_ParseTuple (args, "Os", &file_handle, &filename)
will let me get file_handle as a PyObject *. Is there a way to change the value file_handle represents? I know I can return multiple values to a Python function call, but that isn't what I want to do in this case. Just for consistency with the C API I am making a module to represent.
You can't change what the caller's parameter refers to in the caller, all you can do is perform mutations of the object itself using its API. Basically, you received a copy of the caller's pointer, not a C++-style reference (nor a C-style double pointer that would give you access to a pointer declared in the caller), so you can't reassign the argument in the caller.
In general, you don't want to try to perfectly reproduce C APIs (I'm assuming your C API uses double-pointers to allow reassigning the value in the caller?) in Python APIs. That's how PHP operates, and it makes for terribly inconsistent APIs that often take no advantage of being in a high level language.
This case is doubly-fraught because, when used properly with with statements, file-like objects actually have multiple references (not C++ meaning) to them, the named variable (that was passed to your function) and one or more hidden references held inside the interpreter (to ensure the with statement has a consistent __exit__ to call, even if the caller deletes their own binding for the object). Even if you could somehow reassign the caller's argument, the with statement would still refer to the original file object, and it wouldn't be obvious to the caller that they needed to close (implicitly using with or explicitly calling close) the result again because your function replaced their object.
Return multiple results (Py_BuildValue makes this easy), and the caller can replace their value if they want to.

What happens to a Python input value if it's not assigned to a variable?

Was just wondering this. So sometimes programmers will insert an input() into a block of code without assigning its value to anything for the purpose of making the program wait for an input before continuing. Usually when it runs, you're expected to just hit enter without typing anything to move forward, but what if you do type something? What happens to that string if its not assigned to any variable? Is there any way to read its value after the fact?
TL;DR: If you don't immediately assign the return value of input(), it's lost.
I can't imagine how or why you would want to retrieve it afterwards.
If you have any callable (as all callables have return values, default is None), call it and do not save its return value, there's no way to get that again. You have one chance to capture the return value, and if you miss it, it's gone.
The return value gets created inside the callable of course, the code that makes it gets run and some memory will be allocated to hold the value. Inside the callable, there's a variable name referencing the value (except if you're directly returning something, like return "unicorns".upper(). In that case there's of course no name).
But after the callable returns, what happens? The return value is still there and can be assigned to a variable name in the calling context. All names that referenced the value inside the callable are gone though. Now if you don't assign the value to a name in your call statement, there are no more names referencing it.
What does that mean? It's gets on the garbage collector's hit list and will be nuked from your memory on its next garbage collection cycle. Of course the GC implementation may be different for different Python interpreters, but the standard CPython implementation uses reference counting.
So to sum it up: if you don't assign the return value a name in your call statement, it's gone for your program and it will be destroyed and the memory it claims will be freed up any time afterwards, as soon as the GC handles it in background.
Now of course a callable might do other stuff with the value before it finally returns it and exits. There are a few possible ways how it could preserve a value:
Write it to an existing, global variable
Write it through any output method, e.g. store it in a file
If it's an instance method of an object, it can also write it to the object's instance variables.
But what for? Unless there would be any benefit from storing the last return value(s), why should it be implemented to hog memory unnecessarily?
There are a few cases where caching the return values makes sense, i.e. for functions with determinable return values (means same input always results in same output) that are often called with the same arguments and take long to calculate.
But for the input function? It's probably the least determinable function existing, even if you call random.random() you can be more sure of the result than when you ask for user input. Caching makes absolutely no sense here.
The value is discarded. You can't get it back. It's the same as if you just had a line like 2 + 2 or random.rand() by itself; the result is gone.

Python achieve pointer like behaviour

I have to write a testing module and have c++-Background. That said, I am aware that there are no pointers in python but how do I achieve the following:
I have a test method which looks in pseudocode like this:
def check(self,obj,prop,value):
if obj.prop <> value: #this does not work,
#getattr does not work either, (objects has no such method (interpreter output)
#I am working with objects from InCyte's python interface
#the supplied findProp method does not do either (i get
#None for objects I can access on the shell with obj.prop
#and yes I supply the method with a string 'prop'
if self._autoadjust:
print("Adjusting prop from x to y")
obj.prop = value #setattr does not work, see above
else:
print("Warning Value != expected value for obj")
Since I want to check many different objects in separate functions I would like to be able to keep the check method in place.
In general, how do I ensure that a function affects the passed object and does not create a copy?
myobj.size=5
resize(myobj,10)
print myobj.size #jython =python2.5 => print is not a function
I can't make resize a member method since the myobj implementation is out of reach, and I don't want to type myobj=resize(myobj, 10) everywhere
Also, how can I make it so that I can access those attributes in a function to which i pass the object and the attribute name?
getattr isn't a method, you need to call it like this
getattr(obj, prop)
similarly setattr is called like this
setattr(obj, prop, value)
In general how do I ensure that a function affects the passed object and does not create a copy?
Python is not C++, you never create copies unless you explicitly do so.
I cant make resize a member method since myobj implementation is out of reach, and I don't want to type myobj=resize(myobj,10) everywere
I don't get it? Why should be out of reach? if you have the instance, you can invoke its methods.
In general, how do I ensure that a function affects the passed object
By writing code inside the function that affects the passed-in object, instead of re-assigning to the name.
and does not create a copy?
A copy is never created unless you ask for one.
Python "variables" are names for things. They don't store objects; they refer to objects. However, unlike C++ references, they can be made to refer to something else.
When you write
def change(parameter):
parameter = 42
x = 23
change(x)
# x is still 23
The reason x is still 23 is not because a copy was made, because a copy wasn't made. The reason is that, inside the function, parameter starts out as a name for the passed-in integer object 23, and then the line parameter = 42 causes parameter to stop being a name for 23, and start being a name for 42.
If you do
def change(parameter):
parameter.append(42)
x = [23]
change(x)
# now x is [23, 42]
The passed-in parameter changes, because .append on a list changes the actual list object.
I can't make resize a member method since the myobj implementation is out of reach
That doesn't matter. When Python compiles, there is no type-checking step, and there is no step to look up the implementation of a method to insert the call. All of that is handled when the code actually runs. The code will get to the point myobj.resize(), look for a resize attribute of whatever object myobj currently refers to (after all, it can't know ahead of time even what kind of object it's dealing with; variables don't have types in Python but instead objects do), and attempt to call it (throwing the appropriate exceptions if (a) the object turns out not to have that attribute; (b) the attribute turns out not to actually be a method or other sort of function).
Also, how can I make it so that I can access those attributes in a function to which i pass the object and the attribute name? / getattr does not work either
Certainly it works if you use it properly. It is not a method; it is a built-in top-level function. Same thing with setattr.

Parse Method Variable Names In Python?

Given the python function:
def MyPythonMethod(value1, value2):
# defining some variables
a = 4
myValue = 15.65
listValues = [4, 67, 83, -23]
# doing some operation on the list
listValues[0] = listValues[1]
# looping through the values
for i in listValues:
print i
How can I extract the names and types of all the variables in method MyPythonMethod?
Ideally, I'd like to get all variable names and their types given a method name. for example, the output for method MyPythonMethod will look like this:
varNames = ["a", "myValue", "listValues", "i"]
varTypes = ["int", "float", "list", "float"]
Any ideas?
1 Variables don't have a type in python. Objects have a type, and variables point to objects.
[2] you can use the inspect module to get info about the internals of your function.
Read the docs -- they will tell you what is available for inspection.
MyPythonMethod.func_code.co_varnames will give you the local variable names, for example.
( And note that MyPythonMethod, as defined, is actually a function, not a method. )
[3] But even when you get the names of the local variables, the aren't bound to any objects
except while the function is executing. The value 4 is bound to local var 'a' in the function -- before and after the function is called, there is no 'a' and it's not bound to anything.
[4] If you run the function in the debugger, you can halt the execution at any point and inspect the variables and objects created in the function.
[5] If the function raises an exception, you can catch the exception and get access to some of the state of the function at the time of the exception.
You can't do this "from the outside".
Local variables don't exist until the method runs. Although the scope of all variables is known statically, i.e. at compiletime, I don't think you can get this information easily without crawling through the AST or bytecode yourself. (Edit: Steven proved me wrong about this one... code objects have a tuple containing all local variable names)
A given chunk of code doesn't have access to any scopes but its own and the sourrounding "lexical" scopes (builtins, module-level globals, local scopes of enclosing functions).
There is no such thing as the type of a variable (in Python) - any variable can refer to any number of objects of completely different types during its lifetime. What should the output be if you add a = "foo"? And if you then add a = SomeClass()?
Inside the method itself, you could use locals() to get a dictionary of local variables and the objects they currently refer to, and you could proceed to call type on the values (the objects). Of course this only gets you the type of the object currently referred to. As hinted in the comment, I doubt that this is useful. What do you really want to do, i.e. what problem are you trying to solve?
If you use pdb can't you set the last line as a breakpoint and then ask the debugger to look at the top stack frame and list the variables for you? Or you could look at the pdb code and copy its tricks for how to introduce the breakpoint and then inspect the stack frame beneath the breakpoint function that you register.

Categories

Resources