Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
QuarkJets
Sep 8, 2008

Jose Cuervo posted:

For better or worse I chose PySide and am having reasonable success. I can make the tabbed layout work as accipter suggested below by locking the tabs (disabling them), and maybe if I have more time on my hands than I know what to do with I will look into prettying things up.


So the for loop that iterates over the n simulation replications is in the main_gui function. Each time a simulation replication is completed, I would like the progress bar to update. I don't know how I would send a signal from the for loop in main_gui to the progress bar. Any pointers?

New questions:
In one of my tabs I have a button that, when clicked, dynamically adds a QGroupBox of widgets to the tab. By clicking multiple times on the button you can add multiple QGroupBoxes of the widgets. My problem now is determining how to access/ reference the dynamically added QGroupBoxes and the widgets inside of them. Here is the code:

Python code:
snip
Eventually I need to be able to access the type of fuel selected in each group box, the capacity of the tanker in each group box, and the number of tankers of that type. For right now I was trying to update the title of the group box using signals (specifically the currentIndexChanged signal of the QComboBox). What happens though is that if I add two group boxes, and then try to change the type of fuel in the first QComboBox, it is actually the title of the second group box that changes.

Any insight into why this is happening/ how to change it would be nice. Also any advice on how to access the type of fuel etc in each dynamically added widget.

Each time that you call add_tanker_type, you're explicitly reassigning the contents of self.tanker_type_gb. Since modify_gb_title is operating on self.tanker_type_gb, it's operating on whatever was last assigned.

One thing that you can do instead is append to an internal list of that holds QGroupBox items, then in modify_gb_title you modify the title of whatever index has been selected. You can do this because the currentIndexChanged signal won't just call the function that you connect to it, it'll also call that function with the value of the new index (if you let it).

Python code:
   def __init__(self, the_parent):
        .... # code to initialize class
        self.tanker_type_gb_list = []

    def add_tanker_type(self):
        tanker_type_gb_new = QtGui.QGroupBox("Tanker Type %s" % (len(self.tanker_type_gb_list) + 1), self)
        tanker_type_gb_new.setMaximumHeight(100)
        self.tanker_type_gb_list.append(tanker_type_gb_new)
        tanker_type_fl = QtGui.QFormLayout()
        tanker_fuel = QtGui.QComboBox()
        tanker_fuel.addItem("Diesel")
        tanker_fuel.addItem("Regular")
        tanker_fuel.addItem("Supreme")
        tanker_fuel.currentIndexChanged.connect(self.modify_gb_title)
       .... # other code in this method

    # QComboBox.currentIndexChanged comes with an integer for the new index!
    def modify_gb_title(self, ind):
        tanker_type_gb = self.tanker_type_gb_list[ind]
        current_title = tanker_type_gb.title()
        ... # etc
See http://doc.qt.io/qt-4.8/qcombobox.html#currentIndex-prop
Basically QComboBox.currentIndexChanged will call whatever function that you give it with an integer, if you let it. That integer is the new selected index in that QComboBox. By passing that integer to modify_gb_title, you can modify the correct QGroupBox by using that index to access your list of QGroupBox items.

This also solves the problem where you don't have easy access to those QGroupBox items. Instead of reassigning an attribute each time that you create a new QGroupBox, just append the new QGroupBox to a list. Then you have access to any of the created QGroupBox items.

Adbot
ADBOT LOVES YOU

SurgicalOntologist
Jun 17, 2004

Fergus Mac Roich posted:

It's better if the object doesn't know how to construct its dependencies. If the dependencies are available via the API at the time you construct the object, you should make the API call somewhere in the calling code and then supply the dependencies as arguments to the constructor. Or maybe I write too much java.

This is what I typically do as well. I try to make the only logic in __init__ be assigning parameters to attributes. If I want to supply these by some kind of dependency I will make a classmethod, e.g. Employee.from_file, Employee.from_api, whatever.

accipter
Sep 12, 2003

Jose Cuervo posted:

So the for loop that iterates over the n simulation replications is in the main_gui function. Each time a simulation replication is completed, I would like the progress bar to update. I don't know how I would send a signal from the for loop in main_gui to the progress bar. Any pointers?

