__xor__ in functools.reduce() causing error - python

I'm currently working in python 3 with the Discord API and I want to use a module that was written in python 2. I'm editing some of the code for it to work with python 3. Something I can't figure out is this:
odd_xor = reduce(__xor__, bh) >> 16
This works in python 2 but doesn't in python 3. The simple fix that I thought would work was:
odd_xor = functools.reduce(__xor__, bh) >> 16
but this gives me the error:
reduce() of empty sequence with no initial value
bh is initialized here:
# bh stands for binary hand, map to that representation
card_to_binary = HandEvaluator.Six.card_to_binary_lookup
bh = map(card_to_binary, hand)
I don't really understand what the code segment is trying to do which is why it is so difficult for me to find a solution to this problem. Any thoughts? Thanks in advance!
P.S. if there is an easier way to use python 2 modules with python 3 projects, please enlighten me.

In Python 3, map returns a lazy iterator (much like a generator), rather than a list the way it did in Python 2. This may be the cause of your issue.
In your code, you do map(card_to_binary, hand). If hand gets changed (e.g. emptied) before you use the result, you may not get what you want (e.g. the map may end up iterating over nothing).
To make the code work the same as Python 2, you can simply call list on the iterator you get from map:
bh = list(map(card_to_binary, hand))
Alternatively, you could change other code that modifies hand so that it does something different, perhaps making a new list, copying the list before modifying it, or only modifying hand in place after the reduce call has been completed.

The said error occurs when the sequence passed as the second argument of reduce is empty, which means bh is an empty sequence when the error occurs.
Since bh is initialized with another sequence, hand, you need to find out why hand is empty in the first place.

Related

mulitple loop for reading bands in 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)

Is there a way to change a Python object's byte representation at run-time?

The goal is to simulate a high-radiation environment.
Normally, code like the following:
a = 5
print(a)
print(a)
would print:
5
5
I want to be able to change the underlying byte representation of a randomly during runtime (according to some predefined function that takes a seed). In that case, the following code:
a = RandomlyChangingInteger(5)
print(a)
print(a)
could result in:
4
2
One way this can be done for languages like C and C++ is to insert extra instructions that could potentially modify a, before every usage of a in the compiled code.
Something like BITFLIPS (which uses valgrind) is what I'm thinking about.
Is this even possible in Python?
You can do it, sort of. The built-in int is immutable, therefore you cannot modify its value. You can, however, create a custom class that emulates an int:
import random
class RandomlyChangingInteger(object):
def __int__(self):
return random.randint(0, 10)
def __str__(self):
return str(self.__int__())
then
a = RandomlyChangingInteger()
print(a)
print(a)
should print something like
4
5
Note that you can't use this class to do math as it stands. You must implement other int methods (such as __add__, __mul__, etc) first.
You're trying to simulate radiation-induced bitflips, but your expectations of what that would do are way off target. Radiation effects are much more likely to crash a Python program than they are to change an object's value to another valid value. This makes simulating radiation effects not very useful.
The CPython implementation relies on so many pointers and so much indirection that after a few bit flips in your data, at least one of them is almost certain to hit something that causes a crash. Perhaps corrupting an object's type pointer, causing a bad memory access the next time you try to do almost anything with the object, or perhaps corrupting a reference count, causing an object to be freed while still in use. Maybe corrupting the length of an int (Python ints are variable-width), causing Python to try to read past the end of the allocation.
Where a C array of ints might just be a giant block of numerical data, where random bit corruption could be detected or managed, a Python list of ints is mostly pointers and other metadata.
If you really want to simulate random bit flips, the best way to go would likely be to rebuild CPython with a tool like the BITFLIPS thing you linked.

How to assign the same value to multiple variables in Python

