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
Dominoes
Sep 20, 2007

Fergus Mac Roich posted:

And it doesn't have tail call elimination :arghfist:
Yea; I wish it did.

QuarkJets posted:

I know all about Julia and played around with it when it was 0.2, and then again when it was 0.3, and then again when it was 0.4. It didn't really suit me in beta form due to poor documentation and some weird undocumented stuff going on some of the time, so I'm hoping to return to Julia once it's in 1.0 and stable and well-documented. In the meantime I mostly write Python for development speed and versatility, and if I need certain bits of code to run faster then I compile them with Numba.
So early-release issues aside, you don't mind that it doesn't do OOP? ;)

Dominoes fucked around with this message at 21:37 on Apr 3, 2016

Adbot
ADBOT LOVES YOU

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

Cingulate posted:

Certainly not prioritized, but it does seem to me it's quite possible to do tasks of moderate complexity in idiomatic Python in a functional way. E.g., toolz.

I'd say low complexity; it's definitely possible to do things like aggregate operations (map/filter/fold/et al), but with lack of good support for things like algebraic data types, currying, and pattern matching, it ends up being pretty painful past simple list processing. Plus, even the most OO of OO languages, Java, can do map and reduce now with streams, and it even has lambdas.

Dominoes
Sep 20, 2007

You can curry with toolz.

Nippashish
Nov 2, 2005

Let me see you dance!

Dominoes posted:

Video criticizing OOP.
https://www.youtube.com/watch?v=QM1iUe6IofM

What do y'all think? Personally, I rarely create classes. Exceptions being database models, GUI bits, and complex chunks of code that share variables [that might be better off as separate files.]. There's a stock broker API I use that implements a full-blown OOP Java API from Python, and it embodies one of the video's critiques: Objects wrapping objects wrapping objects; everything obfuscated and opaque.

The video reminded me of one of the cool things about Python: It's flexible and multi-paradigm. I scoffed the OOP part of it, but love its functional and numerical sides.

I wish this guy had used a few more metaphors to explain how OOP leads to jumbled programs. It would have made it easier to overlook the fact that he doesn't have any solutions to offer, or really any specific complaints at all.

Cingulate
Oct 23, 2012

by Fluffdaddy

Asymmetrikon posted:

I'd say low complexity
I guess my moderate complexity may as well be your low complexity :)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Actually, low complexity was not really a good choice of words on my part, sorry; I suppose I mean that Python is good at using functional concepts to augment its imperative, procedural nature, but the problems it solves well are complex in a different way than problems a functional language would be good at.

QuarkJets
Sep 8, 2008

Dominoes posted:

Yea; I wish it did.

So early-release issues aside, you don't mind that it doesn't do OOP? ;)

It sort of does though; you're free to create your own types, they just can't have their own methods. It's partial OOP, which is fine for what julia is designed to do (scientific computation)

bigmandan
Sep 11, 2001

lol internet
College Slice

Nippashish posted:

I wish this guy had used a few more metaphors to explain how OOP leads to jumbled programs. It would have made it easier to overlook the fact that he doesn't have any solutions to offer, or really any specific complaints at all.

I watched some more of his videos and he rewrote some NES emulator written in golang to be more procedural. While he did "fix" some things, I think it got taken to quite an extreme.

Thermopyle
Jul 1, 2003

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

It's a pretty good rule of thumb that you can dismiss the opinion of anyone taking an absolutist position.

Thermopyle
Jul 1, 2003

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

Like, I can highlight the downsides of just about anything and then declare that thing is bad.


edit: Doublepost!

edit2: You'd probably get more/better discussion by posting this video in the general programming questions megathread.

Thermopyle fucked around with this message at 18:14 on Apr 4, 2016

taqueso
Mar 8, 2004


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

:pirate::hf::tinfoil:

It's true, everything is bad.

QuarkJets
Sep 8, 2008

Thermopyle posted:

It's a pretty good rule of thumb that you can dismiss the opinion of anyone taking an absolutist position.

Also any video (or speech) that claims to be "the most important video that you're ever going to watch" is definitely garbage. It does this like 3 times at the start

QuarkJets
Sep 8, 2008

Although I did like the bit where he compared Java to the Nazi regime

Jose Cuervo
Aug 25, 2004

QuarkJets posted:

1. Totally fine for a project of this size, for a larger project you might do one class per screen, one file per class.

2. The most useful part about declaring a parent is that when the parent gets deleted, so do all of its children. This makes memory management way easier, which is really great when writing C++. Python, however, does its own memory management as things fall out of scope, which can result in some interesting bugs when using pyside if you're not using parent-child relationships properly. The best way to prevent problems is to be diligent about making sure that parents are being set. There are also some situations where changing an object (perhaps by resizing a window) will result in all of the children of that object being modified (perhaps resizing them as well), and this only works if you're setting parents properly. For your project, it's small enough and simple enough that you could probably skip setting parents, but it's good practice and incredibly easy to do so you should do it anyway

3. This is a totally reasonable approach so long as you're okay with users possibly going back one or more steps, since they're able to click the tabs themselves.

4. I don't think so. If you wanted to more Pythonic about it you could do something like this:
code:
id_counter = 0
self.tab_widget.addTab(main_tab, 'Main')
self.id_main = id_counter
id_counter += 1
...
self.tab_widget.addTab(define_scenario_tab, 'Simulation Scenario')
self.id_scenario = id_counter
id_counter += 1
... #etc
And then you could have a button on each tab that calls the appropriate next tab based on the id that you've stored in your class, which would mean that you could add more tabs later and not have to worry about reordering things. This is overkill if you don't plan on having more tabs in the future.

5. Looks fine to me, but I didn't exactly comb through it

Thanks for the help. I do want to split the program up into several files (one for each tab in the QTabWidget), and so I built a separate class for the third tab (Simulation Parameters):
Python code:
from PySide import QtGui, QtCore


class SimParamsTab(QtGui.QWidget()):
    def __init__(self, tab_widget):
        super(SimParamsTab, self).__init__(parent)

        # Basic Params
        self.basic_params_gb = QtGui.QGroupBox('Basic parameters', self)
        self.basic_params = QtGui.QFormLayout(self)
        self.sim_duration = QtGui.QLineEdit(placeholderText='Length of simulation horizon in days')
        self.basic_params.addRow('Simulation duration (days)', self.sim_duration)
        self.basic_params_gb.setLayout(self.basic_params)

        # Advanced Params
        self.advanced_params_gb = QtGui.QGroupBox('Advanced parameters', self)
        self.advanced_params = QtGui.QFormLayout(self)
        self.init_cond_seed = QtGui.QLineEdit('None')
        self.advanced_params.addRow('Initial conditions seed', self.init_cond_seed)
        self.advanced_params_gb.setLayout(self.advanced_params)

        self.run_sim_btn = QtGui.QPushButton("Done with simulation settings", self)
        self.run_sim_btn.clicked.connect(tab_widget.move_to_run_sim_tab)

        self.params_box = QtGui.QVBoxLayout(self)
        self.params_box.addWidget(self.basic_params_gb)
        self.params_box.addWidget(self.advanced_params_gb)
        self.params_box.addWidget(self.run_sim_btn)
        self.sim_params_tab.setLayout(self.params_box)
However, now when I try and run the program I get the following error:
code:
QWidget: Must construct a QApplication before a QPaintDevice
From looking this error up online, it seems to be because of the import statement in my main file, where I import the .py file containing the new class before I have the line
Python code:
app = QtGui.QApplication(sys.argv)
Any ideas on how to resolve this error?

accipter
Sep 12, 2003

Jose Cuervo posted:

Thanks for the help. I do want to split the program up into several files (one for each tab in the QTabWidget), and so I built a separate class for the third tab (Simulation Parameters):
Python code:
from PySide import QtGui, QtCore


class SimParamsTab(QtGui.QWidget()):
    def __init__(self, tab_widget):
        super(SimParamsTab, self).__init__(parent)

        # Basic Params
        self.basic_params_gb = QtGui.QGroupBox('Basic parameters', self)
        self.basic_params = QtGui.QFormLayout(self)
        self.sim_duration = QtGui.QLineEdit(placeholderText='Length of simulation horizon in days')
        self.basic_params.addRow('Simulation duration (days)', self.sim_duration)
        self.basic_params_gb.setLayout(self.basic_params)

        # Advanced Params
        self.advanced_params_gb = QtGui.QGroupBox('Advanced parameters', self)
        self.advanced_params = QtGui.QFormLayout(self)
        self.init_cond_seed = QtGui.QLineEdit('None')
        self.advanced_params.addRow('Initial conditions seed', self.init_cond_seed)
        self.advanced_params_gb.setLayout(self.advanced_params)

        self.run_sim_btn = QtGui.QPushButton("Done with simulation settings", self)
        self.run_sim_btn.clicked.connect(tab_widget.move_to_run_sim_tab)

        self.params_box = QtGui.QVBoxLayout(self)
        self.params_box.addWidget(self.basic_params_gb)
        self.params_box.addWidget(self.advanced_params_gb)
        self.params_box.addWidget(self.run_sim_btn)
        self.sim_params_tab.setLayout(self.params_box)