Take a look at this simple example: https://gist.github.com/arkottke/7c1c33fc6fd697cde9c88c2b47fa06ea

I would also point you to the mandelbrot example (https://github.com/PySide/Examples/blob/master/examples/threads/mandelbrot.py).

Jose Cuervo
Aug 25, 2004

QuarkJets posted:

Each time that you call add_tanker_type, you're explicitly reassigning the contents of self.tanker_type_gb. Since modify_gb_title is operating on self.tanker_type_gb, it's operating on whatever was last assigned.

One thing that you can do instead is append to an internal list of that holds QGroupBox items, then in modify_gb_title you modify the title of whatever index has been selected. You can do this because the currentIndexChanged signal won't just call the function that you connect to it, it'll also call that function with the value of the new index (if you let it).

Python code:
   def __init__(self, the_parent):
        .... # code to initialize class
        self.tanker_type_gb_list = []

    def add_tanker_type(self):
        tanker_type_gb_new = QtGui.QGroupBox("Tanker Type %s" % (len(self.tanker_type_gb_list) + 1), self)
        tanker_type_gb_new.setMaximumHeight(100)
        self.tanker_type_gb_list.append(tanker_type_gb_new)
        tanker_type_fl = QtGui.QFormLayout()
        tanker_fuel = QtGui.QComboBox()
        tanker_fuel.addItem("Diesel")
        tanker_fuel.addItem("Regular")
        tanker_fuel.addItem("Supreme")
        tanker_fuel.currentIndexChanged.connect(self.modify_gb_title)
       .... # other code in this method

    # QComboBox.currentIndexChanged comes with an integer for the new index!
    def modify_gb_title(self, ind):
        tanker_type_gb = self.tanker_type_gb_list[ind]
        current_title = tanker_type_gb.title()
        ... # etc
See http://doc.qt.io/qt-4.8/qcombobox.html#currentIndex-prop
Basically QComboBox.currentIndexChanged will call whatever function that you give it with an integer, if you let it. That integer is the new selected index in that QComboBox. By passing that integer to modify_gb_title, you can modify the correct QGroupBox by using that index to access your list of QGroupBox items.

This also solves the problem where you don't have easy access to those QGroupBox items. Instead of reassigning an attribute each time that you create a new QGroupBox, just append the new QGroupBox to a list. Then you have access to any of the created QGroupBox items.

If I understand the code correctly, modify_gb_title is now being passed the index of the option selected in the QComboBox, correct? If so, the line tanker_type_gb = self.tanker_type_gb_list[ind] will not work because ind does NOT refer to the index of the QGroupBox whose QComboBox was changed, correct? So how do I get a reference to the QGroupBox that had a child widget edited?

Assuming I am able to figure out how to get the index of the QGroupBox that had a child widget edited, I would now like to find the QLineEdit corresponding to the row in the QFormLayout titled 'Number of tankers'. I know I can get a reference to the QFormLayout with:
Python code:
for widget in tanker_type_gb.children():
     if isinstance(widget, QtGui.QFormLayout):
         print widget.children()
but the call to widget.children() returns an empty list. However the call to tanker_type_gb.children() returns a list that does contain the QLabels and QLineEdits:
Python code:
print tanker_type_gb.children()
[<PySide.QtGui.QFormLayout object at 0x07D4D198>, <PySide.QtGui.QLabel object at 0x07D4D260>, <PySide.QtGui.QComboBox object at 0x07D4D1E8>, 
<PySide.QtGui.QLabel object at 0x07D4D288>, <PySide.QtGui.QLineEdit object at 0x07D4D210>, 
<PySide.QtGui.QLabel object at 0x07D4D2B0>, <PySide.QtGui.QLineEdit object at 0x07D4D238>]
Can I always expect that tanker_type_gb.children()[1] and tanker_type_gb.children()[2] will be the QLabel and QLineEdit respectively corresponding to the first row in QFormLayout? If not, what it the idiomatic way to look through this list and find the QLineEdit corresponding to the QLabel with text "Number of tankers'?

Jose Cuervo
Aug 25, 2004

Thank you for this example, I am looking through it currently and trying to make sure I understand what everything does.

EDIT:
I think I now have a better grasp on signals and slots. updateRange is a signal that sends out two values (min and max of the range), and you connect it to self.progressBar.setRange which is a slot that takes two values, correct?

The .emit() part means that the signal gets sent, correct?

I am still running into the warning message from the joblib library. Is the answer to that in the Mandelbrot example? I haven't had a chance to look at it line by line, but on a quick read through I did not see that I could find the answer to the joblib question in there.

Jose Cuervo fucked around with this message at 18:01 on Apr 14, 2016

accipter
Sep 12, 2003

Jose Cuervo posted:

Thank you for this example, I am looking through it currently and trying to make sure I understand what everything does.

EDIT:
I think I now have a better grasp on signals and slots. updateRange is a signal that sends out two values (min and max of the range), and you connect it to self.progressBar.setRange which is a slot that takes two values, correct?

The .emit() part means that the signal gets sent, correct?

I am still running into the warning message from the joblib library. Is the answer to that in the Mandelbrot example? I haven't had a chance to look at it line by line, but on a quick read through I did not see that I could find the answer to the joblib question in there.

Emit sends data out. If nothing is connected to that signal nothing happens s. Slots and Signals are the way to transfer data betweens objects.

In your code it looks like you are passing your main window instance to the simulation class. I don't know why you are doing that and I would guess that's the issue. You need to listen to the simulation class's signals instead of directly interacting with it.

creatine
Jan 27, 2012




Ok so I have this problem that I can't seem to figure out the best way to approach:

I have two lists

list1 = A bunch of strings
list2 = another group of strings that are also all present in list1

What I want to do is take every item in list2 and check if it's in list1. If it is found then it should be removed from the corresponding item. The problem is that the list2 items are embedded within the list1 items, surrounded by other things. So what I was trying to do was figure a way to insert the list2 item into a regex search and then check that against the items in list1.

QuarkJets
Sep 8, 2008

Jose Cuervo posted:

If I understand the code correctly, modify_gb_title is now being passed the index of the option selected in the QComboBox, correct? If so, the line tanker_type_gb = self.tanker_type_gb_list[ind] will not work because ind does NOT refer to the index of the QGroupBox whose QComboBox was changed, correct? So how do I get a reference to the QGroupBox that had a child widget edited?

Oh, right, my bad.

You could create a subclass of QGroupBox (for demonstration purposes I'll call it Foo) that contains a QComboBox, and then you connect the items' signals to a Foo method, which would then cause that Foo instance to change its own title. That would do it for sure, since each QComboBox would be emitting a signal that is only connected to its own instance of the Foo class.

quote:

Assuming I am able to figure out how to get the index of the QGroupBox that had a child widget edited, I would now like to find the QLineEdit corresponding to the row in the QFormLayout titled 'Number of tankers'. I know I can get a reference to the QFormLayout with:
Python code:
snip
but the call to widget.children() returns an empty list. However the call to tanker_type_gb.children() returns a list that does contain the QLabels and QLineEdits:
Python code:
snip
Can I always expect that tanker_type_gb.children()[1] and tanker_type_gb.children()[2] will be the QLabel and QLineEdit respectively corresponding to the first row in QFormLayout? If not, what it the idiomatic way to look through this list and find the QLineEdit corresponding to the QLabel with text "Number of tankers'?

If you never change the order in which you're adding things to the QFormLayout, then yes, that children order will be the same every time. Don't do this though, because it's sloppy and a very fragile implementation. If you just define your own TankerType class then you can easily avoid having to do that.

QuarkJets
Sep 8, 2008

Pumpy Dumper posted:

Ok so I have this problem that I can't seem to figure out the best way to approach:

I have two lists

list1 = A bunch of strings
list2 = another group of strings that are also all present in list1

What I want to do is take every item in list2 and check if it's in list1. If it is found then it should be removed from the corresponding item. The problem is that the list2 items are embedded within the list1 items, surrounded by other things. So what I was trying to do was figure a way to insert the list2 item into a regex search and then check that against the items in list1.

Not sure if I understand the question, but something like this?

Python code:
# Predefined stuff
list1 = ["a", "b", "c", "d", "e"]
list2 = ["c", "e"]

# Okay let's get to work
set2 = set(list2)
list1_trimmed = [item for item in list1 if item not in set2]

GameCube
Nov 21, 2006

code:
set(list1).difference(list2)

creatine
Jan 27, 2012




Sweet thanks. I actually learned an easier way to do what I wanted originally but that will come in handy later.

Jose Cuervo
Aug 25, 2004

QuarkJets posted:

Oh, right, my bad.

You could create a subclass of QGroupBox (for demonstration purposes I'll call it Foo) that contains a QComboBox, and then you connect the items' signals to a Foo method, which would then cause that Foo instance to change its own title. That would do it for sure, since each QComboBox would be emitting a signal that is only connected to its own instance of the Foo class.


If you never change the order in which you're adding things to the QFormLayout, then yes, that children order will be the same every time. Don't do this though, because it's sloppy and a very fragile implementation. If you just define your own TankerType class then you can easily avoid having to do that.

OK, I will rewrite the code as a class.

Slots/Signals question:

I would like to run a function that takes arguments (for instance my_func(int, str, int)) when a QtGui.QPushButton is clicked. The following code
Python code:
my_btn = QtGui.QPushButton()
my_btn.clicked.connect(my_func(my_int, my_str, my_second_int))
produces the following RuntimeError: Failed to connect signal clicked().

How can I accomplish this?

accipter
Sep 12, 2003

Jose Cuervo posted:

Slots/Signals question:

I would like to run a function that takes arguments (for instance my_func(int, str, int)) when a QtGui.QPushButton is clicked. The following code
Python code:
my_btn = QtGui.QPushButton()
my_btn.clicked.connect(my_func(my_int, my_str, my_second_int))
produces the following RuntimeError: Failed to connect signal clicked().

How can I accomplish this?

That's impossible. The "clicked" signal passes no arguments. The way you get around this is that you can create another method that takes no arguments and retrieves values from the GUI widgets and passes them to my_func.

fritz
Jul 26, 2003

I'm working on a python thing where I have to talk with a server over tcp on the same host, and I'm seeing quite a lot of latency. I suspect the issue is in how I'm dealing with the socket, but my networking is very rusty. This is how I set it up:

code:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("localhost", 20001))
    fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)
and I read it inside a function:


code:
def receiveFromSocket(s):
    try:
        back = s.recv(1024)
    except socket.error, e:
        # error handling
    return back
(I would like to get sizes down in the 20-40 byte range).


I've tried setting TCP_NODELAY

quote:

s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
without success.

This is on an osx machine, python 2.7, and I've seen the same kind of behavior on linux.

Does anybody have any ideas, or see what I might be doing wrong?

QuarkJets
Sep 8, 2008

Jose Cuervo posted:

OK, I will rewrite the code as a class.

Slots/Signals question:

I would like to run a function that takes arguments (for instance my_func(int, str, int)) when a QtGui.QPushButton is clicked. The following code
Python code:
my_btn = QtGui.QPushButton()
my_btn.clicked.connect(my_func(my_int, my_str, my_second_int))
produces the following RuntimeError: Failed to connect signal clicked().

How can I accomplish this?

I was going to say what accipter already said. You need to examine the signal being emitted (by reading the docs for QPushButton) and then define a function that can be connected to that signal, and that function can expect to receive the same argument types (or fewer). Write a function that expects no arguments and that calls my_func, and then connect that function to QPushButton.clicked. Alternatively, you could turn my_int, my_str, my_second_int, and my_func into class members, eliminating the need for my_func to expect any arguments at all, then connect self.my_func to QPushButton.clicked

Lpzie
Nov 20, 2006

Does anybody have experience with scipy's interpolate.griddata? I have 3 1d arrays that I want interpolated with the purpose of retrieving values. This is in python 2.7.

I have:

Python code:
import numpy as np
from scipy import interpolate

x = [ long array ]
y = [ long array ]
z = [ long array ]

#creates the grid
xi,yi = np.mgrid[ min(x):max(x):2000j, min(y):max(y):2000j ]

#interpolates
zi = scipy.interpolate.griddata( (x,y), z, (xi, yi), method='cubic' )
Now I need to be able to give zi any x and y value that's within the domain given by xi,yi and retrieve an interpolated z value. Does anybody know how to do this? (I'm not even sure if my interpolation method is right, tbh. Cannot test it without z values to compare.)




