Changing the variable given in a function statement - python

My code so far is:
def errorCheckInt(n):
try:
n = int(n)
checkValue1 = True
except:
checkValue1 = False
It is supposed to take a variable input (which is n) and change it to an integer if possible. It will try to get a different input if it is a string.
However, it hasn't worked, and I think it's because you can't change the variable in the code.
This may not be very clear, so I'm giving an example:
testingNum = "2"
# def errorCheckInt here
errorCheckInt(testingNum)
# Should change testingNum to integer value 2, not string "2"
This would be followed by a while statement, checking whether it was successful (whether checkValue1 is True or False) then possibly asking for a new input and error checking that (depending on the input the user gives).
If this still isn't very clear, just comment a question and I may be able to tell you what I had in mind.
Thanks in advance!

It isn't clear to me what you mean when you say "you can't change the variable in the code". Honestly, I'm going to take a leap here (since I have no idea where you are at in terms of Python understanding).
There are two concepts I feel like you may be having trouble with. (1) is the idea of object mutability, and (2) how variables are used and defined in and out of scope inside of Python.
When you re-assign a value like this:
n = int(n)
You haven't actually modified the value held by the variable outside (testingNum). This is because variables in Python are just references to objects. This means that your variable will always point to the same object unless it is re-assigned explicitly. Where this gets confusing is when you're dealing with the concept of mutability. For example, lists, dictionaries and classes are mutable objects. If you do something like:
t = []
n = t
and then do:
n.extend([1,2,3,4])
you'll see that both n and t now look like:
[1,2,3,4]
This isn't really mysterious behavior when you finally understand what's going on. The integer 4 and the [1,2,3,4] are different objects. The only difference is that [1,2,3,4] was also the same object as the initial [] when it was assigned to t. On the other hand, when you re-assign an integer or a string to a variable, you've simply changed what object the variable is pointing to. That's all.
How does this apply to your example?
In essence, all you were missing was a return statement:
def errorCheckInt(n):
try:
n = int(n)
checkValue1 = True
except:
checkValue1 = False
return n
testingNum = "2"
newNum = errorCheckInt(testingNum) # You can catch it here with newNum.
Understanding the use of the return statement is tantamount. When you assign a reference to a variable inside a function, that variable falls out of scope as soon as you exit the function; in other words, if you try to call it afterwards, you'll get an error. To circumvent this, you need to catch the result of your function in a variable that's in the outer scope. This allows you to keep working with the data you've just calculated inside the function.
Note
A better way of doing what you're asking is to use isinstance. For example,
print isinstance(4, int)
# True
print isinstance('4', int)
# False
This will automatically check if the value is an instance of the int type. It's both clearer and cleaner.
Further clarification
An interesting fact of mutability is that when you pass references to mutable objects inside of functions, modifying the object with, say, [].append(4) will mean that any variable pointing to that object (even from outside) is getting the same update if you will. So in certain cases using the return statement isn't necessary, but being explicit is sometimes worth the effort.

When errorCheckInt is run, variable n is bound to the same value as testingNum. However with n =, you change the binding, not the value so n then points to a different value than testingNum. What you need is to pass a mutable type and change the binding inside it:
def errorCheckInt(n):
try:
n[0] = int(n[0])
checkValue1 = True
except:
checkValue1 = False
testingNum = [ "2" ]
errorCheckInt(testingNum)
# testingNum is now 2 and type(testingNum) is int

Related

Why do I not have to define the variable in a for loop using range(), but I do have to in a while loop in Python?

