Cannot understand specific Python 3 code - python

While trying to solve a problem on Hackerank(The Problem). I checked the solutions of people who have solved this problem. Here is the solution from one person-
n = input()
l = []
for _ in range(n):
s = raw_input().split()
cmd = s[0]
args = s[1:]
if cmd !="print":
cmd += "("+ ",".join(args) +")"
eval("l."+cmd)
else:
print l
I cannot understand line 8 and line 9, can someone explain me these lines? Can i write line 8 and line 9 in Python 3 as i'm learning Python 3 ? How ?

Basically, cmd is constructed by appending the command (say "insert"), to the operands. This cmd forms a correct python expression (for example l.insert(0,5), to insert 5 at index 0, in list l).
Here, l. is hardcoded(start of line 9), cmd is initialized in cmd = s[0], and operands are added in line 8.
eval(str) evaluates the command str, in string format, as if it were in a command line.

It would be nice to just include the problem :) . The input is a (text) file as below:
Sample Input 0
12
insert 0 5
insert 1 10
insert 0 6
print
remove 6
append 9
append 1
sort
print
pop
reverse
print
And the expected output for a correct answer is as below:
Sample Output 0
[6, 5, 10]
[1, 5, 9, 10]
[9, 5, 1]
Before looking at the answer you quoted it would be good to read about eval; it takes the argument provided and tries to run it as a python expression using the global and local namespace. So in this case it needs only the local for the "l"-list and "cmd"-tuple.
What is happening is the following:
Empty list l is created.
The "command" (cmd) single-value list is parsed from the line by slicing (cmd = s[0]), since every line starts with or only has a list method
The other arguments are placed in args
Line 8 (as asked): These other arguments are then joined in a string tuple. So "insert 0 5" gives "insert" for l and "(0, 5)" for cmd
Line 8 continued (as asked): cmd is then combined with args using string concatenation (read here for a good and bad example) resulting in "insert(0,5)" as value for cmd
Line 9 (as asked): the eval parameter is yet another string concatenation yielding "l.insert(0,5)" as final expression to be interpreted. Which then inserts integer value 5 on spot 0 in list l (pushing forward any other values already in l)
Hope it helps, keep on trucking!

Related

Unexpected Python for-loop behaviour?

Can someone explain what happened in the second run ? Why did I get a stream of 9's when the code should have given an error?
>>> for __ in range(10): #first run
... print(__)
...
0
1
2
3
4
5
6
7
8
9
This was the second run
>>> for __ in range(10): #second run
... print(_)
...
9
9
9
9
9
9
9
9
9
9
>>> exit()
After this, when I ran the code for the third time, the same code executed as expected and gave the below error. I realize that this question has no practical use. But, I would really like to know why it happened?
NameError: name '_' is not defined
The _ variable is set in the Python interpreter, always holding the last non-None result of any expression statement that has been run.
From the Reserved Classifiers and Identifiers reference:
The special identifier _ is used in the interactive interpreter to store the result of the last evaluation; it is stored in the builtins module.
and from sys.displayhook():
If value is not None, this function prints repr(value) to sys.stdout, and saves value in builtins._. [...] sys.displayhook is called on the result of evaluating an expression entered in an interactive Python session.
Here, that result was 9, from an expression you must have run before the code you shared.
The NameError indicates you restarted the Python interpreter and did not yet run an expression statement yet that produced a non-None value:
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> 3 * 3
9
>>> _
9

Counting the real number of arguments in python