Edit: Nvm. I figured it out. I was complicating things. Simply using zi = scipy.interpolate.interp2d(x,y,z, kind='cubic') and then doing zi_ = zi(x_, y_) where x_ and y_ are the values I want interpolated works.

Lpzie fucked around with this message at 23:01 on Apr 20, 2016

Mr. Crow
May 22, 2008

Snap City mayor for life
This is probably more of an IDE question, but is there any way to get code completion from a .NET DLL in IntelliJ/PyCharm, either natively or through some document specification?

Have a cross language engine and API using Iron Python and it would be nice to have documentation in editor.

creatine
Jan 27, 2012




Question: I don't really understand how zip() works. I managed to find an example to create tuples of n=2 with the following code:

code:
	
def pairwise(self, iterable):
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)
But I want to change it so that it creates tuples of three, and I can't really figure out how to do that. If I just add another variable c it prints tuples of 3 but the first two items repeat themselves.

edit: was able to get it working with the following code:

code:
	
def pairwise(self, iterable):
    a = iter(iterable)
    b = iter(iterable[1::])
    c = iter(iterable[2::])		
    return zip(a, b, c)
And it seems to work great

creatine fucked around with this message at 23:48 on Apr 21, 2016

QuarkJets
Sep 8, 2008

Pumpy Dumper posted:

Question: I don't really understand how zip() works. I managed to find an example to create tuples of n=2 with the following code:

code:
	
def pairwise(self, iterable):
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)
But I want to change it so that it creates tuples of three, and I can't really figure out how to do that. If I just add another variable c it prints tuples of 3 but the first two items repeat themselves.

The zip function takes any number of iterables and returns an iterator that returns tuples that exactly match the first, second, third, etc. values of those iterables.
code:
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
iter = zip(a, b, c)
for item in iter:
  print item
# The above prints (1, 4, 7), then (2, 5, 8), then (3, 6, 9)
If this is the behavior that you want, but not the behavior that you're getting, then there's likely something happening with your inputs that you didn't expect. Check your inputs to make sure that they're returning the values that you expect and in the order that you expect them

e: Sounds like you've fixed the issue :)

creatine
Jan 27, 2012




QuarkJets posted:

The zip function takes any number of iterables and returns an iterator that returns tuples that exactly match the first, second, third, etc. values of those iterables.
code:
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
iter = zip(a, b, c)
for item in iter:
  print item
# The above prints (1, 4, 7), then (2, 5, 8), then (3, 6, 9)
If this is the behavior that you want, but not the behavior that you're getting, then there's likely something happening with your inputs that you didn't expect. Check your inputs to make sure that they're returning the values that you expect and in the order that you expect them

