Counting the real number of arguments in python - 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
...

Related

Tic tac toe- What's the mistake here

WHAT'S THE MISTAKE HERE??
Traceback (most recent call last)
<ipython-input-51-cb088c4c5c82> in <module>
17 display_board(the_board)
18 position = player_choice(the_board)
---> 19 place_marker(the_board,Player1_marker,position)
20 if win_check(the_board,Player1_marker):
21 display_board(the_board)
<ipython-input-41-ba563e2cb168> in place_marker(board, marker, position)
1 def place_marker(board, marker, position):
----> 2 board[position] = marker
TypeError: list indices must be integers or slices, not NoneType
The lines shown state exactly what is wrong, and where. You just need to know how to interpret it:
18 position = player_choice(the_board)
---> 19 place_marker(the_board,Player1_marker,position)
1 def place_marker(board, marker, position):
----> 2 board[position] = marker
TypeError: list indices must be integers or slices, not NoneType
What you can glean from all that is that:
the position variable used in line 2 of place_marker() is set to None since that is the actual error (variables set to None are of the type NoneType, and position is the list index being complained about);
that position variable is initialised from a variable of the same name, as part of the call to place_marker() on line 19, so it too must also be set to None;
that variable (the one passed in) came from the function player_choice().
In other words, your line:
position = player_choice(the_board)
has returned None for some reason.
Unfortunately, since you haven't shown us that code for that function, we can't really dive any deeper into the analysis, but you may want to look for paths in that function that return without a value. This is a typical cause of functions returning None, such as with:
def fn(x):
if x == 1:
return 7 # This path returns 7 when 1 is passed in.
# This path returns None (implicitly) for any other value.
print(fn(1)) # Explicitly gets 7.
print(fn(2)) # Implicitly gets None.
The result of running that code is, as per the comments:
7
None

Cannot understand specific Python 3 code

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!

Python error: Valueerror-need-more-than-1-value-to-unpack

In python when I run this code:
lat, lon = f.variables['latitude'], f.variables['longitude']
latvals = lat[:]; lonvals = lon[:]
def getclosest_ij(lats,lons,latpt,lonpt):
dist_sq = (lats-latpt)**2 + (lons-lonpt)**2
minindex_flattened = dist_sq.argmin()
return np.unravel_index(minindex_flattened, lats.shape)
iy_min, ix_min = getclosest_ij(latvals, lonvals, 46.1514, 20.0846)
It get the following error:
ValueError Traceback (most recent call last)
ipython-input-104-3ba92bea5d48 in module()
11 return np.unravel_index(minindex_flattened, lats.shape)
12 iy_min, ix_min = getclosest_ij(latvals, lonvals, 46.1514, 20.0846)
ValueError: need more than 1 value to unpack
What does it mean? How could I fix it?
I would read a NetCDF file, it is consist of total coloumn water data with dimensions: time(124), latitude(15), and longitude(15). I would appropriate the amount of tcw for specific point (lat,lon), and time. I tried to use the code above to solve the first part of my task to evaluate the tcw for specific coorinates, but didn't work.
Thank your help in advance.
in python you can write
var1, var2 = (1, 2) # = iterable with 2 items
that will store 1 in var1 and 2 in var2.
This feature is called unpacking.
So the error your code throws means, that the function getclosest_ij returned one value instead of the 2 values you would need to unpack them into iy_min and ix_min

VIM, Python: how do you use range objects generated by vim.current.range

function! Cut()
python3 << EOF
import vim
cw = vim.current.window
pos = cw.cursor
cr = vim.current.range
x = cr.end - cr.start
vim.command('y')
vim.command(':normal! gv')
print(cr)
print(cr.start)
print(x)
while x:
vim.command('d')
x -= 1
EOF
endfunction
I get:
<range ... (10:10)>
9
0
<range ... (11:11)>
10
0
so on..
Why am i getting multiple print calls - 1 call per line selected?Shouldn't the range object give you the range of lines selected - it's not doing this, instead it's iterating my lines and setting start=current_line_number?
if you want to handle range by yourself in your function, you should add range argument when you declare/define your function. :h function-range-example, then you can in your function get the range information bya:firstline and a:lastline. For example:
function Foo() range
let start = a:firstline
...
endfunction
In this way, you pass the range once to your function. However if you do, as what you did:
function Foo()
echo "foo"
endfunction
then do a 1,10call Foo() , you will see that 10 foo would be printed(echoed). And yes, for each line, your function was invoked.
It is the basic rule, no matter you implement in python or vimscript.

Python bitstring uint seen as long

I have the following:
I read 30 bits from a bitstream:
MMSI = b.readlist('uint:30')
This seems to work normally except when the values get higher.
MMSI = b.readlist('uint:30')
p = 972128254
# repr(MMSI)[:-1]
print p
print "MMSI :"
print MMSI
if MMSI == p:
The code above outputs:
972128254
MMSI :
[972128254L]
The whole if MMSI ==p: is skipped for it is not equal for some reason.
I do not understand why the value that is far lower than max.int:
>>> import sys
>>> sys.maxint
2147483647
I do not understand why I get a Long returned and not a uint?
If the value returned is 244123456 it works like a charm.
2147483647 is maxint, but an int is 32 bits and you're using 30 bits. So your max is 1/4 of that, or about 500 million.
Values will be 'long' if an intermediate value was a long. So for example 2**1000 / 2**999 will equal 2L. This is just to do with the internals of the method you called and shouldn't affect most code.
The real problem is the comparison you have in your code is comparing an int to a list, which is not what you want to do. You can either use the read method rather than readlist to return a single item, or take the first element of the returned list: if MMSI[0] == p:
Aha, I figured that if I read 30bits and returned it as uint value it would automatically be a 32bits value.
So what you are saying is that I would have to add leading zeros to make a 32 bit value and then it should work.
So that is what I have tested and now I am lost.
I figured lets encode the value I want to compare to in the same way. So this is what I did:
from bitarray import bitarray
from bitstring import BitArray, BitStream,pack
from time import sleep
import string
MMSI = b.readlist('uint:30')
x = pack('uint:30',972000000)
p = x.readlist('uint:30')
y = pack('uint:30',972999999)
q = y.read('uint:30')
print p
print q
print x
print y
print MMSI
resulting in:
p = [972000000L]
q = 972999999
x = 0b111001111011111000101100000000
y = 0b111001111111101100110100111111
MMSI = [972128254L]
How can it be that the higher value 972999999 is not a long?

Categories

Resources