However, now when I try and run the program I get the following error:
code:
QWidget: Must construct a QApplication before a QPaintDevice
From looking this error up online, it seems to be because of the import statement in my main file, where I import the .py file containing the new class before I have the line
Python code:
app = QtGui.QApplication(sys.argv)
Any ideas on how to resolve this error?

Change "class SimParamsTab(QtGui.QWidget())" to "class SimParamsTab(QtGui.QWidget)".

Cingulate
Oct 23, 2012

by Fluffdaddy

QuarkJets posted:

It sort of does though; you're free to create your own types, they just can't have their own methods. It's partial OOP, which is fine for what julia is designed to do (scientific computation)
Well as I said, in my case (neuroimaging), a bit of OO makes a lot of sense. The dominant MEG/EEG packages are OO to various degrees.

Jose Cuervo
Aug 25, 2004

accipter posted:

Change "class SimParamsTab(QtGui.QWidget())" to "class SimParamsTab(QtGui.QWidget)".

DOH! Thank you!

Pie Colony
Dec 8, 2006
I AM SUCH A FUCKUP THAT I CAN'T EVEN POST IN AN E/N THREAD I STARTED

Fergus Mac Roich posted:

And it doesn't have tail call elimination :arghfist:

Not as a built-in language feature, but one of the "good" things about Python is you can pretty much do whatever you want, such as programmatically rewrite recursive calls in tail position for a given function's AST.

Fergus Mac Roich
Nov 5, 2008

Soiled Meat

Pie Colony posted:

Not as a built-in language feature, but one of the "good" things about Python is you can pretty much do whatever you want, such as programmatically rewrite recursive calls in tail position for a given function's AST.

You're right, that is "good".

edit: Oops I'm posting in GBS too much. Fixed capitalization. Also yeah Python isn't perfect in terms of functional programming but I find that first class function objects and map() and stuff get me most functional-esque stuff I'd like to express in my imperative code.

Fergus Mac Roich fucked around with this message at 20:14 on Apr 4, 2016

BigRedDot
Mar 6, 2008

FWIW my favorite anti-OO screed is Object Oriented Programming is an expensive disaster which must end

Hubis
May 18, 2003

Boy, I wish we had one of those doomsday machines...
People sure are mad about programming

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
mine is Goodbye, lovely Car extends Vehicle object-orientation tutorial

Cingulate
Oct 23, 2012

by Fluffdaddy
Is there an easy, simple answer for why, and when, things are faster on my Macbook Air than on our Xeons and Opterons?

Particularly,
code:
import timeit

t1 = timeit.Timer('copy.copy(orig)','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')
t2 = timeit.Timer('orig[:]','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')
t3 = timeit.Timer('list(orig)','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')

print(t1.timeit(10000)/10000)
print(t2.timeit(10000)/10000)
print(t3.timeit(10000)/10000)
runs 25% faster on my 1.4Ghz MBA than on our 2.7 Ghz Xeons and Opterons.

I understand this doesn't benefit at all from our Xeons being dual-CPU, 12-core, but I'd still not expect my MBA to be faster at basically anything but maybe for disk access due to it having an SSD.

Edit: this, too
%time for _ in range(10000000): 2**2**3**2 + 2**2**3**2

Cingulate fucked around with this message at 10:34 on Apr 5, 2016

QuarkJets
Sep 8, 2008

Cingulate posted:

Is there an easy, simple answer for why, and when, things are faster on my Macbook Air than on our Xeons and Opterons?

Particularly,
code:
import timeit

t1 = timeit.Timer('copy.copy(orig)','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')
t2 = timeit.Timer('orig[:]','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')
t3 = timeit.Timer('list(orig)','import copy;import random;orig = [random.randint(0, 255) for r in range(100000)];')