e: Sounds like you've fixed the issue :)

Yeah the problem was I was coming from one list and I wanted to create tuples of 3 using 3 different starting points.

Gangsta Lean
Dec 3, 2001

Calm, relaxed...what could be more fulfilling?

Pumpy Dumper posted:

Question: I don't really understand how zip() works. I managed to find an example to create tuples of n=2 with the following code:

code:
	
def pairwise(self, iterable):
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)
But I want to change it so that it creates tuples of three, and I can't really figure out how to do that. If I just add another variable c it prints tuples of 3 but the first two items repeat themselves.

edit: was able to get it working with the following code:

code:
	
def pairwise(self, iterable):
    a = iter(iterable)
    b = iter(iterable[1::])
    c = iter(iterable[2::])		
    return zip(a, b, c)
And it seems to work great


Your original question is, How does zip() work?
It takes any number of iterables, and iterates over all of them simultaneously. A list is an iterable, a tuple is an iterable, a dictionary is iterable, a set is iterable, a string is iterable. Even classes you create can be iterable. Here's an example using two lists.
code:
items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
items2 = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

for x in zip(items1, items2):
	print(x)

#Result is:
# (0, 10)
# (1, 11)
# (2, 12)
# (3, 13)
# (4, 14)
# (5, 15)
# (6, 16)
# (7, 17)
# (8, 18)
# (9, 19)
Your edited definition of pairwise may work for your use case, but
1. It no longer produces a pair, it is a triple - so, pairwise is a bad name for the method.
2. Your method argument is named iterable, but by using slicing, you prevent iterables that don't support slicing.
3. You created multiple (shallow) copies of the input (see further below).

