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
Obdicut
May 15, 2012

"What election?"
Hey guys, very much a noobie here struggling through some python programming.

I have excel files. Oh boy do I have excel files. I'm trying to write a program that (for a start) searches through a specific column and finds non-empty cells and identifies them. To that end, I'm using XLRD, slicing the column, and then attempting to use index to return the position in the list. But it isn't working, no matter how I try it.

This is what I've cobbled together:
code:
import xlrd
mediascript = xlrd.open_workbook("ForComposer.xls")
sheet0 = mediascript.sheet_by_index(0)
tablenames = sheet0.col_slice(1,2)
tablevalues = sheet0.col_values(1,2)
tabletypes = sheet0.col_values(1,2)
tablehandles = []

for name in tablenames:
	if name != " empty/:/'/'":
		tablehandles.append(name)
print tablehandles
print sheet0.cell_type(1,1)

tableindex = sheet0.col_types(1, start_rowx=3, end_rowx=None)

b = [item for item in range(len(tableindex)) if tableindex[item] == '1']
print tableindex
print b
So there's two failed attempts here. Neither of them works. With 'tableindex' I can get a good list of cells segregated by empty or full but I then can't do crap with it.

Is my approach completely flawed?

Adbot
ADBOT LOVES YOU

tef
May 30, 2004

-> some l-system crap ->
http://www.slideshare.net/r1chardj0n3s/dont-do-this-24000445 i haven't even got halfway this is amazingly disgusting

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Obdicut posted:

excel stuff

I'm not sure if I understood what you really want to do but I noticed this with a hasty look:

Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] == '1']
tableindex is a list of ints and not strings so I guess you were really trying something like
Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] == 1]
or
Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] != 0]
if you want to get anything that is not the empty cell. Check this table to make sure what you really want to get.


edit:
Python code:
cells = sheet0.col_slice(1, 2)
filtered_cells = []
filtered_values = []
for cell in cells:
    if cell.ctype != 0:                     # you can just write 'if cell.ctype:' here actually
        filtered_cells.append(cell)         # if you want to keep the entire cell object
        filtered_values.append(cell.value)  # if you want just the values

Symbolic Butt fucked around with this message at 14:48 on Jul 8, 2013

Obdicut
May 15, 2012

"What election?"

Symbolic Butt posted:

I'm not sure if I understood what you really want to do but I noticed this with a hasty look:

Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] == '1']
tableindex is a list of ints and not strings so I guess you were really trying something like
Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] == 1]
or
Python code:
b = [item for item in range(len(tableindex)) if tableindex[item] != 0]
if you want to get anything that is not the empty cell. Check this table to make sure what you really want to get.


edit:
Python code:
cells = sheet0.col_slice(1, 2)
filtered_cells = []
filtered_values = []
for cell in cells:
    if cell.ctype != 0:                     # you can just write 'if cell.ctype:' here actually
        filtered_cells.append(cell)         # if you want to keep the entire cell object
        filtered_values.append(cell.value)  # if you want just the values

Thank you that, the stupid mistake of searching string vs. integer is what was messing up my index-ing. The code you included looks a lot more elegant than mine, and since I need to both grab the index and the value of the cell it'll be super-useful.

Sorry, that was a mistake I should have caught. Thank you for the help.

Thermopyle
Jul 1, 2003

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

tef posted:

http://www.slideshare.net/r1chardj0n3s/dont-do-this-24000445 i haven't even got halfway this is amazingly disgusting

Python code:
import pyxml_loader

onionradish
Jul 6, 2006

That's spicy.
Is it bad practice to put a lot of the "prep work" for a class into its __init__?

I'm writing a throwaway script that parses a recipe from a URL to get more familiar with lxml, writing classes, unit tests and exception-handling. In my first cut at the script, "recipe = Recipe(url)" fetches the HTML from the URL, parses it, then populates a bunch of class attributes.

Should I instead be calling a method to do that on the object after initializing it? Something like "recipe = Recipe()" then "recipe.getfromurl(url)"?

Chosen
Jul 11, 2002
Vibrates when provoked.

onionradish posted:

Is it bad practice to put a lot of the "prep work" for a class into its __init__?