I have a question about Python, which I am kinda new to. Let's assume I want to assign a 5x5 matrix to 10 different variables. I searched across the board, and what I found was this:
a, b, c, d, e = myMatrix
That is all good, but in Python, this means that when I change a, I also change the values of the other variables, because they all come down to the same memory adress if I got this correctly.
My question: Is there a fast way of assigning myMatrix to multiple Variables and giving each of them a unique memory adress? So that I can change myMatrix without changing a, b or c. I do explicitly search for some kind of multi-assignment.
Thanks in advance!
use the [copy] module
>>> import copy
>>> new_matrix = copy.deepcopy(myMatrix)
As Burhan Khalid and juanchopanza have pointed out, what happens in your example will be different in, for example,
the case where "myMatrix" is actually an array of 5 values (in which case "a" will get the first value and "e" will get the last value), and
the case where "myMatrix" is an instance of an Object (in which case "a" through "e" will each refer to the same object).
It sounds like you're thinking of case 2, and hoping for something like a macro which will automatically expand your single assignment statement (with a single Right Hand Side Value, whether Deep Copied or not) into 5 assignment statements, each with its own Left Hand Side, Right Hand Side, and Deep Copy.
I don't know of any way to do this, and I would point out that:
When most OO languages encounter an assignment operation like yours with an Object on the Right Hand Side, the compiler/interpreter looks for a "copy constructor" for the class of the RHS Object, and uses it (if found) to generate the value (an Object reference) which is actually assigned to the LHS. Can you even imagine what the syntax could look like for what you're describing, where the copy constructor is supposed to be called 5 times to yield 5 different Objects on the RHS, references to which are then assigned to five different variables on the LHS? What could you possibly write in a single assignment statement that would make this intent clear?
If you're writing code where Deep vs. Shallow copies will actually have an effect on behavior then IMHO you owe it to yourself and anyone else who has to read and maintain your code to make this obvious and explicit - like the answer from wong2, repeated 5 times (once for each of the 5 variables).

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:

Modifying variables in Python function is affecting variables with different names outside the function

I have a nested dictionary containing a bunch of data on a number of different objects (where I mean object in the non-programming sense of the word). The format of the dictionary is allData[i][someDataType], where i is a number designation of the object that I have data on, and someDataType is a specific data array associated with the object in question.
Now, I have a function that I have defined that requires a particular data array for a calculation to be performed for each object. The data array is called cleanFDF. So I feed this to my function, along with a bunch of other things it requires to work. I call it like this:
rm.analyze4complexity(allData[i]['cleanFDF'], other data, other data, other data)
Inside the function itself, I straight away re-assign the cleanFDF data to another variable name, namely clFDF. I.e. The end result is:
clFDF = allData[i]['cleanFDF']
I then have to zero out all of the data that lies below a certain threshold, as such:
clFDF[ clFDF < threshold ] = 0
OK - the function works as it is supposed to. But now when I try to plot the original cleanFDF data back in the main script, the entries that got zeroed out in clFDF are also zeroed out in allData[i]['cleanFDF']. WTF? Obviously something is happening here that I do not understand.
To make matters even weirder (from my point of view), I've tried to do a bodgy kludge to get around this by 'saving' the array to another variable before calling the function. I.e. I do
saveFDF = allData[i]['cleanFDF']
then run the function, then update the cleanFDF entry with the 'saved' data:
allData[i].update( {'cleanFDF':saveFDF} )
but somehow, simply by performing clFDF[ clFDF < threshold ] = 0 within the function modifies clFDF, saveFDF and allData[i]['cleanFDF'] in the main friggin' script, zeroing out all the entires at the same array indexes! It is like they are all associated global variables somehow, but I've made no such declarations anywhere...
I am a hopeless Python newbie, so no doubt I'm not understanding something about how it works. Any help would be greatly appreciated!
You are passing the value at allData[i]['cleanFDF'] by reference (decent explanation at https://stackoverflow.com/a/430958/337678). Any changes made to it will be made to the object it refers to, which is still the same object as the original, just assigned to a different variable.
Making a deep copy of the data will likely fix your issue (Python has a deepcopy library that should do the trick ;)).
Everything is a reference in Python.
def function(y):
y.append('yes')
return y
example = list()
function(example)
print(example)
it would return ['yes'] even though i am not directly changing the variable 'example'.
See Why does list.append evaluate to false?, Python append() vs. + operator on lists, why do these give different results?, Python lists append return value.

Categories