print(t1.timeit(10000)/10000)
print(t2.timeit(10000)/10000)
print(t3.timeit(10000)/10000)
runs 25% faster on my 1.4Ghz MBA than on our 2.7 Ghz Xeons and Opterons.

I understand this doesn't benefit at all from our Xeons being dual-CPU, 12-core, but I'd still not expect my MBA to be faster at basically anything but maybe for disk access due to it having an SSD.

Edit: this, too
%time for _ in range(10000000): 2**2**3**2 + 2**2**3**2

The first three are probably due to the MBA having faster memory; all that you're really testing is how quickly you can access a memory address and how quickly you can create a pointer to that memory address. You're not testing computational power at all with those lines of code. Instead of making shallow copies of lists, try calling sha1 on the list instead (do this with map() or a list comprehension).

The edit is bottlenecked by function calls (which are expensive), so you're really just testing to see how quickly you can access the pow function (either on the disk or in memory). Again, not much of a CPU test.

Hubis
May 18, 2003

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

QuarkJets posted:

The first three are probably due to the MBA having faster memory; all that you're really testing is how quickly you can access a memory address and how quickly you can create a pointer to that memory address. You're not testing computational power at all with those lines of code. Instead of making shallow copies of lists, try calling sha1 on the list instead (do this with map() or a list comprehension).

The edit is bottlenecked by function calls (which are expensive), so you're really just testing to see how quickly you can access the pow function (either on the disk or in memory). Again, not much of a CPU test.

And this is why benchmarks are hard :)

Cingulate
Oct 23, 2012

by Fluffdaddy

QuarkJets posted:

The first three are probably due to the MBA having faster memory; all that you're really testing is how quickly you can access a memory address and how quickly you can create a pointer to that memory address. You're not testing computational power at all with those lines of code. Instead of making shallow copies of lists, try calling sha1 on the list instead (do this with map() or a list comprehension).

The edit is bottlenecked by function calls (which are expensive), so you're really just testing to see how quickly you can access the pow function (either on the disk or in memory). Again, not much of a CPU test.
Makes perfect sense, thanks.

Jose Cuervo
Aug 25, 2004
I am still having some trouble knowing what to specify as a parent when adding buttons, etc to the GUI. Here is the code for one of the tabs in the GUI:
Python code:
from PySide import QtGui, QtCore


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

        self.the_parent = the_parent

        # Set the page image
        self.background_pixmap = QtGui.QPixmap("images/main_page.png")
        self.background = QtGui.QLabel(self)
        self.background.setPixmap(self.tfsp_background_pixmap)

        # New scenario button
        self.new_scenario_gb = QtGui.QGroupBox('Define New Simulation Scenario', self)
        self.new_scenario_hbl = QtGui.QHBoxLayout()
        self.new_scenario_btn = QtGui.QPushButton("New Scenario", self)
        self.new_scenario_btn.clicked.connect(the_parent.move_to_scenario_tab)
        self.new_scenario_hbl.addWidget(self.new_scenario_btn)
        self.new_scenario_gb.setLayout(self.new_scenario_hbl)

        # Load existing scenario
        self.existing_scenario_gb = QtGui.QGroupBox('Load Existing Simulation Scenario', self)
        self.existing_scenario_vbl = QtGui.QVBoxLayout()
        self.scenario_file_hbl = QtGui.QHBoxLayout()
        self.scenario_file_browse_btn = QtGui.QPushButton('Browse')
        self.scenario_file_browse_btn.clicked.connect(self.browse_for_files)
        self.scenario_file_lbl = QtGui.QLabel('Scenario file')
        self.scenario_file_le = QtGui.QLineEdit(placeholderText='Click \'Browse\'')
        self.scenario_file_le.setToolTip('Click \'Browse\' to select a file')
        self.scenario_file_hbl.addWidget(self.scenario_file_lbl)
        self.scenario_file_hbl.addWidget(self.scenario_file_le)
        self.scenario_file_hbl.addWidget(self.scenario_file_browse_btn)
        self.existing_scenario_vbl.addLayout(self.scenario_file_hbl)
        self.load_scenario_btn = QtGui.QPushButton("Load Scenario", self)
        self.load_scenario_btn.setToolTip("Load an existing scenario from the selected file")
        self.load_scenario_btn.clicked.connect(self.the_parent.move_to_scenario_tab)
        self.existing_scenario_vbl.addWidget(self.load_scenario_btn)
        self.existing_scenario_gb.setLayout(self.existing_scenario_vbl)

        self.tab_vbl = QtGui.QVBoxLayout()
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.background)
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.new_scenario_gb)
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.existing_scenario_gb)
        self.tab_vbl.addStretch(25)

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

        self.setLayout(self.tab_hbl)

    def browse_for_files(self):
        file_name, _ = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open file',
                                                         filter="*.txt")
        self.scenario_file_le.setText(file_name)
