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
OnceIWasAnOstrich
Jul 22, 2006

Dominoes posted:

Python code:
from toolz import take

one, two = take(2, func())



Is that function basically just itertools.islice with less flexibility and reversed arguments?

In general I feel like itertools in a criminally underused part of the standard library.

edit: Also, does anyone else use collections.defaultdict to a ridiculous degree? I use it so often I feel like I might be doing something wrong. I counted the number of times I see variable = defaultdict(lambda: 0) or defaultdict(list) in my code and its something around once per file.

OnceIWasAnOstrich fucked around with this message at 14:55 on Apr 10, 2016

Adbot
ADBOT LOVES YOU

Cingulate
Oct 23, 2012

by Fluffdaddy

Dominoes posted:

Do y'all have unused variables besides during unpacking?
In science packages, all the time. E.g., something will do a complicated-rear end transformation and analysis on a neural time series, and I basically only want the transformed time series and one specific parameter about the transformation, but it also gives me the R^2 and the residuals and whatnot.

OnceIWasAnOstrich posted:

Is that function basically just itertools.islice with less flexibility and reversed arguments?

In general I feel like itertools in a criminally underused part of the standard library.

edit: Also, does anyone else use collections.defaultdict to a ridiculous degree? I use it so often I feel like I might be doing something wrong.
I feel I criminally underuse those aspects of the standard library. I use a few collections, but that's basically it. Ever so often I browse through itertools and always take a mental note that oh my good, all of this is so smart and useful, but a few weeks later, I'll forget it's there and do a bad on the spot reimplementation myself anyways.

Dominoes
Sep 20, 2007

OnceIWasAnOstrich posted:

Is that function basically just itertools.islice with less flexibility and reversed arguments?

In general I feel like itertools in a criminally underused part of the standard library.

edit: Also, does anyone else use collections.defaultdict to a ridiculous degree? I use it so often I feel like I might be doing something wrong. I counted the number of times I see variable = defaultdict(lambda: 0) or defaultdict(list) in my code and its something around once per file.
AFAIK, yes re islice and take. Having the number of items first allows currying/partial.

ie:

Python code:
take2 = take(2)
I like defaultdict too.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Cingulate posted:

In science packages, all the time. E.g., something will do a complicated-rear end transformation and analysis on a neural time series, and I basically only want the transformed time series and one specific parameter about the transformation, but it also gives me the R^2 and the residuals and whatnot.

I don't know how these scientific packages usually work, but do these functions just return a homogeneous sequence of numbers in order to communicate the parameters back to the user? If so then really it sounds like the problem is that the interface offered by the functions is badly designed. It could and should return a result object or a dict instead. So instead of returning a list of five numbers or whatever and the user has to know what the significance of each of the 5 numbers is, it could return a dict, and the dict keys would be things like "R^2" or "r-squared" or whatever so that the return value would be self-documenting.

Compare

_unused1, _unused2, r_squared, *_unused_remaining = parameters

r_squared = parameters['r_squared']

Cingulate
Oct 23, 2012

by Fluffdaddy

Hammerite posted:

I don't know how these scientific packages usually work, but do these functions just return a homogeneous sequence of numbers in order to communicate the parameters back to the user? If so then really it sounds like the problem is that the interface offered by the functions is badly designed. It could and should return a result object or a dict instead. So instead of returning a list of five numbers or whatever and the user has to know what the significance of each of the 5 numbers is, it could return a dict, and the dict keys would be things like "R^2" or "r-squared" or whatever so that the return value would be self-documenting.

Compare

_unused1, _unused2, r_squared, *_unused_remaining = parameters

r_squared = parameters['r_squared']
Consider something like this:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html

Not actually what I'm using, but similar to this.

Dominoes
Sep 20, 2007

If I understand that doc, it's still an unpacking issue.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Cingulate posted:

Consider something like this:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html

Not actually what I'm using, but similar to this.

I just went and looked at that, and the documentation page didn't completely clear it up for me, but it has a link to the source code so I went and looked at that and my conclusion is that it does indeed do what I thought you had been describing. So I think it's badly designed for the reasons I gave in my previous post. Also the people designing this stuff are overly fond of coming up with unnecessarily abbreviated parameter names that are presumably clear to them but are opaque to a complete outsider like me. If I were using any of that library I'd probably put my own wrapper functions around it to give it a sane interface to my code, because it seems to me like it would be a hassle to use.