Is there any way to count the real number of arguments passed to a function in python, even when some defaults values are set? I'm trying to write a function, which replaces a certain range of a text file with 0 (or an offset value), but it doesn't work because python returns the number of arguments including the arguments which are not passed.
The input file is like this:
foo.txt
0
1
2
3
4
5
6
7
8
9
10
11
Here is the code:
import os
import numpy as np
from inspect import signature
def substitute_with(FILE, start, end=10, offset=0):
sig = signature(substitute_with)
params = sig.parameters
print('len(params): %d' % len(params))
filename, file_extension = os.path.splitext(FILE)
file_i = FILE
file_o = filename + '_0' + file_extension
Z = np.loadtxt(file_i)
with open(file_o, "w") as fid:
length_Z = len(Z)
print('length_Z: %d' % length_Z)
if(len(params) < 3): # gives me 4, but actually, I need 2 here!
end=length_Z
X = np.concatenate([np.ones((start)), np.zeros((end-start)), np.ones((length_Z-end))])
Y = np.concatenate([np.zeros((start)), np.ones((end-start)), np.zeros((length_Z-end))])*offset
A=Z.T*X+Y
for i in range(0, length_Z):
fid.write('%d\n' % (A[i]))
#substitute_with('foo.txt',4,8)
#substitute_with('foo.txt',4,8,2)
substitute_with('foo.txt',4)
... This works only when the 3rd argument 'end' is passed. Without the 3rd argument, from 4 through the end (11) are supposed to be replaced with 0. But, in reality, from 4 through 9 are replaced with 0.
I reluctantly set a default value (=10) to end, otherwise the compiler gives me the following error:
TypeError: substitute_with() missing 1 required positional argument: 'end'
So, how would you guys solve this? Please don't tell me to check the length of the file first and then give it to the function. It should be done inside the function. In MATLAB, 'nargin' returns the real number of arguments, so this kind of logic would work easily. If python cannot do this, it's gonna be a shame.
Just use None as the default for end:
def substitute_with(FILE, start, end=None, offset=0):
...
if end is None:
end = length_Z
...

List Index out of range in python?