Now self.background is a QtGui.QLabel which is placed in self.tab_hbl. Should the parent of self.background be self (i.e. the instance of MainTab), or self.tab_hbl?

Further self.scenario_file_browse_btn is a QtGui.QPushButton that is placed in a QHBoxLayout, the QHBoxLayout is placed in a QVBoxLayout, and the QVBoxLayout is placed in a QGroupBox. So should self.scenario_file_browse_btn have the QHBoxLayout as its parent, the QHBoxLayout have the QVBoxLayout as its parent, the QVBoxLayout have the QGroupBox as its parent, and the QGroupBox have self as its parent?

Lastly, I am declaring everything using self. since I am in the __init__ function. Is this correct?

QuarkJets
Sep 8, 2008

Jose Cuervo posted:

I am still having some trouble knowing what to specify as a parent when adding buttons, etc to the GUI. Here is the code for one of the tabs in the GUI:
Python code:
from PySide import QtGui, QtCore


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

        self.the_parent = the_parent

        # Set the page image
        self.background_pixmap = QtGui.QPixmap("images/main_page.png")
        self.background = QtGui.QLabel(self)
        self.background.setPixmap(self.tfsp_background_pixmap)

        # New scenario button
        self.new_scenario_gb = QtGui.QGroupBox('Define New Simulation Scenario', self)
        self.new_scenario_hbl = QtGui.QHBoxLayout()
        self.new_scenario_btn = QtGui.QPushButton("New Scenario", self)
        self.new_scenario_btn.clicked.connect(the_parent.move_to_scenario_tab)
        self.new_scenario_hbl.addWidget(self.new_scenario_btn)
        self.new_scenario_gb.setLayout(self.new_scenario_hbl)

        # Load existing scenario
        self.existing_scenario_gb = QtGui.QGroupBox('Load Existing Simulation Scenario', self)
        self.existing_scenario_vbl = QtGui.QVBoxLayout()
        self.scenario_file_hbl = QtGui.QHBoxLayout()
        self.scenario_file_browse_btn = QtGui.QPushButton('Browse')
        self.scenario_file_browse_btn.clicked.connect(self.browse_for_files)
        self.scenario_file_lbl = QtGui.QLabel('Scenario file')
        self.scenario_file_le = QtGui.QLineEdit(placeholderText='Click \'Browse\'')
        self.scenario_file_le.setToolTip('Click \'Browse\' to select a file')
        self.scenario_file_hbl.addWidget(self.scenario_file_lbl)
        self.scenario_file_hbl.addWidget(self.scenario_file_le)
        self.scenario_file_hbl.addWidget(self.scenario_file_browse_btn)
        self.existing_scenario_vbl.addLayout(self.scenario_file_hbl)
        self.load_scenario_btn = QtGui.QPushButton("Load Scenario", self)
        self.load_scenario_btn.setToolTip("Load an existing scenario from the selected file")
        self.load_scenario_btn.clicked.connect(self.the_parent.move_to_scenario_tab)
        self.existing_scenario_vbl.addWidget(self.load_scenario_btn)
        self.existing_scenario_gb.setLayout(self.existing_scenario_vbl)

        self.tab_vbl = QtGui.QVBoxLayout()
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.background)
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.new_scenario_gb)
        self.tab_vbl.addStretch(1)
        self.tab_vbl.addWidget(self.existing_scenario_gb)
        self.tab_vbl.addStretch(25)

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

        self.setLayout(self.tab_hbl)

    def browse_for_files(self):
        file_name, _ = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open file',
                                                         filter="*.txt")
        self.scenario_file_le.setText(file_name)