edit: They even hit on the idea of one of the return values being a dictionary with appropriately chosen keys, but they didn't make the jump to "why not just return the dictionary".

Hammerite fucked around with this message at 17:47 on Apr 10, 2016

vikingstrike
Sep 23, 2007

whats happening, captain
Go ahead and queue up the math/stats notation in code argument.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

_ is a fine variable name.

Now what?

Cingulate
Oct 23, 2012

by Fluffdaddy

Hammerite posted:

I just went and looked at that, and the documentation page didn't completely clear it up for me, but it has a link to the source code so I went and looked at that and my conclusion is that it does indeed do what I thought you had been describing. So I think it's badly designed for the reasons I gave in my previous post. Also the people designing this stuff are overly fond of coming up with unnecessarily abbreviated parameter names that are presumably clear to them but are opaque to a complete outsider like me. If I were using any of that library I'd probably put my own wrapper functions around it to give it a sane interface to my code, because it seems to me like it would be a hassle to use.

edit: They even hit on the idea of one of the return values being a dictionary with appropriately chosen keys, but they didn't make the jump to "why not just return the dictionary".
I'll assume the scipy people usually know what they're doing - it's one of the biggest Python projects, and massively successful and influential - and that typically, when you see them doing something stupid, it's either because there actually is a very good reason for it, or it's a legacy thing they have to deal with being a massive project.
But the matter at hand is that this is the kind of code we are dealing with all the time, and thus, I sometimes do

code:
_, x, _, _, y, _ = overly_complicated_function(input)

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Cingulate posted:

I'll assume the scipy people usually know what they're doing - it's one of the biggest Python projects, and massively successful and influential - and that typically, when you see them doing something stupid, it's either because there actually is a very good reason for it, or it's a legacy thing they have to deal with being a massive project.
But the matter at hand is that this is the kind of code we are dealing with all the time, and thus, I sometimes do

code:
_, x, _, _, y, _ = overly_complicated_function(input)

The people writing SciPy may be very clever and capable or they may not be, and they may have legacy constraints or they may not, but having a user-facing function that returns a big old tuple of values with heterogeneous types or purposes, instead of a dictionary or a result object, is bad design - that's all I'll commit to. You shouldn't have to write code that looks like that to use some library.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Cingulate posted:

I'll assume the scipy people usually know what they're doing - it's one of the biggest Python projects, and massively successful and influential - and that typically, when you see them doing something stupid, it's either because there actually is a very good reason for it, or it's a legacy thing they have to deal with being a massive project.
But the matter at hand is that this is the kind of code we are dealing with all the time, and thus, I sometimes do

code:
_, x, _, _, y, _ = overly_complicated_function(input)

I have no statistics on the matter, but I would find it surprising if scipy is influential outside of scientific code...which, outside of scientific circles, isn't generally considered to be good code to begin with.

That, of course, is a stereotype...there's plenty of good scientific code and plenty of bad non-scientific code and what most people would consider bad outside of scientific circles is just fine inside.

I will commit myself to agreeing that making GBS threads out big ole' tuples of data that consumers commonly only want part of is pretty lovely code.

Cingulate
Oct 23, 2012

by Fluffdaddy

Thermopyle posted:

I have no statistics on the matter, but I would find it surprising if scipy is influential outside of scientific code
Which is a lot of code, see PEP465.

Not gonna defend it as good code- what would you expect, professional scientists are inherently not professional programmers.

vikingstrike
Sep 23, 2007

whats happening, captain
I write terrible scientific/data analysis code, but I'd like to think this thread has helped me clean it up a lot over the last couple of years.

QuarkJets
Sep 8, 2008

Thermopyle posted:

_ is a fine variable name.

Now what?

The discussion was over the idea that _ is somehow superior to i in a list comprehension, which is preposterous. They're basically equivalent, and _ is a little obtuse if anything.

Cingulate posted:

Not gonna defend it as good code- what would you expect, professional scientists are inherently not professional programmers.

