How can a variable be assigned to two objects? - python-3.x

g = None
try:
g = open("mydata.txt", "r")
except IOError:
print(’Python could not open the file mydata.txt.’)
if g:
try:
lines = g.readlines()
print("The list of lines is:")
print(lines)
except IOError:
print(’Error while trying to read the data in the file.’)
This is an example of using try and except in python from my textbook. The textbook stated that "g is given an initial binding of None (which is treated as False within the boolean context of the if statement)". From my understanding, g already holds a file object returned from the open function, how can it be treated as False within the boolean context of the if statement?

g changes from holding a None to a File object when it's reassigned at:
g = open("mydata.txt", "r")
It doesn't "have 2 objects" at once.

It can't be both None and the contents of the file at the same time; the idea is that if open() fails, and the first Except block is hit, then g will still be equal toNone`.
So if the open() process completes successfully, than the if g statement will evaluate to true, and the function will proceed. If the open() process fails, g will still be equal to None, and therefore the if g statement will evaluate to false and the readlines() section will be skipped.

so it is important to understand that Python is an interpreted language which is executed statement by statement
when this code is compiled the compiler know that g is None from g = None. but the compiler keeps reading more lines. When it reads g = open("mydata.txt", "r") then the variable g now reassign to holds a file object and no longer none

Related

Save io.read() file reading result to a string

So I have some code:
io.input(file)
print(io.read())
result = io.read()
print(result)
io.close(file)
and when I run this, I get
dasdasd
nil
where "dasdasd" is the content of the file. This signifies to me that the result of io.read() was not properly not saved to the string. Why is this the case? What am I missing?
You're assuming read() goes back to the beginning each time. This would require a seek() operation to be performed. https://pgl.yoyo.org/luai/i/file%3Aseek
f = io .input( 'filename.txt' )
print( f :read() )
f :seek('set') -- set returns to the beginning
result = f :read()
print( result )
f :close()
Lua is not a referentially transparent programming language, and io.read() is not a pure function. If you want to use the output from a call to it multiple times, you can't just call it multiple times. Save it to a variable and use that instead (like you did anyway immediately after your first call to it).

How to tackle the error str object is not callable