I have the following code using a for loop:
total = 0
for num in range(101):
total = total + num
print(total)
Now the same result using a while loop:
num = 0
total = 0
while num <= 99:
num = num + 1
total = total + num
print(total)
Why is it that I do not have to define num in the first case, but I do have to define it in the second? Are they both not variables?
Well, for is a special statement that automatically defines the variable for you. It would be redundant to require you to declare the variable in advance.
while is a general purpose loop construct. The condition for a while statement doesn't even have to include a variable; for example
while True:
or
while my_function() > 0:
I'd like to approach this question from a slightly different perspective.
If we look at the official Python grammar specification, we can see that (approximately speaking), a while statement takes a test, while a for statement takes an exprlist and testlist.
Conceptually, then, we can understand that a while statement needs one thing: an expression that it can repeatedly evaluate.
On the other hand, a for statement needs two: a collection of expressions to be evaluated, as well as a number of names to bind the results of those evaluations to.
With this in mind, it makes sense that a while statement would not automatically create a temporary variable, since it can accept literals too. Conversely, a for statement must bind to some names.
(Strictly speaking, it is valid, in terms of Python grammar, to put a literal where you would expect a name in a for statement, but contextually that wouldn't make sense, so the language prohibits it.)
In python there is no need, in most cases, to define/declare variables.
The rule is that if you write (assign) a variable then the variable is a local variable of the function; if you only read it instead then it's a global.
Variables assigned at top-level (outside any function) are global... so for example:
x = 12 # this is an assignment, and because we're outside functions x
# is deduced to be a global
def foo():
print(x) # we only "read" x, thus we're talking of the global
def bar():
x = 3 # this is an assignment inside a function, so x is local
print(x) # will print 3, not touching the global
def baz():
x += 3 # this will generate an error: we're writing so it's a
# local, but no value has been ever assigned to it so it
# has "no value" and we cannot "increment" it
def baz2():
global x # this is a declaration, even if we write in the code
# x refers to the global
x += 3 # Now fine... will increment the global
The for statement is simply a loop that writes to a variable: if no declaration is present then the variable will be assumed to be a local; if there is a global or nonlocal declaration then the variable used will have the corresponding scope (nonlocal is used to write to local variable of the enclosing function from code in a nested function: it's not used very frequently in Python).
If you are coming from other programming languages like C, C++ or Java then do not confuse with for in loop of python.
In python, for in loop pick one item from list of items and does something with help of the picked item.
For Loop iterates each element from the list until the given range. So no need of any variable to check condition.
While Loop iterates until the given condition is true. Here we need some variable or value to check the condition, So the variable num is used before the loop.
Python for loops assign the variable and let you use it. We can transform a for loop into a while loop to understand how Python actually does it (hint: it uses iterables!):
iterator = iter(iterable) # fresh new iterator object
done = False
while not done:
try:
item = next(iterator)
except StopIteration:
done = True
else:
# inside code of a for loop, we can use `item` here
pass

Why does this function need to be stored in a variable?

I originally had a problem with this code as I was missing the 'n =' in the last line of code and, as a result, was stuck in an infinite loop.
At this point, while I understand what needed to be corrected I don't understand why. Why can't 'collatz(n)' be enough to call the function and use n as its variable? If anyone could explain this in simple terms (beginner here), I'd really appreciate it.
def collatz(number):
if number % 2 == 0:
print (number // 2)
return number // 2
elif number % 2 == 1:
print (3 * number + 1)
return 3 * number + 1
print ('Please enter a number.')
n = int(input())
while n != 1:
n = collatz(n)
In Python, functions accept one or more arguments and return a single value or object. Most of the time they don't modify their arguments (and indeed your collatz function doesn't attempt to modify its argument).
As an example, this function accepts a variable x, and returns x**2.
def f(x):
return x**2
This function doesn't modify x in place, and the return value won't automatically get assigned to x. Automatic assignment to x would often be unhelpful, and it would be unclear what to do if your function accepted multiple arguments -- which one should get the return result?
You can call this function in various ways, but if you want to do something with the result, you have to store it to a variable or use it immediately:
y = 2
z = f(y)
z = f(2)
y = 2
print(f(y))
Note that all of these make sense if you think of the function f as an object that converts its argument to something else and returns that, but none of them make sense if you expect f to modify its argument in place (then f(2) would somehow have to convert the number 2 to mean 4 during later references).
For what it's worth, even if you did replace one of the arguments with a new value inside the function, that would not change the value of the corresponding variable outside the function. This is because the variables within the function only point to the corresponding value or object. If you assign a new value to the variable, the local variable within the function will now point to the new value, but the original variable outside the function still points to the old value. On the other hand, you can sometimes modify the underlying value or object rather than creating a new object and pointing the local variable to it. For example, adding an item to a list or dictionary will modify the underlying object, and that change will be visible outside your function.
But your collatz function does neither of these - it just calculates a new value and returns it. If you want to do anything with that value, you have to store the result of the function call explicitly. It won't automatically be stored in the argument variable.
When you pass a variable as an argument to a function, a copy of the variable is sent to the function and not the variable itself.
So in your case n_copy (for example) is sent to your function and not n.
Now when you modify it within the function it remains in the scope of the function (accessible only by the function) and not the main program.
So when the function ends, nothing happens to n because a copy of n was modified.
Now we come to the return function. Because of the above problem, there is a return function. This will return a value from the function to the main program.
As you modified n within your function, you need to return the modified value to the main program.
Once you return it to the main program, it has to be stored in a variable, in your case it is n.
As you have started learning Python, you should read about namespace, scopes also.
Here is the first link from google search
https://matthew-brett.github.io/teaching/global_scope.html

Python Lists and Equality

I'm practicing for a midterm, and I came across this:
the_cake = [1,2,[3],4,5]
a_lie = the_cake[1:4]
the_cake = the_cake[1:4]
great = a_lie
delicious = the_cake
moist = great[:-1]
After running this code in the Python interpreter, why is:
the_cake.append == a_lie.append
False
My thought is that they are equal methods, and though not "IS", should fulfill the equality.
Maybe this evaluates to False because of instantiation?
If this is true, then do class attributes evaluate to True when compared?
Is this a special case with list objects?
Follow-up:
According to this:
Is there a difference between `==` and `is` in Python?
"IS will return True if two variables point to the same object, == if the objects referred to by the variables are equal."
Then do methods of the List class point to separate instances of the "append" method?
So if I define a function x(parameter), every time I call it, it'll be the same because it's the same object assigned to different variables, right?
Then for some equivalent variable "parameter":
x(parameter) == x(parameter)
True
Thanks!
The methods are at different locations along with their respective object instances. For instance we have:
a = []
b = []
So we have:
>>> a.append == b.append
False
and their respective locations is given in:
>>> a.append
<built-in method append of list object at 0x7f7c7c97d560>
>>> b.append
<built-in method append of list object at 0x7f7c7c97d908>
Notice the different addresses.
Both answers are valid, but check this out too:
>>> a = []
>>> b = a
>>> a.append == b.append
True
Python 2.x: Functions of type objects implement rich comparisons based on the object's address in memory.
Python 3.x: be careful that functions are not longer orderable. So, e.g., the_cake.append > a_lie.append will throw an error message.
Slicing of list in python always returns a new list. the_cake[1:4] returns a new list as well. So if you call the same slice each time that does not mean that it will return the same list. Irrespective of whether you do the same slice again and again, it will return a new list each time it is being called.
Even though you are assigning the same slice the_cake[1:4] to a_lie as well as to itself(i.e. the_cake), both are referring to a new list which is different from the other one.
So both the list have a different memory location assigned during creation. If you check id(the_cake) == id(a_lie), it will return False.
So now when you refer to append for both of the instances, they also differ as well. Even though same method is being referred, it is referred from two different instances. So it will create different instances as well for the method being invoked. Therefore the instances referred when called the_cake.append differs from that of a_lie.append.

using exception with for loop in python

hey guys am new to python app development..i have been trying to fetch only numbers from a list using a for loop..But am confused with the correct syntax..The code i have been used.is like below.
babe = [10,11,13,'vv']
int(honey) [for honey in babe]:
print honey
When i run this i got syntax error.i have tried many situations.But it didnt helped me at all.Sorry for the silly question..
do i wanna add square brackets or something on the second line ??
Am really stuck.Hope you guys can help me out..Thanks in advance
You seem to be conflating the syntax for for loops (a statement followed by a suite of statements ... otherwise known as a "block of code") and a list comprehension (an expression).
Here's a list comprehension:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = [int(x) for x in b]
... that's syntactically valid. However, the semantics of that example will raise an exception because 'vv' is not a valid literal (string). It cannot be interpreted as a decimal integer.
Here's a for loop:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = list()
for x in b:
try:
a.append(int(x))
except ValueError:
pass
In this case we explicitly loop over the given list (b) and ignore any ValueError exceptions raised when we try to convert each of those entries into an integer.
There is no reasonable way to handle exceptions from within a list comprehension. You could write a function which returned some sentinel value (from the expression) for any invalid input value. That would look something like this:
#/usr/bin/python
# Given:
b = [1, 2, 3, 'vv']
def mk_integer_if_possible(n):
'''Returns an integer or the sentinel value None
'''
results = None
try:
results = int(n)
except ValueError:
pass
return results
# Use that function:
a = [mk_integer_if_possible(x) for x in b if mk_integer_if_possible(x) is not None]
Note: the absurd function name is deliberate. This is an ugly way to do this and the awkwardness of having to call this putative function TWICE for each element of b is an indication that you should NOT use a list comprehension for this situation. (You have to call it once to make the conversion but again for the conditional. Saving the results from one call would, of course, be a STATEMENT, which we can't have embedded within an EXPRESSION).
Statements contain one or more expressions. Expressions are components of statements. Python strictly delineates between statements and expressions. Assignments are statements in Python. These distinctions can be nuanced and there are other programming languages where assignments are expressions rather than being strictly defined, by the language's syntax, as statements.
So, use the for loop whenever you have to handle possible exceptions while iterating over any sort of data set and usually when you need to filter on the results generated by mapping a function over a list comprehension.
Incidentally the explicit use of the expression is not None is necessary in this example. If I attempted to shorten that test to simply be if mk_integer_if_possible(x) using Python's implicit boolean handling then we'd be inadvertently filtering out any entries from b that evaluated to integer 0 as well as any that were returned as the None sentinel by my ill-advised function.
In Python it's often fine to use implicit boolean values as conditions. None and False as well as any numerically zero value, any empty string or any sort of empty list, tuple or dictionary, are all treated as "false" in a boolean context. However, when dealing with sentinel values it's best to use the is operator and explicitly test for object identity. Otherwise you'll have corner cases where your condition might be matched by values other than your sentinel.
(Handy trick: if you ever come across the need to allow None through some sort of filter or pass it along, but you need some other sentinel ... just use sentinel = object() ... you can create (instantiate) a generic Pythonobject and use is to match it for your sentinel handling. That will be unique to your code and no other Python object or type will match it. Guaranteed).
By the way ... I should note that this code it technically not "fetching only numbers from a list." It is returning integers for all entries in the list which can be converted thereto. This is a nitpick; but it's a distinction that any good engineer will notice. Do you want to return all integers from the input list? Or do you want to return all entries as integers if that can be so converted? Your code suggested that you're trying to accomplish the latter; so that's how I implemented my working examples for you. However, to implement the later semantics you'd probably want to use either the (mathematical) additive or multiplicative identity property like so:
# ... from within some function:
try:
results = x == x + 0 # Additive identity
except (TypeError, ValueError):
results = None
return results
babe = [10,11,13,'vv']
a = [honey for honey in babe if isinstance(honey, int)]
print a
See more here about list comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

what's the difference between assign and bound when talking about variable?

Except from http://www.stavros.io/tutorials/python/
# This swaps the variables in one line(!).
# It doesn't violate strong typing because values aren't
# actually being assigned, but new objects are bound to
# the old names.
>>> myvar, mystring = mystring, myvar
I don't understand the point he is making.
He means to say the two variables are essentially swapped without knowing their types or explicitly using an intermediate variable as you normally would. A weakly-typed swap looks like this:
temp = A
A = B
B = temp
A previously-unitialized temporary variable temp must be created in order to perform the swap. However, because no type is specified when temp is first created, it violates strong typing. Here is a strongly-typed swap:
int temp = A
A = B
B = temp
A swap like A, B = B, A does not violate strong typing because an intermediate variable doesn't need to be explicitly defined with or without a type. It's simply an assignment operation, and a basic assignment operation is always ambiguously typed (aka: A = B is the same regardless of whether you are using a strong-typed language or a weak-typed one).
An assignment like a=1 , conceptually Python will perform three distinct steps to carry out the request.
1.Create an object to represent the value 1
2.Create the variable a.
3.Link(or bound as in the link) the variable a to new object 1.
In your case, the statement
myvar, mystring = mystring, myvar
will change the variable-object bound relationship.

Categories