An input that is iterable but doesn't support slicing, such as a dictionary (iterating over a dictionary gives you the keys), does this when using your pairwise function:

code:
items3 = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7}

def pairwise(iterable):
    a = iter(iterable)
    b = iter(iterable[1::])
    c = iter(iterable[2::])		
    return zip(a, b, c)

for x in pairwise(items3):
	print(x)

# Traceback (most recent call last):
#   File "python", line 51, in <module>
#   File "python", line 41, in pairwise
# TypeError: unhashable type: 'slice'
When you used the [1::] syntax, you created a duplicate of your input. You can see this here, because only the first list is affected.
code:
items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
v = items1[1::]
items1[2] = 10000

print(items1)
print(v)

[0, 1, 10000, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

If you want to support all types of iterables, you want to use something more like this:
code:
import itertools

items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
items3 = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7}

def threewise(iterable):
	a, b = itertools.tee(iterable)
	a, c = itertools.tee(iterable)
	next(b, None)
	next(c, None)
	next(c, None)
	return zip(a, b, c)


print('threewise a list')
for x in threewise(items1):
	print(x)
	
print('threewise a dictionary')
for x in threewise(items3):
	print(x)


# threewise a list
# (0, 1, 2)
# (1, 2, 3)
# (2, 3, 4)
# (3, 4, 5)
# (4, 5, 6)
# (5, 6, 7)
# (6, 7, 8)
# (7, 8, 9)
# threewise a dictionary
# ('f', 'c', 'h')
# ('c', 'h', 'a')
# ('h', 'a', 'd')
# ('a', 'd', 'b')
# ('d', 'b', 'g')
# ('b', 'g', 'e')
* itertools.tee() returns two independent iterators from a single iterable, so we can iterate more than once from the same input iterator. We need to do this twice so that we get three independent iterators: a, b, and c. Tee does not duplicate the input. By using it, it allows each of a, b, and c to iterate over the values of the input one item at a time, without producing three complete copies of the input.

* next() advances an iterator by one item. To set the desired starting points, we need to do this once to skip one item in b, and twice to skip two items in c.

* zip() was explained earlier.

Does this demonstrate it well enough?

creatine
Jan 27, 2012




Gangsta Lean posted:

Your original question is, How does zip() work?
It takes any number of iterables, and iterates over all of them simultaneously. A list is an iterable, a tuple is an iterable, a dictionary is iterable, a set is iterable, a string is iterable. Even classes you create can be iterable. Here's an example using two lists.
code:
items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
items2 = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

for x in zip(items1, items2):
	print(x)

#Result is:
# (0, 10)
# (1, 11)
# (2, 12)
# (3, 13)
# (4, 14)
# (5, 15)
# (6, 16)
# (7, 17)
# (8, 18)
# (9, 19)
Your edited definition of pairwise may work for your use case, but
1. It no longer produces a pair, it is a triple - so, pairwise is a bad name for the method.
2. Your method argument is named iterable, but by using slicing, you prevent iterables that don't support slicing.
3. You created multiple (shallow) copies of the input (see further below).

An input that is iterable but doesn't support slicing, such as a dictionary (iterating over a dictionary gives you the keys), does this when using your pairwise function:

code:
items3 = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7}

def pairwise(iterable):
    a = iter(iterable)
    b = iter(iterable[1::])
    c = iter(iterable[2::])		
    return zip(a, b, c)

for x in pairwise(items3):
	print(x)

# Traceback (most recent call last):
#   File "python", line 51, in <module>
#   File "python", line 41, in pairwise
# TypeError: unhashable type: 'slice'
When you used the [1::] syntax, you created a duplicate of your input. You can see this here, because only the first list is affected.
code:
items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
v = items1[1::]
items1[2] = 10000

print(items1)
print(v)

[0, 1, 10000, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

If you want to support all types of iterables, you want to use something more like this:
code:
import itertools

items1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
items3 = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7}

def threewise(iterable):
	a, b = itertools.tee(iterable)
	a, c = itertools.tee(iterable)
	next(b, None)
	next(c, None)
	next(c, None)
	return zip(a, b, c)