Whenever I am trying to run the given code it always gives the error 'str' object is not callable.
Somebody please tell me what is wrong with the code.
Here is the code:
def intel():
c=0
for i in num(1,9):
if((num[i]%2)==0):
c=c+1
return c
num = input()
out= intel()
print(out)```
Bachchu, welcome! There are a few different things going on here:
As usr2564301 explained, the TypeError: 'str' object is not callable is Traceback for statement for i in num(1,9): because the num() function does not exist unless you define one yourself. That is to say that functions like print() are built-in to Python such that you need not import additional modules to have automatic access to them. The num() function does not exist in the default 'namespace' which you have access to. Perhaps you did define one in another module and forgot to import it, or perhaps you did not mean to call that as a function, but it caused the error because unless you have visibility to it (for example through a def or import) then it does not exist as far as Python is concerned.
This segues into Carl Brubaker's assumption that you meant to use the range() function instead of num() altogether. The range() function would generate a list of [1,2,3,4,5,6,7,8] for your code to iterate through. It starts at the first argument (1) and goes up to but not including the second argument (9-1 = 8). I will add that perhaps, if you did indeed intend for the generation of a list, you probably meant to include 9 in the list, in which case you would need to use range(1,10).
As far as num() and input() are concerned, I don't think you are trying to define a num() function by entering it at the keyboard and assigning it to variable num via a call to the input() function.
The num = input() statement accepts user input from the keyboard and assigns it in string format to the variable num. As Carl Brubaker explained, you will need to convert (or cast if you are familiar with other languages) that data to int() before comparing it numerically. You can easily do this by wrapping the input() call:
num = int(input())
or like this:
num = input()
num = int(num)
One last piece of two-cents: The input() function can be passed a prompt string to present to the user so that when the control is passed to the terminal, the prompt will indicate to the user that it is expecting something. Here's an example:
num = int(input('Please enter a number: '))
As expected, this will present the user, at the terminal (command prompt), with the following:
Please enter a number:
Note that the blank space is a spacer so that the user's data will begin one space after the colon (for the sake of clarity).
At this juncture, we could guess what your objective is, but it would be best if you first cleaned up what we have pointed out here, then followup with outstanding issues, if any remain.

Infinite loop using iter method

I am an amateur and am playing around with writing my own (very bad) compression tool, just for fun.
The following code is used to read a text file and create a dictionary of the indexes of every character in the file.
I'm trying to read the file in 1K chuncks, just for the hell of it but for some reason I get an infinite loop.
I'm guessing I've misunderstood something in the "Iter" method.
code:
def dictify(myFile):
compDict = {}
count = 0
with open(myFile, 'r') as f:
for chunk in iter(f.read, 1024):
for ch in chunk:
if ch in compDict:
compDict[ch].append(count)
else:
compDict[ch] = []
compDict[ch].append(count)
count += 1
print(compDict)
print(compDict)
dictify('test.txt')
the print statement was for debugging purposes and I left it in because it will make it clear to whomever runs the code where the inf. loop is.
Also - the txt file can be anything. Mine just says "I am the walrus"
any ideas what I'm doing wrong?
Thanks!
this is not how iter works.
your example is given in the doc as:
from functools import partial
with open('mydata.db', 'rb') as f:
for block in iter(partial(f.read, 64), b''):
process_block(block)
if you use iter with 2 arguments, the first must be a callable and the second a sentinel; i.e. something to look for when iter needs to terminate.
in your case the second argument is an integer (1024); f.read returns a string; so it will never terminate.
if you read your file in text mode (as opposed to binary) you need to make the following changes (i also adapted your block size):
with open('mydata.db', 'r') as f:
for block in iter(partial(f.read, 1024), ''):
process_block(block)

Variable change in a function - Python 3

So I got the following code:
def foo(a, b, c):
try:
a = [0]
b[0] = 1
c[0] = 2
w[0] = 3
except:
pass
return z
x, y, z = [None], [None], [None]
w = z[:]
foo(x,y,z)
print(x,y,z,w)
The last line of the code print(x,y,z,w) prints [None] [1] [2] [3], however
I don't quite get it. Why are x,y,z are being changed from within the funciton? and if w changes - and it points to z, why doesnt z change accordingly?
In Python objects are passed by reference to functions.
This line makes a copy of z
w = z[:]
so changes to z don't affect w and vice versa. In the line
a = [0]
you change the reference to point to a new object, so you don't mutate x (which is what a was initially bound to). In the following lines
b[0] = 1
c[0] = 2
you mutate the objects that you got references to (y and z in global scope), so the objects in the outside scope change. In the line
w[0] = 3
you mutate the global object w since the name w is not a parameter of the function, nor is it bound in the body of the function.
What everyone else says is correct, but I want to add my way of thinking that may be helpful if you have experience with a language like C or C++.
Every variable in Python is a pointer (well, the technical term is a "reference", but I find that more difficult to visualize than "pointer"). You know how in C/C++ you can get a function to output multiple values by passing in pointers? Your code is doing essentially the same thing.
Of course, you may be wondering, if that is the case, why don't you see the same thing happening to ints, strs or whatnot? The reason is that those things are immutable, which means you cannot directly change the value of an int or a str at all. When you "change an integer", like i = 1, you are really changing the variable, pointing it to a different int object. Similarly, s += 'abc' creates a new str object with the value s + 'abc', then assigns it to s. (This is why s += 'abc' can be inefficient when s is long, compared to appending to a list!)
Notice that when you do a = [0], you are changing a in the second way --- changing the pointer instead of the object pointed to. This is why this line doesn't modify x.
Finally, as the others has said, w = z[:] makes a copy. This might be a little confusing, because for some other objects (like numpy arrays), this syntax makes a view instead of a copy, which means that it acts like the same object when it comes to changing elements. Remember that [] is just an operator, and every type of object can choose to give it a different semantical meaning. Just like % is mod for ints, and formatting for strs --- you sometimes just need to get familiar with the peculiarities of different types.

Why UnboundLocalError doesn't occur with lists?

I have a question regarding a tutorial problem.
Write a function make_monitored that takes as input a function, f, that itself takes one input. The result returned by make_monitored is a third function, say mf, that keeps track of the number of times it has been called by maintaining an internal counter. If the input to mf is the special string "how-many-calls?", then mf returns the value of the counter. If the input is the special string "reset-count", then mf resets the counter to zero. For any other input, mf returns the result of calling f on that input and increments the counter.
I have the following solution which works, surprisingly.
def make_monitored(f):
calls=[0]
def helper(n):
if n=="how-many-calls?":
return calls[0]
elif n=="reset-count":
calls[0]=0
else:
calls[0]+=1
return f(n)
return helper
I recalled reading about UnboundLocalError here: UnboundLocalError in Python
My question would be why won't calls[0]+=1 trigger that error? I made an assignation to a variable outside the local scope of the third function helper , and it seems a similar solution that uses instead calls.append(1) (the rest of the code correspondingly becomes len(calls) and calls.clear()) also bypasses that error.

Resources