Well yeah, that's the point that everyone else is making.

QuarkJets
Sep 8, 2008

vikingstrike posted:

I write terrible scientific/data analysis code, but I'd like to think this thread has helped me clean it up a lot over the last couple of years.

I'm in this boat. When I first started learning Python (roughly 10 years ago) I was writing some seriously bad bullshit code in a scientific context; it did what I wanted it to do but it wasn't written well at all. Talking about and reading about Python code in this thread helped tremendously and now the compsci-educated people in my department comment on how my code is efficient and clean, unlike most scientific code that they see. I wish more science-inclined people would take the effort to learn more about effectively using their language of choice

pmchem
Jan 22, 2010


Thermopyle posted:

I have no statistics on the matter, but I would find it surprising if scipy is influential outside of scientific code...which, outside of scientific circles, isn't generally considered to be good code to begin with.

That, of course, is a stereotype...there's plenty of good scientific code and plenty of bad non-scientific code and what most people would consider bad outside of scientific circles is just fine inside.

I will commit myself to agreeing that making GBS threads out big ole' tuples of data that consumers commonly only want part of is pretty lovely code.

You can hate on aspects of it if you want, but scipy is amazingly useful, hugely influential, and a large part of the reason why Python enjoys the success it does today. Its coding style is generally pretty good too; they make an effort to well-document source and often conform to PEP 8. Like any very large project, it's easy to cherry pick warts.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

pmchem posted:

You can hate on aspects of it if you want, but scipy is amazingly useful, hugely influential, and a large part of the reason why Python enjoys the success it does today. Its coding style is generally pretty good too; they make an effort to well-document source and often conform to PEP 8. Like any very large project, it's easy to cherry pick warts.

I don't disagree with any of this, as I have no idea one way or the other. I was merely stating that the assertion (which you've repeated) that it is influential, great, and an amazing example of wonderful coding is surprising because of the reasons I mentioned.

Dominoes
Sep 20, 2007

Cingulate posted:

I'll assume the scipy people usually know what they're doing - it's one of the biggest Python projects, and massively successful and influential - and that typically, when you see them doing something stupid, it's either because there actually is a very good reason for it, or it's a legacy thing they have to deal with being a massive project.
But the matter at hand is that this is the kind of code we are dealing with all the time, and thus, I sometimes do

code:
_, x, _, _, y, _ = overly_complicated_function(input)
Appeal to authority: -10 points!

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

QuarkJets posted:

The discussion was over the idea that _ is somehow superior to i in a list comprehension, which is preposterous. They're basically equivalent, and _ is a little obtuse if anything.


Are they though? I mean I only dabble in python so this is more of an outsider's view (so it was a genuine question!), but to me if I see a variable called i I assume it's some kind of counter or index, with a value that's going to be used somewhere. Working out that it's missing from the rest of the code takes time, and involves more mental effort by keeping it in mind until you realise you should be ignoring it completely. Its presence kinda shapes the algorithm in your understanding, y'know?