I'm writing a throwaway script that parses a recipe from a URL to get more familiar with lxml, writing classes, unit tests and exception-handling. In my first cut at the script, "recipe = Recipe(url)" fetches the HTML from the URL, parses it, then populates a bunch of class attributes.

Should I instead be calling a method to do that on the object after initializing it? Something like "recipe = Recipe()" then "recipe.getfromurl(url)"?

Yeah, generally speaking, you should try to avoid doing "real work" in a constructor. Here's a good read from Google that mentions it, with some other rules of thumb: http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-decided-to.html.

coaxmetal
Oct 21, 2010

I flamed me own dad
technically speaking __init__ isn't a constructor :science: it is an initializer run automatically on a new instance after it is constructed. There is an actual constructor, __new__, but generally you don't need to use it.

what you are doing actually sounds like a pretty reasonable use case for initialization, assuming a Recipe isn't useful without that information. it would be silly to create an object, then add all the instance information. It wouldn't hurt to separate out some of that into a different method and call that from inside __init__ though, easier to unit test and more flexible. I'd probably have __init__ take an optional kwarg of url, and initialize itself using another method, say get_from_url, if a url was provided.

something like

code:
class Recipe(object):
    def __init__(self, url=None):
        if url:
            self.get_from_url(url)
        # other more general initialization steps if necessary

coaxmetal fucked around with this message at 04:59 on Jul 9, 2013

QuarkJets
Sep 8, 2008

Yes, __new__ is technically the constructor, but you almost never need to use __new__, so for all intents and purposes when someone says "my constructor in PYTHON" everyone knows what they really mean is __init__ (which, while technically is not a constructor, serves many of the same purposes)

Still, it's a cool thing to be aware of

FoiledAgain
May 6, 2007

Symbolic Butt posted:

Every time I use lambda I feel like I'm compensating some shortcoming in the language, like for example this nested defaultdict thing:
Python code:
d = collections.defaultdict(lambda: [0, collections.defaultdict(int)])

Can you explain what this does? I understand how defaultdict works, I use it a lot, but I've only ever used it with Python's basic types, e.g. dd=defaultdict(list). This looks like it makes a dictionary where by default every value is a function - am I reading this correctly? Why is there another defaultdict inside?

Opinion Haver
Apr 9, 2007

FoiledAgain posted:

Can you explain what this does? I understand how defaultdict works, I use it a lot, but I've only ever used it with Python's basic types, e.g. dd=defaultdict(list). This looks like it makes a dictionary where by default every value is a function - am I reading this correctly? Why is there another defaultdict inside?

The argument to defaultdict isn't a type, it's a function; defaultdict(f) will call f() to create the 'default' value; for lists this is the empty list, for ints it's 0, etc. The reason it does that and doesn't just take a value is because if it did, defaultdict([]) would use the same list object, which is probably not what you want. So, for example, you can do
Python code:
d = defaultdict(lambda: defaultdict(int))
d["hi"]["hello"] == 0
d["foo"]["bar"] = "baz"

FoiledAgain
May 6, 2007

yaoi prophet posted:

The argument to defaultdict isn't a type, it's a function; defaultdict(f) will call f() to create the 'default' value; for lists this is the empty list, for ints it's 0, etc. The reason it does that and doesn't just take a value is because if it did, defaultdict([]) would use the same list object, which is probably not what you want. So, for example, you can do
Python code:
d = defaultdict(lambda: defaultdict(int))
d["hi"]["hello"] == 0
d["foo"]["bar"] = "baz"

Ah that makes sense, thanks. I learned it this way: I tried defaultdict(list()) and it didn't work then I tried defaultdict(list) and it did, so I got it in my head that you pass a type.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Ronald Raiden posted:

technically speaking __init__ isn't a constructor :science: it is an initializer run automatically on a new instance after it is constructed.

Now explain how Java and C++ constructors aren't actually constructors either.

onionradish
Jul 6, 2006

That's spicy.
Thanks for the __init__ feedback.

The googletesting link Chosen posted is great timing because I'll be trying to set up tests next so I can refactor now where needed.