print('threewise a list')
for x in threewise(items1):
	print(x)
	
print('threewise a dictionary')
for x in threewise(items3):
	print(x)


# threewise a list
# (0, 1, 2)
# (1, 2, 3)
# (2, 3, 4)
# (3, 4, 5)
# (4, 5, 6)
# (5, 6, 7)
# (6, 7, 8)
# (7, 8, 9)
# threewise a dictionary
# ('f', 'c', 'h')
# ('c', 'h', 'a')
# ('h', 'a', 'd')
# ('a', 'd', 'b')
# ('d', 'b', 'g')
# ('b', 'g', 'e')
* itertools.tee() returns two independent iterators from a single iterable, so we can iterate more than once from the same input iterator. We need to do this twice so that we get three independent iterators: a, b, and c. Tee does not duplicate the input. By using it, it allows each of a, b, and c to iterate over the values of the input one item at a time, without producing three complete copies of the input.

* next() advances an iterator by one item. To set the desired starting points, we need to do this once to skip one item in b, and twice to skip two items in c.

* zip() was explained earlier.

Does this demonstrate it well enough?

This is perfect, thank you. I had no idea that I had to create to instances of tee() in order for what I was trying to do to work. The explanation is fantastic too, thanks!

QuarkJets
Sep 8, 2008


That is an awesomely thorough explanation of how those various functions work! Nice!

Lpzie
Nov 20, 2006

What's the preferred method to do a calculation multiple times and store them in a list?

My goto method is

Python code:
G = 6.67e-8
m = [1.90e33, 2.00e33, 2.10e33, 2.20e33]
r = [5.00e10, 5.10e10, 5.20e10, 5.30e10]

logg = []

for i in range( len(r) ):
    logg.append( np.log10( G * m[i] / r[i]**2 ) )
Isn't there some way to do this using that fancy lambda thing?

KICK BAMA KICK
Mar 2, 2009

Don't even need a lambda, just a list comprehension:
Python code:
logg = [np.log10(G * mx / rx **2) for (mx, rx) in zip(m, r)]
Extracting that, what is that, gravity?, calculation into a function with a sensible name would be a good idea and then the comprehension works the same way but gets even more readable.

Lpzie
Nov 20, 2006

Thanks. It's surface gravity, yeah.


EDIT: VVV Thanks.

Lpzie fucked around with this message at 00:49 on Apr 23, 2016

Gangsta Lean
Dec 3, 2001

Calm, relaxed...what could be more fulfilling?
Lpzie, I see you're using numpy. If m and r in your real data are large numpy arrays, neither your original code nor list comprehensions are efficient. You can do it all with numpy, where it will be much faster since all the calculations take place in non-interpreted code.

code:
import numpy

G = 6.67e-8
m = numpy.array([1.90e33, 2.00e33, 2.10e33, 2.20e33])
r = numpy.array([5.00e10, 5.10e10, 5.20e10, 5.30e10])

logg = numpy.log10(G * m / numpy.power(r, 2))

Dominoes
Sep 20, 2007

Python code:
-2 ** 2
Out[15]: -4
What am I missing? Julia, Google, and Wolfram alpha do it too, and I can't find confused SO posts on this!

Dominoes fucked around with this message at 13:29 on Apr 24, 2016

Jewel
May 2, 2009

Dominoes posted:

Python code:
-2 ** 2
Out[15]: -4
What am I missing? Julia, Google, and Wolfram alpha do it too, and I can't find confused SO posts on this!

Quick guess was right. It's not doing what you think it is. It's doing -(2^2) rather than (-2)^2 like you're expecting. :)

^ has precedence even in scenarios with a prefixed -, which to me is a little silly that they all treat "-2" as a shorthand for the operation "0 - 2" internally instead of treating it like a single number and giving it max precedence, but I guess that's how it is!

Dominoes
Sep 20, 2007

Thx. Thought I was losing it! This works: (-2) ** 2

Scratching my head as to why they'd all set it up that way.

QuarkJets
Sep 8, 2008