Now self.background is a QtGui.QLabel which is placed in self.tab_hbl. Should the parent of self.background be self (i.e. the instance of MainTab), or self.tab_hbl?

Either answer can be correct, but ideally the parent should be tab_hbl. Note that some methods will cause an object to take ownership of other objects automatically. In this case, QWidget.setLayout and QLayout.addWidget will result in objects being re-parented, so you don't need to set the parent in these cases (or if you do anyway, just know that this parent info will get overwritten).

quote:

Further self.scenario_file_browse_btn is a QtGui.QPushButton that is placed in a QHBoxLayout, the QHBoxLayout is placed in a QVBoxLayout, and the QVBoxLayout is placed in a QGroupBox. So should self.scenario_file_browse_btn have the QHBoxLayout as its parent, the QHBoxLayout have the QVBoxLayout as its parent, the QVBoxLayout have the QGroupBox as its parent, and the QGroupBox have self as its parent?

This seems like a reasonable parent hierarchy to me; think of layouts as containers, so if your layout has 3 widgets inside of it then you want those 3 widgets to have the layout as a parent. You're using addWidget and setLayout, so your parentage is probably all okay already

quote:

Lastly, I am declaring everything using self. since I am in the __init__ function. Is this correct?

It's not strictly necessary, using self implicitly means that you want to be able to access the content of those variables later. Due to the way in which Qt parent/child relationships and signal/slot mechanics work, you could not use self for the vast majority of Gui elements so long as you've got parentage sorted out. But definitely use self for variables that you'll need later.

GameCube
Nov 21, 2006

I've been using Python for bullshit scripts for a few years, but now I'm working on my first real-rear end app. Coming from C++, duck typing feels weird and wrong to me. Now that the abc module's been around for a while, what's the general sentiment? Is it pythonic?

KICK BAMA KICK
Mar 2, 2009

GameCube posted:

I've been using Python for bullshit scripts for a few years, but now I'm working on my first real-rear end app. Coming from C++, duck typing feels weird and wrong to me. Now that the abc module's been around for a while, what's the general sentiment? Is it pythonic?
I've never done anything more than hobbyist stuff, but I liked using abc when I was learning Python as my first language. Then when I got some experience in statically typed languages with actual interfaces, I felt like abc was just a crutch that could never really fulfill what I wanted when I tried to use it. Just my vague opinion though.

Maybe abc now interacts somehow with the new type annotations to more clearly define what's expected of an implementation? But I feel like whenever you start asking those kinds of questions, you're really asking why should you be using Python for that task in the first place?

Hammerite
Mar 9, 2007

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

KICK BAMA KICK posted:

I've never done anything more than hobbyist stuff, but I liked using abc when I was learning Python as my first language. Then when I got some experience in statically typed languages with actual interfaces, I felt like abc was just a crutch that could never really fulfill what I wanted when I tried to use it. Just my vague opinion though.

Maybe abc now interacts somehow with the new type annotations to more clearly define what's expected of an implementation? But I feel like whenever you start asking those kinds of questions, you're really asking why should you be using Python for that task in the first place?

I kind of feel like this. I had a personal project I was working on recently (still not got anywhere with it) that I started out trying to write in Python, realised after a while that I was trying to write C# in Python, switched to trying to do it in C# instead, but then got frustrated with some of the roadblocks that C# puts in your way that feel unreasonable after you've gotten used to being able to play a bit fast and loose like you can in Python*. Then I went back to Python trying to use the new type annotation stuff but it still wasn't what I was looking for.

Basically I'm in an unhappy point in between the two languages and it is pretty annoying.

* like not having a notion akin to Python's "class methods", where you have an essentially static method but it cares which class you used to call it

Dominoes
Sep 20, 2007

Some thought after posting the video about OOP a few days ago and the responses. I think I like making classes for cases that fit the progamming-101 paradigm of managing concrete members of a category; this is why they make sense for database ORMs. I don't like using them for abstractions.

Munkeymon
Aug 14, 2003

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



Hammerite posted:

* like not having a notion akin to Python's "class methods", where you have an essentially static method but it cares which class you used to call it

Extension methods don't do what you want?

drainpipe
May 17, 2004