I'd actually done all of the "work" in the __init__ through methods as Ronald Raiden suggested, but the idea of making the parameter optional (even though it'd always be provided in practice) seems like it'd be better for testing, allowing creation of a "plain" instance and then assertions against the methods.

DSA_Key
Dec 9, 2004
minimalist
Thought I would post this here asking for a little help. I'm trying to return a list from a function but when I print the list out outside the function it comes back with "None".


Here's the code:

Python code:

    for record in records:

        badip = failed(record)

    print(badip)


def failed(record):

    badip = []

    if record[8] == "Failed":
        
        if record[3] not in badip:
          
          badip.append(record[3])
          
          return badip

When I try it in the python interpreter to check if my logic is sound it appears to work:

Python code:

>>> def list():
	myl = []
	myl.append('1')
	return myl

>>> list()
['1']
>>> mylist = list()
>>> mylist
['1']

Any help is appreciated.

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

yaoi prophet posted:

The argument to defaultdict isn't a type, it's a function; defaultdict(f) will call f() to create the 'default' value; for lists this is the empty list, for ints it's 0, etc. The reason it does that and doesn't just take a value is because if it did, defaultdict([]) would use the same list object, which is probably not what you want. So, for example, you can do
Python code:
d = defaultdict(lambda: defaultdict(int))
d["hi"]["hello"] == 0
d["foo"]["bar"] = "baz"

This allows perhaps the neatest encoding of trees (maybe a rose tree?) in python:
code:
inf_dict = lambda: defaultdict(inf_dict)

FoiledAgain
May 6, 2007

DSA_Key posted:

Thought I would post this here asking for a little help. I'm trying to return a list from a function but when I print the list out outside the function it comes back with "None".


Here's the code:

Python code:

    for record in records:

        badip = failed(record)

    print(badip)


def failed(record):

    badip = []

    if record[8] == "Failed":
        
        if record[3] not in badip:
          
          badip.append(record[3])
          
          return badip


Python functions return "None" by default. Even if you don't write a return line, when the function is done it returns None. That's what happening inside of failed when it doesn't pass the if check.

Dominoes
Sep 20, 2007

What FoiledAgain said.

Here's a cleaner way, using list comprehensions. It replaces the entire block of code you posted.

Python code:
badip = [record[3] for record in records if record[8] == "Failed"]

Haystack
Jan 23, 2005





^^^^^ Just FYI, that list comprehension isn't exactly the same, since it won't filter out duplicate ips.

DSA_Key posted:

Thought I would post this here asking for a little help. I'm trying to return a list from a function but when I print the list out outside the function it comes back with "None".


Here's the code:

Python code:

    for record in records:
        badip = failed(record)
    print(badip)

def failed(record):
    badip = []
    if record[8] == "Failed":    
        if record[3] not in badip:       
          badip.append(record[3])
          return badip
Any help is appreciated.


You've got two reasons that badip is turning out None: First, failed will only return a list if it's a bad IP. Second, the way you've written it, badip will only ever either be None or a list with one item with it, since you're overwriting it with a newly returned value every iteration of the for loop. Also, I suspect that you're expecting the badip list created in the failed function will carry over between calls. That's not the case; the list will get recreated each and every time the function gets called.

Realistically speaking, you should structure your approach differently. The failed function should only return a bad ip or None. The for loop should be the one responsible for filling and filtering the list of bad ips. For instance:

Python code:
def failed(record):
    if record[8] == "Failed":        
        return record[3]
    #There's an implied return None at the end of every python function

bad_ips = []
for record in records:
    bad_ip = failed(record)
    if bad_ip is not None and bad_ip is not in bad_ips:
        bad_ips.append(bad_ip)
print(bad_ips)

Dren
Jan 5, 2001

Pillbug
There's only one hard and fast rule I apply to __init__. If an error is encountered in __init__ throw the exception (or capture it and throw your own exception). It doesn't make much sense to swallow the error and allow the constructor to return a no good object that will blow up later when someone tries to use it.

Stuff like how much real work to put into __init__ is a matter of use-case. I try to go with as little as possible.

DSA_Key
Dec 9, 2004
minimalist

Haystack posted:


You've got two reasons that badip is turning out None: First, failed will only return a list if it's a bad IP. Second, the way you've written it, badip will only ever either be None or a list with one item with it, since you're overwriting it with a newly returned value every iteration of the for loop. Also, I suspect that you're expecting the badip list created in the failed function will carry over between calls. That's not the case; the list will get recreated each and every time the function gets called.

Realistically speaking, you should structure your approach differently. The failed function should only return a bad ip or None. The for loop should be the one responsible for filling and filtering the list of bad ips. For instance:


This is very helpful, I arrived at this conclusion shortly after I posed the question, I guess my brain wasn't working this morning. Thanks again!

FoiledAgain
May 6, 2007

What is going on here? Why is seg changing types?

code:

import Tkinter

def some_method(self):
	#...stuff
	seg = str(line[0])
	seg_button = Tkinter.Button(self, text=seg, command=lambda: self.show_segment_info(seg))

def show_segment_info(self,seg):
	title = 'WORDS CONTAINING ' + seg
	#other stuff that never happens because of TypeError


TypeError: cannot concatenate 'str' and 'instance' objects
edit: just to be clear, I know how to fix this, I'm more curious as to what's making this happen
edit2: changed to show Tkinter

FoiledAgain fucked around with this message at 04:24 on Jul 10, 2013

Dominoes
Sep 20, 2007

Maybe show_segment_info() is altering it in place. Check seg's type before and after the 'seg_button =' line.

Dominoes fucked around with this message at 23:56 on Jul 9, 2013

FoiledAgain
May 6, 2007

Dominoes posted:

Maybe show_segment_info() is altering it in place. Check seg's type before and after the 'seg_button =' line.

It's definitely a string going in, because I cast it to one the line before creating the Button. I didn't cut out any code there. And that concatenation is actually the first line of show_segment_info() so I'm sure nothing has happened to seg yet. I figured it had something to do with lambdas(?)

coaxmetal
Oct 21, 2010

I flamed me own dad
I think self.show_segment_info(seg) isnt' evaluated until that lambda is executed, so that's probably related

SelfOM
Jun 15, 2010
Something like this works for me: https://gist.github.com/anonymous/5962369, maybe it has something do with with what's going on in Button as this works for me:

Python code:
test = Test()
test.something(20)
test.seg_button.push()
I'm having with trouble with Cython memory views:
Python code:
import numpy as np
cimport numpy as np                                                                     
cpdef double test(int[:]):
      ### Stuff ## 
Used to work, now I get:
code:
cpdef double test(int[:]):
                  ^
Expected an identifier or literal

FoiledAgain
May 6, 2007

I realize that I didn't say that's the Button class from Tkinter, not my own object. Sorry for the confusion.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

yaoi prophet posted:

The argument to defaultdict isn't a type, it's a function; defaultdict(f) will call f() to create the 'default' value; for lists this is the empty list, for ints it's 0, etc. The reason it does that and doesn't just take a value is because if it did, defaultdict([]) would use the same list object, which is probably not what you want. So, for example, you can do
Python code:
d = defaultdict(lambda: defaultdict(int))
d["hi"]["hello"] == 0
d["foo"]["bar"] = "baz"

I don't really see why it would necessarily use the same list object, but I guess it would break the possibility of a tree like Malcolm XML showed.

My beef is how misleading the examples of defaultdicts are when they use int, float or list as the argument. Maybe using just lambdas/building the constant functions would be better?
Python code:
defaultdict(lambda: 12)
defaultdict(lambda: defaultdict(lambda: 0))
defaultdict(lambda: [])
I really hated this but thinking more about it now I can see why it's important for the argument to be callable.

Sylink
Apr 17, 2004

Are there any Python modules that I can use to make requests to a webpage and show what resources have been requested and hopefully the amount of time the requests take?

I want to make something that does what this web page analyzer does: http://tools.pingdom.com/fpt/

I can request a webpage easily enough in Python but trying to find examples or modules that would help me break it down further like Chrome/firefox developer tools and that pingdom tool do has not been easy.

RobotRob
Aug 7, 2007

Let's get weird, but not end of BSG weird.

Sylink posted:

Are there any Python modules that I can use to make requests to a webpage and show what resources have been requested and hopefully the amount of time the requests take?