I think that those languages do recognize that "-2" is its own integer rather than the result of the operation "0-2", but they also respect a specific order of operations when evaluating a line, and in doing so the negative sign attached to the 2 gets ignored until after the exponent gets evaluated. There are a few languages that make an exception for this case by giving unary minus a higher precedence, so that -2**2 results in +4 (I know that Excel is one of them but I don't use any of the others)

Tigren
Oct 3, 2003

QuarkJets posted:

I think that those languages do recognize that "-2" is its own integer rather than the result of the operation "0-2", but they also respect a specific order of operations when evaluating a line, and in doing so the negative sign attached to the 2 gets ignored until after the exponent gets evaluated. There are a few languages that make an exception for this case by giving unary minus a higher precedence, so that -2**2 results in +4 (I know that Excel is one of them but I don't use any of the others)

It seems like the statement is being evaluated as -1*2**2 which, following the order of operations I learned in whatever grade, would mean 2^2 then multiplied by -1.

QuarkJets
Sep 8, 2008

Tigren posted:

It seems like the statement is being evaluated as -1*2**2 which, following the order of operations I learned in whatever grade, would mean 2^2 then multiplied by -1.

I think that's a fair interpretation. It's not really storing a -1 in memory or anything like that, but the minus operator is definitely being interpreted last, which is common. The way around that is to slam parens around the value in question (because parens are always evaluated first)

Nippashish
Nov 2, 2005

Let me see you dance!
It's interpreted the same way as -x**2.

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...

Dominoes posted:

Thx. Thought I was losing it! This works: (-2) ** 2

Scratching my head as to why they'd all set it up that way.

I don't know any language that would determine " - x [op] y" as "(-x) [op] y" (in the general case).

Grace Baiting
Jul 20, 2012

Audi famam illius;
Cucurrit quaeque
Tetigit destruens.



Hubis posted:

I don't know any language that would determine " - x [op] y" as "(-x) [op] y" (in the general case).

A language with negative numeric literals would presumably parse it as "(-x) [op] y" but that requires negative numeric literals. I know C and Python specifically do not have negative numeric literals -- unary minus in each is an actual operator that negates an expression's value, and is parsed according to operator precedence -- and I'm not familiar with any language that does include them.

Fake edit: I now know that Common Lisp has negative numeric literals as well as rational literals, I imagine as a convenience for allowing e.g. (* -3e2 2/5) instead of (* (- (* 3 (EXP 10 2))) (/ 2 5)), since there's no operator precedence to worry about anyway (outside the parsing of those numeric literals but that's pretty restricted, with no general exponentiation).
...but this is pretty far afield of Python and the question I was tangent'ing from!

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

I was trying to think of where this might not be true, and in Rust, it seems like the unary operators (including -) have higher precedence than binary operators.

code:
fn main() {
    let x = 5;
    assert_eq!(  - x + 1     ,    -4);
    assert_eq!(  - (x + 1)   ,    -6);
    assert_eq!(  (- x) + 1   ,    -4);
}
https://play.rust-lang.org/?gist=0f0c7aecaa04d12beb7c23c369680f06&version=nightly&backtrace=0

taqueso fucked around with this message at 17:24 on Apr 26, 2016

Dominoes
Sep 20, 2007

I feel like this falls into the same category as floating-point peculiarities, and Python 2's [floor] division: there's a technical reason behind them that makes the language consistent on some level, but it produces counter-intuitive results to someone who's not familiar with how the language works under-the-hood.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



taqueso posted:

I was trying to think of where this might not be true, and in Rust, it seems like the unary operators (including -) have higher precedence than binary operators.

code:
fn main() {
    let x = 5;
    assert_eq!(  - x + 1     ,    -4);
    assert_eq!(  - (x + 1)   ,    -6);
    assert_eq!(  (- x) + 1   ,    -4);
}
https://play.rust-lang.org/?gist=0f0c7aecaa04d12beb7c23c369680f06&version=nightly&backtrace=0

Same in JS. It's almost like they come from the same organization heh

Adbot
ADBOT LOVES YOU

QuarkJets
Sep 8, 2008

Dominoes posted:

I feel like this falls into the same category as floating-point peculiarities, and Python 2's [floor] division: there's a technical reason behind them that makes the language consistent on some level, but it produces counter-intuitive results to someone who's not familiar with how the language works under-the-hood.

To be fair, it's how most languages work under-the-hood. Even just written out on paper it's a bit ambiguous

  • Locked thread