mulitple loop for reading bands in python - python

i want to read separate table from images in python. i have 10 images (b1,b2,b3....b10) with 8 bands in which I have to proceed this functions
b1 = rasterio.open('B1.tif')
b2 = rasterio.open('B2.tif')
b3 = rasterio.open('B3.tif')
...
b10 = rasterio.open('B10.tif')
I started to try this with just one loop and the update. but this error appears
b1 = rasterio.open('B1.tif')
for i in range(1,8):
b1_(i) = b1.read(i)
File "<ipython-input-4-c7fe8df05d17>", line 3
b1_(i) = b1.read(i)
^
SyntaxError: cannot assign to function call

I guess you assume, that the python interpreter will resolve b1_(i) to e.g. b1_10 if i equals 10 in that loop. That however is not part of the python language definition. In fact, and as the error states, this syntax looks like a function invocation to the interpreter (of the function b1_ with argument i).
For your code to be able to be interpretet, (but be aware, this is a bad habit of coding and I will suggest a possible solution below,) you could replace b1_(i) = b1.read(i) by eval("b1_"+str(i)+"b1.read("+str(i)+")"). eval is a function, which takes a string and evaluates it as a line of code.
As mentioned, this is bad coding style. Code using eval is much harder to read, as this simple example should already sufficiently show. Furthermore, eval is in some situations susceptible to code injection, which may lead to security issues. (Especially, if eval is used to execute a piece of code, which contains data entered from a user, who could use this fact to inject malicious code on his own.) There are also other issues, but to discuss that further would unnessesarily bloat this answer; you may consider doing some research on yourself here.
So how to do it right? The best way would be to use an array of values instead of many different variables. You can do that in python like this:
fp_b1 = rasterio.open('B1.tif')
store_b1 = []
for i in range(1,9):
store_b1[i] = fp_b1.read(i)
Note, that I had also to change the parameters of range, since range will not include stop.
As array generally start with index 0 in python (and many other programming languages), this code would probably be written rather like this:
fp_b1 = rasterio.open('B1.tif')
store_b1 = []
for i in range(8):
store_b1[i] = fp_b1.read(i+1)

Related

Difference between similar looking Python for-loops?

I was curious about the way this
for _ in range(10): #1
loop#1 execution is different from
for i in range(10): #2
loop#2 execution. They certainly do look exactly the same, but, I wanted to have a clear understanding and know if their functioning under the hood is also exactly the same? Also, I know when both these types of loops are used, so, I am not looking for an answer to "When to use What?".
I had already read this question, but, it doesn't provide a clear distinction and the working of the two under the hood.
They both do the exact same thing
The former is used if the variable is disposable and not usually referenced in the loop
for _ in range(10): #1
The latter is used if you plan to reference the variable name within the loop
for i in range(10): #2
It's boils down to the python naming convention -- under the hood, both loops function in the exact same way
in python the underscore character it's a valid var name, so bot snippets are the same but with different var names, like #AK47 says, use de under score if you don't want use the var inside the loop, but the _ it's a valid var name so you can used inside the loop:
some frameworks like django use the underscore in their code patterns:

How to assign result to a variable AND print result in one command in Python?

In R, when you assign something to a variable, you can wrap your code in brackets to also print the result:
> a<-1+2
> a
3
>(a<-1+2)
3
Is there an equivalent feature in python?
No. You can't mix statements and expressions in the same "command".
You can, however, use ; to have both on the same "line":
a = 1 ; print(a)
# 1
There is no single statement which allows to that.
First we have assignment statements. Which allow to, well, make assignments.
And then you have either a print function (for Python 3.x) or a print statement (for Python 2.x). But neither of them cannot be mixed with the aforementioned assignemnt statement.
So no, you cannot do that in a single statement. You can, of couse, cheat that into one line by using ; but that is something not very readable which I would not recommend.
Bonun non-aswering rambling
From a readability point of view, assigning and printing are two very different things which should not be mixed.
Moreover, if you are (for instance) using a logging library instead of direct print usage, then the "single statement" you are looking for would become useless. In fact, I think that that is a rationale behind moving print from statement to function.
So, you don't have a single statement for assign-and-print and, I will add, that kind of statement doesn't seem a good idea in the Python language.

When is it required to define a separate function in Python

In my code, I am printing a menu
print(num_chars * char)
for option in options:
print("{:d}. {:s}".format(option, options[option]))
print(num_chars * char)
The code print(num_chars * char) prints a separator/delimiter in order to "beautify" the output. I have learned from several coding tutorials that I am not allowed to write the same code more than once.
Is it really preferable to define a function
def get_char_repeated(char='*', num_chars=30):
"""
Return the character repeated an arbitrary number of times
"""
return num_chars * char
and call this two times in my original code?
Are there any alternatives if I need to print nice looking menu from a dictionary?
Thank you.
I have learned from several coding tutorials that I am not allowed to write the same code more than once.
This principle, called "don't repeat yourself" (DRY) is a good rough guideline. For every programmer who writes too many functions (splitting code into too small units), there are 20 who write too few.
Don't go overboard with it, though. The reasoning behind DRY is to make reading and changing the code later on easier. print(num_chars * char) is pretty basic already, and super-easy to understand and change, so it doesn't really pay off to factor it into a function.
If the repeated code grows to 3 lines, you can (and probably should) factor it out then.
It's not necessary at that level. What might be helpful is if you were often doing that whole block of code, you could easily change it to
def printOptions(options, char='*', num_chars=30):
print(num_chars * char)
for option in options:
print("{:d}. {:s}".format(option, options[option]))
print(num_chars * char)
The main point of functions is to save time with blocks of code you use a lot in a very similar way by not retyping/copy pasting them. But they also save time when you make changes. If you used the same function in 10 different places you still only need to change it once for all 10 uses to be updated rather than having to find all 10 manually and update them.
So if you decided you wanted to put a title header into this menu printing section and you had used it as this or a similar function in a bunch of places, you could quite easily update them all without difficulty.
I find it a good rule, that if the code you're turning into a function is used more than once and takes up more than 3 lines, it is a candidate to be turned into a function. If it is a very complex single line of code (like this x = [ i**j for i in z for j in y ]) and is used more than twice, it could be a candidate to turn into a function.
It may be a matter of preference where you draw the line but the basic idea is if it makes your code easier to read or easier to write, turning something into a function can be a good idea. If it makes your code harder to read (because every time you see the function you have to look back at the specifics of what it does), you probably should not have turned that code into a function.