I want to make something that does what this web page analyzer does: http://tools.pingdom.com/fpt/

I can request a webpage easily enough in Python but trying to find examples or modules that would help me break it down further like Chrome/firefox developer tools and that pingdom tool do has not been easy.

You will probably want to look into the HAR format. That is the format standard for gathering all those different web requests. It is basically JSON.

http://element34.ca/blog/harpy
This link may set you down the right path.

spitefulcrow
Jun 16, 2013

Symbolic Butt posted:

I don't really see why it would necessarily use the same list object, but I guess it would break the possibility of a tree like Malcolm XML showed.

My beef is how misleading the examples of defaultdicts are when they use int, float or list as the argument. Maybe using just lambdas/building the constant functions would be better?
Python code:
defaultdict(lambda: 12)
defaultdict(lambda: defaultdict(lambda: 0))
defaultdict(lambda: [])
I really hated this but thinking more about it now I can see why it's important for the argument to be callable.

Lists are a bad example to see why it would use the same object — consider a more complex (i.e. user-defined) type:

Python code:
class MyBizarroList(list):
    # do some weird thing here
Remember that [] is equivalent to list(), so the equivalent defaultdict construction here is:

Python code:
defaultdict(MyBizarroList())
So can you see how, when given an arbitrary object instance, defaultdict wouldn't know how to make more of them (given that copy() is fraught with danger and there are many ways to get a new instance of something)? That's why you give it a callable that takes no arguments — it provides a single interface that defaultdict knows how to use to construct as many instances of the default value as needed.

Another way to look at this: most Python type names refer to the constructor for the type. As I mentioned above, [] is really just sugar for list(), as {} is for dict() and () is for tuple(). Since you instantiate your user-defined classes by invoking the class name, why should builtin types be any different?

For posterity, here's how to make an arbitrarily deep nested dictionary structure (with autovivification of intermediate dictionaries like Perl hashes):

Python code:
def moar_dicts():
    return defaultdict(moar_dicts)

d = defaultdict(moar_dicts)
This may or may not be of use to you.

Hot Dog Day #42
Jun 17, 2001

Egbert B. Gebstadter

FoiledAgain posted:

What is going on here? Why is seg changing types?

Do you do anything else with seg later in some_method? Lambda will use its last value from that call of the function:
code:
>>> def foo():
...  x = "butts"
...  ret = lambda : x
...  x = "dongs"
...  return ret
... 
>>> bar = foo()
>>> bar()
'dongs'

mellowjournalism
Jul 31, 2004

helllooo
Hey guys, so I teach Python one-on-one at a private high school and it's lame to keep telling my students "it's a hassle" when they ask me if they can deploy their little choose your own adventure and conversation programs to their friends and family. Sure for us it seems simple to just make sure python is installed, run a program in IDLE or whatever, etc. And my students obviously can do it too. But what if they want to show it to their grandma? Grandma just wants a double-click, and even that's already asking a lot. Things would also be easier if we were dealing with GUIs, but right now we're talking about really simple console text-based programs.

So I'm wondering, of all the random and partially-supported deployment methods out there, what you guys think is the smoothest and most reliable across a broad range of given systems. Hopefully resulting in a double-click affair. I realize this is asking kind of a lot especially with a text-based program but I'm wondering if I'm missing something really simple. Thanks!



Also, any of you teachers out there, do you prefer to teach in 2.7 or 3.3?

mellowjournalism fucked around with this message at 19:58 on Jul 11, 2013

Pie Colony
Dec 8, 2006
I AM SUCH A FUCKUP THAT I CAN'T EVEN POST IN AN E/N THREAD I STARTED
i don't know how good it is, but py2exe exists.

OnceIWasAnOstrich
Jul 22, 2006

Both cx_freeze and PyInstaller have worked for me and are both cross-platform in the sense that you can use it on Windows/OSX/Linux to build a double-click executable for that system, although PyInstaller seemed to have more problems with some libraries.

Dominoes
Sep 20, 2007

yellowjournalism posted:

Hey guys, so I teach Python one-on-one at a private high school and it's lame to keep telling my students "it's a hassle" when they ask me if they can deploy their little choose your own adventure and conversation programs to their friends and family. Sure for us it seems simple to just make sure python is installed, run a program in IDLE or whatever, etc. And my students obviously can do it too. But what if they want to show it to their grandma? Grandma just wants a double-click, and even that's already asking a lot. Things would also be easier if we were dealing with GUIs, but right now we're talking about really simple console text-based programs.

So I'm wondering, of all the random and partially-supported deployment methods out there, what you guys think is the smoothest and most reliable across a broad range of given systems. Hopefully resulting in a double-click affair. I realize this is asking kind of a lot especially with a text-based program but I'm wondering if I'm missing something really simple. Thanks!



Also, any of you teachers out there, do you prefer to teach in 2.7 or 3.3?
You need cx_freeze (Installers avaialable in the link), and a copy of msvcp100.dll, and msvcr100.dll. They're located in your Windows directory. I don't remember where, but I'll send you a copy if you can't find them. Cx_freeze is a module that makes standalone Windows programs. The DLLs need to be placed in the generated .exe's directory, incase the users don't have the same version of Visual C++ your Python install uses.

Create a setup.py file that looks like this, and put it in your program's directory. Fill in the blanks.
Python code:
import sys
import os

import cx_Freeze

import module_locator

DIR = module_locator.path()
base = None
if sys.platform == "win32":
    base = "Win32GUI"

cx_Freeze.setup(
    name = "",
    version = "",
    description = "",
    executables = [cx_Freeze.Executable(os.path.join(DIR, '.py'),
                   base=base, icon=os.path.join(DIR, '.ico'))]
)
Run this .py file, from the same directory:
Python code:
import module_locator
import os

DIR = module_locator.path()
os.system(' '.join(['python', os.path.join(DIR, 'setup.py'), 'build']))
This is the module_locator file referenced:
Python code:
import os
import sys

def we_are_frozen():
    # All of the modules are built-in to the interpreter, e.g., by py2exe
    return hasattr(sys, "frozen")

def path():
    if we_are_frozen():
        return os.path.dirname(sys.executable)
    return os.path.dirname(__file__)

Dominoes fucked around with this message at 02:08 on Jul 12, 2013

mellowjournalism
Jul 31, 2004

helllooo
Ssss yeah I run a macbook at school, as do most of my students, along with our school computers running various versions of OS X. I can do it on my home PC but that still leaves out students who only have access to OS X. I tried to use wineskin, and maybe I'll try again, but the fact that it even started to give me a headache says to me that it's not really appropriate for the level I teach at (mostly middle school-age kids; I forgot to mention that even though we're technically a high school, we do one-on-one instruction and most of my python students are like 12)

I was already planning on pretty much just going through all the ones listed here http://wiki.python.org/moin/deployment but figured I'd ask you guys for preferred methods or anything simple I'm missing. I might have to also just target Python 2.7 since there's generally less support for 3.3. Thanks though!

Dominoes
Sep 20, 2007

Discovering the same hassle clued me in that Python is more of a programmer's programming language. It's interesting how the language and modules are designed to be easy to understand and use, but the results for users are not.

Dominoes fucked around with this message at 01:04 on Jul 12, 2013

mellowjournalism
Jul 31, 2004

helllooo
I actually hate teaching Python and transition to Java as soon as possible (for a variety of reasons). As you said, Python feels more like a really convenient language for prototyping, getting quick little things done, and whatever web/scripting/etc stuff that I don't know about but am aware is quite useful for others.

Half the time Python honestly builds in a lot of arbitrary and confusing training scars for kids that can be annoying to deal with when they learn the more popular industry languages.

Adbot
ADBOT LOVES YOU

spankweasel
Jan 4, 2006

yellowjournalism posted:

I actually hate teaching Python and transition to Java as soon as possible (for a variety of reasons). As you said, Python feels more like a really convenient language for prototyping, getting quick little things done, and whatever web/scripting/etc stuff that I don't know about but am aware is quite useful for others.

Half the time Python honestly builds in a lot of arbitrary and confusing training scars for kids that can be annoying to deal with when they learn the more popular industry languages.

:ughh:

  • Locked thread