AAHHHHHHH!!!!
I'm just beginning to learn Python, and I was wondering what the best way to create a list of variable length filled with copies of one thing is. Specifically, I want to create the list [[],[],...,[]] where there are k empty lists. Right now, I'm looping over k and appending empty lists to my growing list of empty lists. I can't do [] * k because modifying one of the [] modified them all.

More generally, my setup is that I need k containers that I will fill with numbers. I do not know how many numbers will go in each container. Is there a better way to do this than a list of empty lists? I'm using NumPy/SciPy if that's any help.

vikingstrike
Sep 23, 2007

whats happening, captain
You can use a list comprehension to do that cleaner. Or you could use a dict of lists.

Fergus Mac Roich
Nov 5, 2008

Soiled Meat

drainpipe posted:

I'm just beginning to learn Python, and I was wondering what the best way to create a list of variable length filled with copies of one thing is. Specifically, I want to create the list [[],[],...,[]] where there are k empty lists. Right now, I'm looping over k and appending empty lists to my growing list of empty lists. I can't do [] * k because modifying one of the [] modified them all.

More generally, my setup is that I need k containers that I will fill with numbers. I do not know how many numbers will go in each container. Is there a better way to do this than a list of empty lists? I'm using NumPy/SciPy if that's any help.

from itertools import repeat

QuarkJets
Sep 8, 2008

drainpipe posted:

I'm just beginning to learn Python, and I was wondering what the best way to create a list of variable length filled with copies of one thing is. Specifically, I want to create the list [[],[],...,[]] where there are k empty lists. Right now, I'm looping over k and appending empty lists to my growing list of empty lists. I can't do [] * k because modifying one of the [] modified them all.

More generally, my setup is that I need k containers that I will fill with numbers. I do not know how many numbers will go in each container. Is there a better way to do this than a list of empty lists? I'm using NumPy/SciPy if that's any help.

The list comprehension thing that vikingstrike mentioned would go like this:
Python code:
list_of_lists = [[] for i in range(k)]
Would you be interested in telling us more about what you're doing? When I'm working with people who are new at Python the "I need a list of list of lists" idea sometimes comes up when really they'd be better served by one list that holds a bunch of struct instances or something.

Basically there might be a better way to accomplish whatever you're trying to do without resorting to lists of lists

QuarkJets fucked around with this message at 19:46 on Apr 8, 2016

Cingulate
Oct 23, 2012

by Fluffdaddy

QuarkJets posted:

The list comprehension thing that vikingstrike mentioned would go like this:
Python code:
list_of_lists = [[] for i in range(k)]
Would you be interested in telling us more about what you're doing? When I'm working with people who are new at Python the "I need a list of list of lists" idea sometimes comes up when really they'd be better served by one list that holds a bunch of struct instances or something.

Basically there might be a better way to accomplish whatever you're trying to do without resorting to lists of lists

Possibly slightly better:

code:
list_of_lists = [[] for _ in range(k)]
Also yes, my guess would also be there are very few instances where you want to do that - pre-allocate lists of empty lists of varying length. Elaborate the problem.

drainpipe
May 17, 2004

AAHHHHHHH!!!!
I'm coding up the k-means clustering algorithm for a homework assignment. I'm given a list of data points (each with two coordinates) and I need to put them into k clusters. The way I'm doing it is to define k empty lists and fill them up with indices of my data points according to which cluster they belong to. I just realized that adding an extra column to the data array to indicate cluster assignment might work just as well.

edit: actually, that probably wouldn't be good since I need to calculate the means of a cluster and accessing the points of a cluster would be much harder if I had to read it from a field.

drainpipe fucked around with this message at 21:05 on Apr 8, 2016

Adbot
ADBOT LOVES YOU

vikingstrike
Sep 23, 2007

whats happening, captain

drainpipe posted:

I'm coding up the k-means clustering algorithm for a homework assignment. I'm given a list of data points (each with two coordinates) and I need to put them into k clusters. The way I'm doing it is to define k empty lists and fill them up with indices of my data points according to which cluster they belong to. I just realized that adding an extra column to the data array to indicate cluster assignment might work just as well.

edit: actually, that probably wouldn't be good since I need to calculate the means of a cluster and accessing the points of a cluster would be much harder if I had to read it from a field.

Have you looked into pandas? Stuff like this seems like it would be suited well. For example, to find the mean of a cluster is a simple groupby function call. Accessing the data points of a cluster is just indexing, etc.

  • Locked thread