I'm kind of new to python and needed help with this - it says list index out of range?
file=open("Reg_Details.csv","r")
Reg=[line.split(',') for line in file]
file=open("Speed_Exceeded.csv","r")
Speed=[line.split(',') for line in file]
for x in Reg:
for y in Speed:
if x[2]==y[2]:
print("match")
file=open("Details_user.csv","w")
file.write("%s,%s,%s\n" % (x[0],[0],x[1]))
file.close()
(Original screencap)
It means that the list doesn't have an element with the index id you're asking for.
>>> variable = [1,2,3]
>>> variable[2]
3
>>> variable[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
In this example the valid ids are 0, 1 and 2, but 3 is invalid.
When you check
x[2] == y[2]
you're accessing the third element of each of the two lists (0 is the first element). The error you are getting means that either x or y has less than 3 elements, so the element you are asking for is out of range. Most likely Reg_Details.csv or Speed_Exceeded.csv have only 1 or 2 columns.
Also looking at your code, you probably want to replace
file=open("Details_user.csv", "w")
by
file=open("Details_user.csv", "a")
The opening mode "w" puts the writing stream at the beginning of the file, so every time you run this line you are erasing whatever was inside before (meaning each iteration of your loop you are deleting the previous line, and at the end "Details_user.csv" will contain only one line). Using the opening mode "a" (from 'append') opens the file putting the writing stream at the end of the file, so you will append a new line to the file at every iteration.

Unable to index into a list

I am writing a program to read the output of another program, read it line by line and put it in a list.
#!/usr/bin/python
import subprocess
def RECEIVE(COMMAND):
PROCESS = subprocess.Popen(COMMAND, stdout=subprocess.PIPE)
LINES = iter(PROCESS.stdout.readline, "")
for LINE in LINES:
RECARR = LINE.split()
print RECARR[14]
RECEIVE(["receivetest","-f=/dev/pcan32"])
The output from the receivetest program is:
19327481.401 receivetest: m s 0x0000000663 8 2f 00 42 02 00 e4 8a 8a
19327481.860 receivetest: m s 0x000000069e 8 00 1f 5e 28 34 83 59 1a
it is a constant stream of messages. When split, the list has a range of 14 because after splitting, to make sure, I used:
print len(RECARR)
This gave me an output of 14.
but whenever I try to print the last element:
print RECARR[14]
I get the following error:
file "./cancheck.py", line 10, in RECEIVE
print RECARR[14]
IndexError: list index out of range
This is caused by some erronious text that is printed at the top of the list, so I need some way of making sure that the program only reads in lines that start with
1234567.123
/^(.......\.\d{1,3}) (.*)$/
Any ideas?
Based on the sample data you provided, the length of RECARR is always 14.
14 is the size of the list, not the maximum index. To get the final element of the array, you can try RECARR[13] for this list, or RECARR[-1] in general.
The reason for this is that in Python, as in most programming languages, array indices are zero-based: the first element is accessed with RECARR[0], the second with RECARR[1], and so on. So, the 14th element (or the last one, in your case) would be accessed with RECARR[13].
So, your for loop would look something like this:
for LINE in LINES:
RECARR = LINE.split()
print RECARR[13] # or RECARR[-1]
Right everyone, it's a terrible workaround but I fixed the issue by working out that the only lines with exactly 14 elements are the lines I need so I fixed it by using the following
for LINE in LINES:
RECARR = LINE.split()
if(len(RECARR) == 14):
#do stuff
List indexes start from 0 and not 1. So
print RECARR[1]
prints the 2nd element and not the first. Thus to print the last element you have to use print RECARR[13] or negative index print RECARR[-1].
The lists in python can be depicted as
As you can see the last element can be accessed using either -1 or length of the list -1
An easier way to gauge the ranges is to put the indices before the cell. (Courtesy - Aristide)
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
You could have also done something similar to this:
try:
print RECARR[13]
except IndexError:
pass
This way you can easily handle the lines that are not long enough as well.

python sys.argv can't get the argument value?

I tried to pass some variables to my python code . the variable is a list, after i run the python script . which is simply just print out sys.argv. the output is following:
:~ xxx$ /var/folders/kg/qxxxxxd343433gq/T/Cleanup\ At\ Startup/pdTry-375321896.860.py.command ; exit;
var1, var2, var1, var2
the len argv is 1
/Users/xxx/python/pdTry.py
Traceback (most recent call last):
File "/Users/xxx/python/pdTry.py", line 58, in <module>
main()
File "/Users/xxx/python/pdTry.py", line 33, in main
print (sys.argv[1])
IndexError: list index out of range
logout
you can see the the list contains var1 and var2 actually print out 2 times. but i can get the value, the len sys.argv is 1. No value for sys.argv[1]. Do anyone know why? Why the length is 1, should it be 2? arg[0] is the script name, and arg[1] is the variable list i passed to it?
The code is simply
def main():
os.system ('osascript up.scpt')
#print (sys.argv)
a= 'the len is '+str(len(sys.argv))
print (a)
print (sys.argv[0])
print (sys.argv[1])
Remember that lists in python start at 0.
List Length : 1 2 3 4
Element number: 0 1 2 3
Data : A B C D
so when you have length 1 you only have 1 element (argv[0]) which means argv[1] doesn't exist.
Dude,
you are reading argv[[1] when your length is 1. How can array of length have two items ( read 0th and 1st item).
It seems you left out any real arguments for the script, which could be added to the sys.argv list. In the call you posted, I see no list of variables passed to the script. If the semicolon separating the commands (the script name and exit shell builtin) was escaped, then most likely you would have len(sys.argv) equal to 3 (but I doubt it was your original intention to have the semicolon and exit as sys.argv values).
# simple test script
$ cat exittest.py
import sys
print(sys.argv, len(sys.argv))
# and some calls
$ python3.2 exittest.py
['exittest.py'] 1
$ python3.2 exittest.py \; exit
['exittest.py', ';', 'exit'] 3
# and for a similar call as you posted I ssh'ed to my localhost
# to test it with exit builtin
$ python3.2 exittest.py ; exit
['exittest.py'] 1

Categories

Resources