But _ just looks like a blank space, and when everyone always uses it to mean 'whatever' then it's a lot easier to understand and visually scan the code, for me anyway. I'd never seen it before Python (now I know it's in functional languages too), but I really like that it's there. It's just neat :shobon:

QuarkJets
Sep 8, 2008

baka kaba posted:

Are they though? I mean I only dabble in python so this is more of an outsider's view (so it was a genuine question!), but to me if I see a variable called i I assume it's some kind of counter or index, with a value that's going to be used somewhere.

In this context, that's exactly what it was: it was a variable holding an integer index that was used inside of a list comprehension:

QuarkJets posted:

The list comprehension thing that vikingstrike mentioned would go like this:
Python code:
list_of_lists = [[] for i in range(k)]

I think that single-character variable names (such as i, j, _, etc) should be single-use throwaway variables that aren't used anywhere else. So a for loop might use i as its index, but then you shouldn't be using i outside of that loop unless you create a new for loop, and if the loop happens to be large then you should probably use something other than i, for clarity's sake.

QuarkJets fucked around with this message at 22:23 on Apr 10, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Well that's a pretty short comprehension so you're not saving a lot of brainpower, but the index isn't actually being used, right? It's there because it has to be there, but you're never using the value - it's just noise being produced by iterating over the length of the range

To me using a blank like _ makes it immediately clear you're not using the actual values, and in a more complex bit of code it just cleans the whole thing up. It's like redacting the irrelevant bits. I mean sometimes it obviously doesn't really matter, but it feels like a more elegant solution to me than using something that looks like it could be important

QuarkJets
Sep 8, 2008

baka kaba posted:

Well that's a pretty short comprehension so you're not saving a lot of brainpower, but the index isn't actually being used, right? It's there because it has to be there, but you're never using the value - it's just noise being produced by iterating over the length of the range

To me using a blank like _ makes it immediately clear you're not using the actual values, and in a more complex bit of code it just cleans the whole thing up. It's like redacting the irrelevant bits. I mean sometimes it obviously doesn't really matter, but it feels like a more elegant solution to me than using something that looks like it could be important

It's used in the comprehension. You could hypothetically use that variable after the comprehension is over, if you wanted to have the last value and didn't want to fetch it from the list for some reason.

Like I said, I don't think that single-character variable names should ever have importance. If your index variable has importance, and isn't throw-away, use "i_<something>". I think that's a pretty commonly-used convention, even if it's not codified anywhere (and this convention is ignored in most science code, but it seems like elsewhere people shy away from single-character variable names; for instance, using "ind" or "index" instead of "i" when you're indexing into many containers)

Also, I think that _ is an ugly character and makes code less elegant

SurgicalOntologist
Jun 17, 2004

As much as I love scipy, it's interface is not all that great, and is oftentimes repeating Matlab's bad choices or too transparent to the FORTRAN/C++/whatever that it's wrapping. For the latter see the difference between integrate.odeint and integrate.ode. I think outputting an arbitrary sequence of values and not at least using a namedtuple is an example of the former.

That said, I think _ is a perfectly acceptable solution to this problem from the user's perspective. Alternatively, if I use one of these in a few places and always grab the same output, I just wrap it myself to give it a more sensible interface.

Another place where scientific Python code borrows some warts from MATLAB is all the different ways to call matplotlib.pyplot.plot. At least scipy doesn't do anything like that, at least as far as I've come across.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

The value isn't used though, is what I meant. You're really doing [[] for range(k)] except that's not valid, you have to assign a variable but you don't actually care about it yourself. If you did need to access it as an index later, then obviously that doesn't apply! That's what I mean, choosing whether or not to name it (with _ being 'unnamed') carries meaning and intent, and conveys something to the reader

List comprehensions tend to be pretty compact anyway, right? Single-letter names can be more readable, especially if they fit the data well like x and y, so a convention where you use longer names for the stuff you care about seems clunky. With something like _ it's clear whether a variable is going to be used for something, or completely ignored. You don't even need to come up with a throwaway name for it!

I mostly do Java though so maybe that's why I appreciate the brevity :v:

QuarkJets
Sep 8, 2008

baka kaba posted:

The value isn't used though, is what I meant. You're really doing [[] for range(k)] except that's not valid, you have to assign a variable but you don't actually care about it yourself. If you did need to access it as an index later, then obviously that doesn't apply! That's what I mean, choosing whether or not to name it (with _ being 'unnamed') carries meaning and intent, and conveys something to the reader

List comprehensions tend to be pretty compact anyway, right? Single-letter names can be more readable, especially if they fit the data well like x and y, so a convention where you use longer names for the stuff you care about seems clunky. With something like _ it's clear whether a variable is going to be used for something, or completely ignored. You don't even need to come up with a throwaway name for it!

I mostly do Java though so maybe that's why I appreciate the brevity :v:

Yeah, for list comprehensions I see nothing wrong with using a single-letter variable. That's a great throwaway example, and almost any variable name would be fine there, including _ if you can stand that sort of thing. I personally can't do it, because _ looks awful to me, but it's fine if others want to do that.

What you should definitely not do is assume that a variable defined inside of a list comprehension has importance elsewhere, regardless of what that variable is named. And you also shouldn't use single-letter variable names for important variables.

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS
I mentioned this up-thread but this works perfectly and encapsulates everything:
Python code:
list_of_lists = map(lambda x: [], range(k))
It's not terribly performant compared to a comprehension but this discussion is academic anyways.

Proteus Jones
Feb 28, 2013



QuarkJets posted:

I personally can't do it, because _ looks awful to me, but it's fine if others want to do that.

Same. And it always throws me for a second when I see it others' code.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Blinkz0rz posted:

I mentioned this up-thread but this works perfectly and encapsulates everything:
Python code:
list_of_lists = map(lambda x: [], range(k))
It's not terribly performant compared to a comprehension but this discussion is academic anyways.

But what should the name of the "x" variable be? As an expert on bikeshed colours, this is of critical importance! Critical I say!

(also needs an outer list() call, for the Python version that's good)

Munkeymon
Aug 14, 2003

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



Hammerite posted:

I don't know what you mean - I don't understand how extension methods would be relevant to this, but if you can point me to something I don't know about them that would be great.

Might be me misunderstanding why classmethods are useful, but in C# if I want to make a utility method that I can just call as if it were a member of a type when it's not, I'd write an extension method. Granted, this doesn't give the extension method access to private members or anything similarly magical, but it looks like a similar use case to me.

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...
Personally, I insist on thorough Hungarian notation in all the Python code I review...

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Munkeymon posted:

Might be me misunderstanding why classmethods are useful, but in C# if I want to make a utility method that I can just call as if it were a member of a type when it's not, I'd write an extension method. Granted, this doesn't give the extension method access to private members or anything similarly magical, but it looks like a similar use case to me.

No, that's not what I mean. I mean I wanted to have something like Python's "classmethod" where it acts like a static method (you don't need an instance to call it), but it does still care which class it's called through. A dumb, babby's- first-OOP type example would be

code:
import abc

class Animal(metaclass = abc.ABCMeta):
    @classmethod
    @abc.abstractmethod
    def noise(cls):
        return 'A noise an animal makes'

class Cat(Animal):
    @classmethod
    def noise(cls):
        return 'Meow'

class Dog(Animal):
    @classmethod
    def noise(cls):
        return 'Woof'

print(Cat.noise()) # Meow
print(Dog.noise()) # Woof
You can't do this in C#. An abstract method can't be static, and although you do have "type" objects you can't call type-specific methods on them.

Munkeymon
Aug 14, 2003

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



Hammerite posted:

No, that's not what I mean. I mean I wanted to have something like Python's "classmethod" where it acts like a static method (you don't need an instance to call it), but it does still care which class it's called through. A dumb, babby's- first-OOP type example would be

code:
import abc

class Animal(metaclass = abc.ABCMeta):
    @classmethod
    @abc.abstractmethod
    def noise(cls):
        return 'A noise an animal makes'

class Cat(Animal):
    @classmethod
    def noise(cls):
        return 'Meow'

class Dog(Animal):
    @classmethod
    def noise(cls):
        return 'Woof'

print(Cat.noise()) # Meow
print(Dog.noise()) # Woof
You can't do this in C#. An abstract method can't be static, and although you do have "type" objects you can't call type-specific methods on them.

You kind-of can, though: https://dotnetfiddle.net/TRTDYx E: well, you can't override the implementation's methods with an extension - you'd have to inherit and explicitly override to do that. To associate a static method with a type is totally doable, though.

Munkeymon fucked around with this message at 16:58 on Apr 11, 2016

Jose Cuervo
Aug 25, 2004
More PySide GUI programming questions:

1. I have finally 'connected' my simulation to the GUI - when I press the "Run" button the simulation codes runs. However, while the simulation code is running, the GUI becomes unresponsive (progress bar not updating, etc). Looking this up, it seems to be because I was not using threading. So I implemented threading as follows based on examples I found online:
Python code:
from PySide import QtGui, QtCore
import my_sim


# noinspection PyPep8Naming
class RunSimTab(QtGui.QWidget):
    def __init__(self, the_parent):
        super(RunSimTab, self).__init__(the_parent)

        self.the_parent = the_parent
        self.workerThread = WorkerThread(self)

        self.sim_progress_bar = QtGui.QProgressBar(self)
        self.sim_progress_bar.setRange(0, 20)
        self.sim_progress_bar.setTextVisible(False)
        # self.sim_progress_bar.setGeometry(30, 40, 200, 50)

        self.start_sim_btn = QtGui.QPushButton('Start', self)
        self.start_sim_btn.clicked.connect(self.run_simulation)

        self.output_analysis_btn = QtGui.QPushButton('View Output Analysis', self)
        self.output_analysis_btn.clicked.connect(the_parent.move_to_analysis_tab)
        self.output_analysis_btn.setEnabled(False)

        tab_vbl = QtGui.QVBoxLayout()
        tab_vbl.addWidget(self.sim_progress_bar)
        tab_vbl.addWidget(self.start_sim_btn)
        tab_vbl.addWidget(self.output_analysis_btn)

        tab_hbl = QtGui.QHBoxLayout()
        tab_hbl.addStretch(3)
        tab_hbl.addLayout(tab_vbl)
        tab_hbl.addStretch(3)
        self.setLayout(tab_hbl)

    def run_simulation(self):
        self.the_parent.tab_widget.setTabEnabled(self.the_parent.tab_index_dict['scenario_tab'], False)
        self.the_parent.tab_widget.setTabEnabled(self.the_parent.tab_index_dict['sim_params_tab'], False)
        self.start_sim_btn.setEnabled(False)

        self.workerThread.start()

        self.output_analysis_btn.setEnabled(True)


class WorkerThread(QtCore.QThread):
    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)

        self.the_parent = parent

    def run(self):
        my_sim.main_gui(self.the_parent.sim_progress_bar)
This allows the GUI to be responsive, however I get the following warning(?) message:
code:
UserWarning: Multiprocessing backed parallel loops cannot be nested below threads, setting n_jobs=1
I use the joblib library in my simulation code to make multiple simulation replications run in parallel, however only one simulation replication is being run at a time (a consequence of the message). Is there a way to use the joblib parallelization and have the GUI be responsive?

2. Based on feedback from people I have shown the GUI to the tab structure that I have is not really a good solution - users will try clicking on the different tabs out of order, whereas I want to guide the user through a specific path (specify new simulation scenario (or load existing scenario) -> make any edits to the scenario -> make any edits to the simulation parameters -> run the simulation -> look at the output). I am having trouble finding examples of code that shows how to get started on programming a GUI in PySide that has a single window that transitions between the different 'pages'. Anyone got suggestions or example code I can looks at?

Nippashish
Nov 2, 2005

Let me see you dance!

Jose Cuervo posted:

I am having trouble finding examples of code that shows how to get started on programming a GUI in PySide that has a single window that transitions between the different 'pages'. Anyone got suggestions or example code I can looks at?

Have you considered making a browser based gui? You can have your program run a web server locally so you don't need to actually host things separately, but "a single window that transitions between different pages" is basically the thing browsers are good at.

accipter
Sep 12, 2003

Jose Cuervo posted:

More PySide GUI programming questions:

1. I have finally 'connected' my simulation to the GUI - when I press the "Run" button the simulation codes runs. However, while the simulation code is running, the GUI becomes unresponsive (progress bar not updating, etc). Looking this up, it seems to be because I was not using threading. So I implemented threading as follows based on examples I found online:
Python code:
from PySide import QtGui, QtCore
import my_sim


# noinspection PyPep8Naming
class RunSimTab(QtGui.QWidget):
    def __init__(self, the_parent):
        super(RunSimTab, self).__init__(the_parent)

        self.the_parent = the_parent
        self.workerThread = WorkerThread(self)

        self.sim_progress_bar = QtGui.QProgressBar(self)
        self.sim_progress_bar.setRange(0, 20)
        self.sim_progress_bar.setTextVisible(False)
        # self.sim_progress_bar.setGeometry(30, 40, 200, 50)

        self.start_sim_btn = QtGui.QPushButton('Start', self)
        self.start_sim_btn.clicked.connect(self.run_simulation)

        self.output_analysis_btn = QtGui.QPushButton('View Output Analysis', self)
        self.output_analysis_btn.clicked.connect(the_parent.move_to_analysis_tab)
        self.output_analysis_btn.setEnabled(False)

        tab_vbl = QtGui.QVBoxLayout()
        tab_vbl.addWidget(self.sim_progress_bar)
        tab_vbl.addWidget(self.start_sim_btn)
        tab_vbl.addWidget(self.output_analysis_btn)

        tab_hbl = QtGui.QHBoxLayout()
        tab_hbl.addStretch(3)
        tab_hbl.addLayout(tab_vbl)
        tab_hbl.addStretch(3)
        self.setLayout(tab_hbl)

    def run_simulation(self):
        self.the_parent.tab_widget.setTabEnabled(self.the_parent.tab_index_dict['scenario_tab'], False)
        self.the_parent.tab_widget.setTabEnabled(self.the_parent.tab_index_dict['sim_params_tab'], False)
        self.start_sim_btn.setEnabled(False)

        self.workerThread.start()

        self.output_analysis_btn.setEnabled(True)


class WorkerThread(QtCore.QThread):
    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)

        self.the_parent = parent

    def run(self):
        my_sim.main_gui(self.the_parent.sim_progress_bar)
This allows the GUI to be responsive, however I get the following warning(?) message:
code:
UserWarning: Multiprocessing backed parallel loops cannot be nested below threads, setting n_jobs=1
I use the joblib library in my simulation code to make multiple simulation replications run in parallel, however only one simulation replication is being run at a time (a consequence of the message). Is there a way to use the joblib parallelization and have the GUI be responsive?

2. Based on feedback from people I have shown the GUI to the tab structure that I have is not really a good solution - users will try clicking on the different tabs out of order, whereas I want to guide the user through a specific path (specify new simulation scenario (or load existing scenario) -> make any edits to the scenario -> make any edits to the simulation parameters -> run the simulation -> look at the output). I am having trouble finding examples of code that shows how to get started on programming a GUI in PySide that has a single window that transitions between the different 'pages'. Anyone got suggestions or example code I can looks at?

You should read about Qt and Threads (http://doc.qt.io/qt-5/thread-basics.html). Basically, you need to start the simulation from a worker thread so that the GUI thread can be responsive.

I use the tabbed organization for an application that I developed that does a similar thing as yours. I do lock the tabs during the calculation phase, and then auto-advance to the results tab. If you want another organization you might consider QWizard (http://doc.qt.io/qt-5/qwizard.html)

edit: My stylesheet is hosed up because of my proxy at work so I didn't really understand your question. I think your problem is this:
code:
    def run(self):
        my_sim.main_gui(self.the_parent.sim_progress_bar)
You should be communicating back to the GUI thread via signals. Have a signal from the worker thread that updates the range of the progress bar, and one that signals when the progress should be incremented.

accipter fucked around with this message at 22:07 on Apr 12, 2016

Dominoes
Sep 20, 2007

Speaking of GUI code, Anaconda now includes a package called QtPy, presumably to attempt to unite Python's QT fracture. It lets you write PyQT5 code, but run it from PyQt4, PyQt5, or pyside. This seems like a good way forward.

Dominoes fucked around with this message at 11:04 on Apr 13, 2016

Jose Cuervo
Aug 25, 2004

Nippashish posted:

Have you considered making a browser based gui? You can have your program run a web server locally so you don't need to actually host things separately, but "a single window that transitions between different pages" is basically the thing browsers are good at.

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.

accipter posted:

You should read about Qt and Threads (http://doc.qt.io/qt-5/thread-basics.html). Basically, you need to start the simulation from a worker thread so that the GUI thread can be responsive.

I use the tabbed organization for an application that I developed that does a similar thing as yours. I do lock the tabs during the calculation phase, and then auto-advance to the results tab. If you want another organization you might consider QWizard (http://doc.qt.io/qt-5/qwizard.html)

edit: My stylesheet is hosed up because of my proxy at work so I didn't really understand your question. I think your problem is this:
code:
    def run(self):
        my_sim.main_gui(self.the_parent.sim_progress_bar)
You should be communicating back to the GUI thread via signals. Have a signal from the worker thread that updates the range of the progress bar, and one that signals when the progress should be incremented.

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:
from PySide import QtGui, QtCore

class ScenarioTab(QtGui.QWidget):
    def __init__(self, the_parent):
        super(ScenarioTab, self).__init__(the_parent)

        self.the_parent = the_parent

        self.sub_tab_widget = QtGui.QTabWidget()

        tankers_tab = TankersSubTab(self)
        self.sub_tab_widget.addTab(tankers_tab, 'Tankers')

        tab_vbl = QtGui.QVBoxLayout()
        tab_vbl.addWidget(self.sub_tab_widget)

        self.setLayout(tab_vbl)


class TankersSubTab(QtGui.QWidget):
    def __init__(self, the_parent):
        super(TankersSubTab, self).__init__(the_parent)

        self.the_parent = the_parent
        self.tanker_type_count = 0

        tab_content = QtGui.QWidget()
        self.tab_content_vbl = QtGui.QVBoxLayout()
        tab_content.setLayout(self.tab_content_vbl)
        content_sa = QtGui.QScrollArea()
        content_sa.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        content_sa.setWidgetResizable(True)
        content_sa.setWidget(tab_content)

        add_tanker_type_btn = QtGui.QPushButton('Add New Tanker Type')
        add_tanker_type_btn.clicked.connect(self.add_tanker_type)
        add_tanker_type_btn.setMaximumWidth(300)
        add_tanker_type_btn.setMinimumWidth(300)
        add_tanker_type_btn_hbl = QtGui.QHBoxLayout()
        add_tanker_type_btn_hbl.addWidget(add_tanker_type_btn)
        add_tanker_type_btn_hbl.addStretch(1)

        tab_vbl = QtGui.QVBoxLayout(self)
        tab_vbl.addWidget(content_sa)
        tab_vbl.addLayout(add_tanker_type_btn_hbl)
        self.setLayout(self.tab_content_vbl)

        self.add_tanker_type()

    def add_tanker_type(self):
        self.tanker_type_gb = QtGui.QGroupBox("Tanker Type %s" % (self.tanker_type_count + 1), self)
        self.tanker_type_gb.setMaximumHeight(100)
        tanker_type_fl = QtGui.QFormLayout()
        self.tanker_fuel = QtGui.QComboBox()
        self.tanker_fuel.addItem("Diesel")
        self.tanker_fuel.addItem("Regular")
        self.tanker_fuel.addItem("Supreme")
        self.tanker_fuel.currentIndexChanged.connect(self.modify_gb_title)  <<<<<<<---- THIS IS THE LINE THAT DOESN"T WORK RIGHT
        tanker_type_fl.addRow('Fuel type', self.tanker_fuel)
        tanker_capacity = QtGui.QLineEdit(placeholderText='8000')
        tanker_type_fl.addRow('Storage capacity (gallons)', tanker_capacity)
        num_tankers = QtGui.QLineEdit(placeholderText='10')
        tanker_type_fl.addRow('Number of tankers', num_tankers)
        self.tanker_type_gb.setLayout(tanker_type_fl)

        self.tab_content_vbl.addWidget(self.tanker_type_gb)

        self.tanker_type_count += 1

    def modify_gb_title(self):
        current_title = self.tanker_type_gb.title()
        if current_title.find('(') == -1:
            self.tanker_type_gb.setTitle(current_title + " (" + self.tanker_fuel.currentText() + ")")
        else:
            base_title = current_title[:current_title.find('(') - 1]
            self.tanker_type_gb.setTitle(base_title + " (" + self.tanker_fuel.currentText() + ")")
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.

Jose Cuervo fucked around with this message at 02:55 on Apr 14, 2016

Fluue
Jan 2, 2008
If I'm using a class as a sort of pseudo-Model that populates its attributes (e.g. name, is_active) by consuming a response to an external API call is it better to:

a.) Within __init__ call an internal class method that makes a request to the API and then populates some of the attributes of the class
b.) Explicitly call a method to populate the attributes of a class

A project I'm working on has a developer using a lot of option A, but it feels wrong to me. Am I just over thinking this?

Adbot
ADBOT LOVES YOU

Fergus Mac Roich
Nov 5, 2008

Soiled Meat
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.

  • Locked thread