Python - disposable ifs

While writing state machines to analyze different types of text data, independent of language used (VBA to process .xls contents using arrays/dictionaries or PHP/Python to make SQL insert queries out of .csv's) I often ran into neccesity of something like
boolean = False
while %sample statement%:
x = 'many different things'
if boolean == False:
boolean = True
else:
%action that DOES depend on contents of x
that need to do every BUT first time I get to it%
Every time I have to use a construction like this, I can't help feeling noob. Dear algorithmic gurus, can you assure me that it's the only way out and there is nothing more elegant? Any way to specify that some statement should be "burnt after reading"? So that some stupid boolean is not going to be checked each iteration of the loop
The only things that come across as slightly "noob" about this style are:
Comparing a boolean variable to True or False. Just write if <var> or if not <var>. (I'll ignore the = vs == as a typo!)
Not giving the boolean variable a good name. I know that here boolean is just a placeholder name, but in general using a name like first_item_seen rather than something generic can make the code a lot more readable:
first_item_seen = False
while [...]:
[...]
if first_item_seen:
[...]
else:
first_item_seen = True
Another suggestion that can work in some circumstances is to base the decision on another variable that naturally conveys the same state. For instance, it's relatively common to have a variable that contains None for the first iteration, but contains a value for later iterations (e.g. the result so far); using this can make the code slightly more efficient and often slightly clearer.
If I understand your problem correctly, I'd try something like
x = 'many different things'
while %sample statements%:
x = 'many different things'
action_that_depends_on_x()
It is almost equivalent; the only difference is that in your version the loop body could be never executed (hence x never being computed, hence no side effects of computing x), in my version it is always computed at least once.

Python - using a string in for in statement?

so i know this is a bit of a workaround and theres probably a better way to do this, but heres the deal. Ive simplified the code from where tis gathering this info from and just given solid values.
curSel = nuke.selectedNodes()
knobToChange = "label"
codeIn = "[value in]"
kcPrefix = "x"
kcStart = "['"
kcEnd = "']"
changerString = kcPrefix+kcStart+knobToChange+kcEnd
for x in curSel:
changerString.setValue(codeIn)
But i get the error i figured i would - which is that a string has no attribute "setValue"
its because if i just type x['label'] instead of changerString, it works, but even though changer string says the exact same thing, its being read as a string instead of code.
Any ideas?
It looks like you're looking for something to evaluate the string into a python object based on your current namespace. One way to do that would be to use the globals dictionary:
globals()['x']['label'].setValue(...)
In other words, globals()['x']['label'] is the same thing as x['label'].
Or to spell it out explicitly for your case:
globals()[kcPrefix][knobToChange].setValue(codeIn)
Others might suggest eval:
eval('x["label"]').setValue(...) #insecure and inefficient
but globals is definitely a better idea here.
Finally, usually when you want to do something like this, you're better off using a dictionary or some other sort of data structure in the first place to keep your data more organized
Righto, there's two things you're falling afoul of. Firstly, in your original code where you are trying to do the setValue() call on a string you're right in that it won't work. Ideally use one of the two calls (x.knob('name_of_the_knob') or x['name_of_the_knob'], whichever is consistent with your project/facility/personal style) to get and set the value of the knob object.
From the comments, your code would look like this (my comments added for other people who aren't quite as au fait with Nuke):
# select all the nodes
curSel = nuke.selectedNodes()
# nuke.thisNode() returns the script's context
# i.e. the node from which the script was invoked
knobToChange = nuke.thisNode()['knobname'].getValue()
codeIn = nuke.thisNode()['codeinput'].getValue()
for x in curSel:
x.knob(knobToChange).setValue(codeIn)
Using this sample UI with the values in the two fields as shown and the button firing off the script...
...this code is going to give you an error message of 'Nothing is named "foo"' when you execute it because the .getValue() call is actually returning you the evaluated result of the knob - which is the error message as it tries to execute the TCL [value foo], and finds that there isn't any object named foo.
What you should ideally do is instead invoke .toScript() which returns the raw text.
# select all the nodes
curSel = nuke.selectedNodes()
# nuke.thisNode() returns the script's context
# i.e. the node from which the script was invoked
knobToChange = nuke.thisNode()['knobname'].toScript()
codeIn = nuke.thisNode()['codeinput'].toScript()
for x in curSel:
x.knob(knobToChange).setValue(codeIn)
You can sidestep this problem as you've noted by building up a string, adding in square brackets etc etc as per your original code, but yes, it's a pain, a maintenance nightmare, and starting to go down that route of building objects up from strings (which #mgilson explains how to do in both a globals() or eval() method)
For those who haven't had the joy of working with Nuke, here's a small screencap that may (or may not..) provide more context:

Categories