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
Suspicious Dish
Sep 24, 2011

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

KICK BAMA KICK posted:

OK, I'll concede the PEP-8 point. I never actually use a named lambda in reality, that was just for illustration of the concept, but would you really rather see a full-fledged def than a lambda assigned to a name on its own line for something that's simple but barely too long to comfortably fit an an anonymous argument as like the key of sorted? Cause despite whatever PEP-8 has to say, the latter seems way more readable to me.

Judgment is key here. I don't think one is fundamentally more unreadable than the other, it heavily depends on the context.

For cases involving something like sorted(steam_inventory, key=lambda game: game.price), the lambda is perfectly fine, and I prefer it over "fieldgetter" or whatever the dumb operators function is.

If you were doing something like:

Python code:
def game_cost(game):
    # tax is 10% on the *retail* price, not the sale price
    tax = game.retail_price * 0.10
    return game.sale_price + tax

how_worthless_am_i = sum(game_cost(item) for game in steam_inventory)
Then the full method is a lot better than shoving it all in one line.

Adbot
ADBOT LOVES YOU

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Suspicious Dish posted:

For cases involving something like sorted(steam_inventory, key=lambda game: game.price), the lambda is perfectly fine, and I prefer it over "fieldgetter" or whatever the dumb operators function is.

I got used to operator.attrgetter because in cases like this I never want to sort by only one attribute so

sorted(steam_inventory, key=attrgetter(price, name))

looks less complicated to me than

sorted(steam_inventory, key=lambda game: (game.price, game.name))

(it's also faster if you're silly to be into python code micro-optimization)

KICK BAMA KICK
Mar 2, 2009

Suspicious Dish posted:

Judgment is key here. I don't think one is fundamentally more unreadable than the other, it heavily depends on the context.
That's cool, I'd just add one factor that hasn't been mentioned: at the scope of a module, I might lean toward a def. Inside any scope that's already enclosed, I would lean toward a lambda, even if that meant giving it a name, cause if I see a def inside a function or a method my first thought is to assume it's a closure and start looking for any names it uses in the enclosing scope and to me that's a little less readable (also you're throwing another level of indentation in there) but maybe that's just me.

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

KICK BAMA KICK posted:

OK, I'll concede the PEP-8 point. I never actually use a named lambda in reality, that was just for illustration of the concept, but would you really rather see a full-fledged def than a lambda assigned to a name on its own line for something that's simple but barely too long to comfortably fit an an anonymous argument as like the key of sorted? Cause despite whatever PEP-8 has to say, the latter seems way more readable to me.
Granted the PEP-8 isn't a strict style guide unless you're doing development of Python itself (the line limit guideline in particular is rightfully frequently ignored). However one stated reason for using def instead of assigning a lambda is that it can help with debugging due to tracing names.

Also note you are allowed to do one-line def statements
Python code:
get_butts = lambda x: x.butts
Python code:
def get_butts(x): return x.butts

SurgicalOntologist
Jun 17, 2004

Suspicious Dish posted:

Don't write Lisp in Python, please.

I've never written Lisp and it looks indecipherable to me. Whereas what I would wrote appears pretty obvious even to someone with little functional experience (I think).

That said, the moment someone pays me to write Python for them, I will stop doing that kind of thing. But as long as I'm just writing data analysis scripts for myself, I find it a real easy approach.

Anyways, a real question. Compare
Python code:
def word_counts(filename):
    with open(filename) as f:
        raw_text = f.read()
     return Counter(word.lower() for word in raw_text.split())
with
Python code:
def word_counts(filename):
    return Counter(word.lower() for word in open(filename).read().split())
I see this kind of thing occasionally, using open without a with statement if it's in a one-liner. Are they essentially equivalent, and having a one-line with block isn't really necessary? Because in the second version, the filename object is never assigned a name so it's immediately garbage collected. Oh but wait, is it ever closed?

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

SurgicalOntologist posted:

Oh but wait, is it ever closed?
The file is closed when the object is garbage collected. However...

SurgicalOntologist posted:

Because in the second version, the filename object is never assigned a name so it's immediately garbage collected.

...this is not true. I'm dumb.

\/ it does, I got confused. But I'm still not a big fan of open() one-liners.

Symbolic Butt fucked around with this message at 18:06 on Jan 17, 2015

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

Symbolic Butt posted:

The file is closed when the object is garbage collected. However...


...this is not true. So yeah, not explicitly closing file objects is a bad habit.
Does it get garbage collected when it goes out of scope at least? (ie, when the function returns there?)

SurgicalOntologist
Jun 17, 2004

Can you guys clarify? Are you saying that (1) it gets closed when it gets garbage collected (that would make sense) but (2) it does not get garbage collected until the function returns? That makes less sense.

What you think about the advisability of it? I see it for example in setup.py with something like long_description=open('README.rst').read(). I guess the question is if all you're doing with the file object before it gets out of scope is calling the read method, can that method fail? If so you'd want to use with to close it in case it does fail.

E: saw your edit. I'm inclined to agree. I guess this same argument could be made against my functional version as well, come to think of it. I guess you could make a safe_read function that encapsulates the with statement with the read method.

ironypolice
Oct 22, 2002

SurgicalOntologist posted:

I've never written Lisp and it looks indecipherable to me. Whereas what I would wrote appears pretty obvious even to someone with little functional experience (I think).

That said, the moment someone pays me to write Python for them, I will stop doing that kind of thing. But as long as I'm just writing data analysis scripts for myself, I find it a real easy approach.

Anyways, a real question. Compare
Python code:
def word_counts(filename):
    with open(filename) as f:
        raw_text = f.read()
     return Counter(word.lower() for word in raw_text.split())
with
Python code:
def word_counts(filename):
    return Counter(word.lower() for word in open(filename).read().split())
I see this kind of thing occasionally, using open without a with statement if it's in a one-liner. Are they essentially equivalent, and having a one-line with block isn't really necessary? Because in the second version, the filename object is never assigned a name so it's immediately garbage collected. Oh but wait, is it ever closed?

These are pretty much equivalent in cpython, but garbage collection doesn't necessarily work the same across all implementations. In pypy, for instance, the file wouldn't immediately be closed in the second function.

Begall
Jul 28, 2008
A few things from the current project I'm playing around with...

1. Authentication over JSON-RPC

I'm trying to build a system where the application logic and the UI are totally separated, with all information/updates between them through JSON-RPC calls. I'd like to keep the user account/authentication in the application logic layer, both to avoid each UI having to implement its own user database, and because I'd like the flexibility of being able to do different things based on the user that is calling the service. The first method of doing this that comes to mind would be to create user/session tables in the application DB along with a service that would pass back a session token for a given user upon correct credentials being supplied, which would then need to be used in all subsequent service calls to identify that user. However, this seems like a problem that would have been solved in the past and better then I could manage, so am I missing something obvious?

2. SQLAlchemy Sessions

In the application layer code I have so far, I have a file which contains the SQL database code like so:

Python code:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, Query
engine = create_engine('postgres://user:password@IP:Port/postgres', convert_unicode=True, echo=False)
Base = declarative_base()
Base.metadata.reflect(engine)

class address_data(Base):
    __table__ = Base.metadata.tables['address_data']
In a class which imports this I am then doing the following:

Python code:
from database import address_data, engine

class Address(object): 
    def __init__(self): 
        self._db_session  = scoped_session(sessionmaker(bind=engine))
Basically, am I doing this correctly? With this setup, I will need to import from the database module for each class I wish to have database access and create a scoped_session and I'm not sure if that's the best practise or not, or even something that will cause me problems down the road.

3. Auto Incrementing Numbers & SQLAlchemy

In the address_data table referenced above, the PK for it is set up as an auto incrementing integer in the Postgres DB. When doing some testing, I discovered that if I make a .add( ) call to the session, but not a .commit() after, it will still increment that integer and effectively I've lost that reference since there will never be a record for it. Is there a way to avoid this, or is there a good reason for it to work in that fashion?

KICK BAMA KICK
Mar 2, 2009

Begall posted:

2. SQLAlchemy Sessions
I'm not quite sure what you're doing here in the larger picture -- is your code interacting with a pre-existing database whose schema you don't have any control over (a guess from the Base.metadata.reflect)? I'm confused as to what the address_data (got a good reason for an unconventional class name like that?) and Address classes are supposed to represent.

Begall
Jul 28, 2008

KICK BAMA KICK posted:

I'm not quite sure what you're doing here in the larger picture -- is your code interacting with a pre-existing database whose schema you don't have any control over (a guess from the Base.metadata.reflect)? I'm confused as to what the address_data (got a good reason for an unconventional class name like that?) and Address classes are supposed to represent.

I do have control over the schema, but I've been making changes to it quite rapidly through a web admin tool, so it seemed easier to just reflect it rather than go through and update the code each time. address_data is simply the name of the table, and represents the table so that I can do things like:

Python code:
self.db_session.query(address_data).filter_by(addressref = self.addressref).first()
Address is then implementing some application logic, which also includes calls to the address_data table. Does that make sense?

KICK BAMA KICK
Mar 2, 2009

I'm still not sure if I'm completely misunderstanding what you're doing -- entirely possible, I've just been teaching myself SQLAlchemy over the course of my own pet project with no prior coding experience -- or if maybe you're misapplying some SQLAlchemy concepts and have gotten yourself kinda stuck halfway between the declarative way of doing things and the other way? Like is there more to the definition or use of address_data or could you just be using a Table object?

Does an instance of Address represent a single address (whatever that means in your domain) corresponding to a single record in the address_data table? If so, it seems like the declarative way of doing this would be to scrap that address_data intermediary and make Address to itself be the mapped class inheriting from Base, which you could use in queries the same way you're using address_data. If not, at least the way I've been working, address_data is the thing that should be called Address and I wouldn't know what to call what you're calling Address without understanding what exactly it is.

That's before we get to the question about the Session itself, which was pretty thorny for me to work out in my own experience too.

Space Kablooey
May 6, 2009


Begall posted:

I do have control over the schema, but I've been making changes to it quite rapidly through a web admin tool, so it seemed easier to just reflect it rather than go through and update the code each time. address_data is simply the name of the table, and represents the table so that I can do things like:

Python code:
self.db_session.query(address_data).filter_by(addressref = self.addressref).first()
Address is then implementing some application logic, which also includes calls to the address_data table. Does that make sense?

You should look at alembic. It generates migrations for your database (creating tables/fields, altering them, etc.) based on your SQLAlchemy models.

Aaronicon
Oct 2, 2010

A BLOO BLOO ANYONE I DISAGREE WITH IS A "BAD PERSON" WHO DESERVES TO DIE PLEEEASE DONT FALL ALL OVER YOURSELF WHITEWASHING THEM A BLOO BLOO
What's the best way to dynamically add more subclasses (and by extension, remove them) to an existing class? Right now I have a generic 'Entity' class that inherits a number of mixin classes to provide it with specific utility - this mixin handles if and how something moves, this mixin has variables and methods that determine that it's a biological construct, etc. However, I'd like the ability to dynamically add and remove other mixins during runtime.

Adding the new classes as a variable is possible but the A.B.C.whatever() syntax gets messy and it's hard to programmatically determine whether or not a particular class has the mixin class added. A dict in the base Entity class that the mixins get added to? That lets me add and remove things and also the ability to determine if the mixin class exists attached to the base class and provide a default if it doesn't, so that's what I'm leaning towards, but I dunno if there's an easier / more obvious route that I'm not seeing.

nonathlon
Jul 9, 2004
And yet, somehow, now it's my fault ...
I'm using the builtin logging module to ... well ... log stuff and do some informational messages for the user. I was writing a few simple convenience functions for myself and in the process was trying to extend the logger behaviour (add in some more format specifiers, etc.)

Except: while you can define a Logger class for the logging to use, this doesn't get used as the root logger, because by simply importing logging, you instantiate the root logger.

Which is odd behaviour and seems to imply that you can never redefine or override the root logger. Googling shows other people coming to the realisation, with one or two cryptic reports that others have "got around it". Is this right?

QuarkJets
Sep 8, 2008

outlier posted:

I'm using the builtin logging module to ... well ... log stuff and do some informational messages for the user. I was writing a few simple convenience functions for myself and in the process was trying to extend the logger behaviour (add in some more format specifiers, etc.)

Except: while you can define a Logger class for the logging to use, this doesn't get used as the root logger, because by simply importing logging, you instantiate the root logger.

Which is odd behaviour and seems to imply that you can never redefine or override the root logger. Googling shows other people coming to the realisation, with one or two cryptic reports that others have "got around it". Is this right?

Instead of using the root logger, you call methods of your class instead of functions from the logging module (which are aliased to method calls of the root Logger instance). You could also redefine the root Logger instance, but that's unnecessary.

Python code:
log = MyLogger()
log.setLevel(logging.INFO)
log.info('dickbutt')

FoiledAgain
May 6, 2007

Maybe it's just really early, but I don't understand why this happens:

code:
>>a,b = False,False
>>flags = [a,b]
>>b = True
>>any(flags)
False
>>any([a,b])
True
Am I not really putting b into flags here?

Jewel
May 2, 2009

FoiledAgain posted:

Maybe it's just really early, but I don't understand why this happens:

code:
>>a,b = False,False
>>flags = [a,b]
>>b = True
>>any(flags)
False
>>any([a,b])
True
Am I not really putting b into flags here?

Python code:
>>> a, b = False, False
>>> flags = [a, b]
>>> b = True
>>> [v for v in flags]
[False, False]

>>> class someObject:
	value = False

>>> a, b = someObject(), someObject()
>>> flags = [a, b]
>>> b.value = True
>>> [v.value for v in flags]
[False, True]
Basically everything in python is a reference to some kind of internal object. When you assign a value (such as storing it in an array) it will do one of two things:

If it's a simple value (int, bool, float, string) it will copy "by value", so it a = b (when both bool) won't mean that a refers to the same object as b, so changing b will not change a.

If it's an object of some kind, then it actually copies "by reference", so they both refer to the same object, in which a = b means that changing b will actually change a.

Imagine "by reference" as the variable holding a kind of object ID that python uses internally to route to a specific instance, so a = b just makes them both have the same "id".

Jewel fucked around with this message at 11:03 on Jan 22, 2015

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
This is the kind of thing where pythontutor can really help you understand it in a more visual way:

http://www.pythontutor.com/visualiz...B%5D&curInstr=0

Then try doing stuff like

code:
list_flags = [flags, 0, flags]
flags[0] = 'aaaa'
print(list_flags)
to see what happens.

Jewel
May 2, 2009

Symbolic Butt posted:

This is the kind of thing where pythontutor can really help you understand it in a more visual way:

http://www.pythontutor.com/visualiz...B%5D&curInstr=0

Then try doing stuff like

code:
list_flags = [flags, 0, flags]
flags[0] = 'aaaa'
print(list_flags)
to see what happens.

Oh that's a realllly nice site, thanks for that. It helps to look at mine too, see how they "point" to the new object http://www.pythontutor.com/visualiz...B%5D&curInstr=3

QuarkJets
Sep 8, 2008

FoiledAgain posted:

Maybe it's just really early, but I don't understand why this happens:

code:
>>a,b = False,False
>>flags = [a,b]
>>b = True
>>any(flags)
False
>>any([a,b])
True
Am I not really putting b into flags here?

The list does not hold a variable, it holds values. You put False, False into flags.

nonathlon
Jul 9, 2004
And yet, somehow, now it's my fault ...

QuarkJets posted:

Instead of using the root logger, you call methods of your class instead of functions from the logging module (which are aliased to method calls of the root Logger instance). You could also redefine the root Logger instance, but that's unnecessary.

Python code:
log = MyLogger()
log.setLevel(logging.INFO)
log.info('dickbutt')

That's true - i may be overthinking this thing. 90% of the time, I'll just be using a single logger so why not do it this way. But it's very strange that you can't change the root logger, so if you use subloggers, they will be behaving differently to the root.

(The original problem I was trying to solve is that formats are specific to handlers not levels, so a DEBUG message will look the same as an informational one. Irritating more than essential.)

SYSV Fanfic
Sep 9, 2003

by Pragmatica
I've been doing more development. I've become very tired of figuring out layouts for tkinter programs. Which GUI designer is the best?

Dominoes
Sep 20, 2007

SYSV Fanfic posted:

I've been doing more development. I've become very tired of figuring out layouts for tkinter programs. Which GUI designer is the best?

Qt Designer.

SYSV Fanfic
Sep 9, 2003

by Pragmatica

Dominoes posted:

Qt Designer.

Prefer to keep working with tkinter at the moment.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
You're stuck. tkinter is bad.

SYSV Fanfic
Sep 9, 2003

by Pragmatica

Suspicious Dish posted:

You're stuck. tkinter is bad.

Yeah, next application or refactor I guess I will learn QT.

QuarkJets
Sep 8, 2008

SYSV Fanfic posted:

Yeah, next application or refactor I guess I will learn QT.

It's similar to Tkinter in a lot of ways

SYSV Fanfic
Sep 9, 2003

by Pragmatica
Which leads to: I had an idea for a program other people might contribute to and even possibly use. Are there any non performance drawbacks to writing something that could cause headaches as the project grows?

Being unable to prevent access to class internals doesn't seem like a problem if all code is reviewed for it before a commit.

accipter
Sep 12, 2003

SYSV Fanfic posted:

Which leads to: I had an idea for a program other people might contribute to and even possibly use. Are there any non performance drawbacks to writing something that could cause headaches as the project grows?

Being unable to prevent access to class internals doesn't seem like a problem if all code is reviewed for it before a commit.

I don't fully understand what you are asking in the bolded statement.

SYSV Fanfic
Sep 9, 2003

by Pragmatica

accipter posted:

I don't fully understand what you are asking in the bolded statement.

Problems apart from performance. How well does python scale as the complexity ramps up?

QuarkJets
Sep 8, 2008

SYSV Fanfic posted:

Problems apart from performance. How well does python scale as the complexity ramps up?

Pretty well, there are some big Python projects on github. Look at this sweet project with 92 contributors:

"Luigi is a Python module that helps you build complex pipelines of batch jobs. It handles dependency resolution, workflow management, visualization etc. It also comes with Hadoop support built in." They mention further down that Luigi is used at Spotify, and this github was apparently started by Spotify employees.
https://github.com/spotify/luigi

If you're working on a project that becomes complex, you might consider using a nice IDE like PyCharm to help you manage things.

onionradish
Jul 6, 2006

That's spicy.
Since QT came up recently, can anyone give a quick "for dummies" summary of the QT 4/5 versions and licenses? When I looked into it a long while back, I got confused about all the Nokia/commercial/GPL stuff. I've avoided doing anything with QT since out of uncertainty about how I could actually use and/or release something using it. Tkinter, while generally terrible and ugly, I at least know is safe to use.

Dominoes
Sep 20, 2007

onionradish posted:

Since QT came up recently, can anyone give a quick "for dummies" summary of the QT 4/5 versions and licenses? When I looked into it a long while back, I got confused about all the Nokia/commercial/GPL stuff. I've avoided doing anything with QT since out of uncertainty about how I could actually use and/or release something using it. Tkinter, while generally terrible and ugly, I at least know is safe to use.
PySide is Qt 4 only, and uses the LGPL (ie it can be used for proprietary software?). PyQt is Qt 4 or Qt 5, and the free version is licensed under GPL (ie software that uses yours must be open sorce), or a commercial license you pay for.

QuarkJets
Sep 8, 2008

Dominoes posted:

PyQt is Qt 4 or Qt 5, and the free version is licensed under GPL (ie software that uses yours must be open sorce), or a commercial license you pay for.

According to a cursory google search (I am not a lawyer), it's actually unclear whether a work that uses GPL-licensed software must be open source. The GPL refers to derivative work, which is poorly defined. Is a derivative work one in which you modify the GPL-licensed source code as part of your own project's development? Is a derivative work one in which you merely link to a GPL-licensed library? The Free Software Foundation claims that both of these are derivative works, but I and many others would disagree with the second one. Legally, I think it's an open question. However, everyone agrees that under the terms of the GPL your work doesn't have to be publicly available, it just needs to be open source. I think that this is an important distinction to make.

By contrast, the LGPL is basically the GPL but explicitly allows propriety software to use or modify your open source work. So when in doubt, you should probably use LGPL (or BSD or any of a hundred other "non-copyleft" software licenses) libraries.

Here's an article that brings up the derivative work question
http://www.linuxjournal.com/article/6366

And here's a relevant question from GNU's Q&A

quote:

You have a GPL'ed program that I'd like to link with my code to build a proprietary program. Does the fact that I link with your program mean I have to GPL my program? (#LinkingWithGPL)
Not exactly. It means you must release your program under a license compatible with the GPL (more precisely, compatible with one or more GPL versions accepted by all the rest of the code in the combination that you link). The combination itself is then available under those GPL versions.

This is how PySide, which uses the GPL-licensed Qt, can be released under the less-restrictive LGPL. The LGPL explicitly allows proprietary software to be created from open source software; the open source software must remain open source, but the software linking to the open source libraries can be closed source.

Basically, if you want to be create something without ever releasing the source code for it, don't use GPL-licensed software. However, the GPL is permissive about selling software, so if you don't mind handing over the source code to whoever buys a copy then don't worry about the license.

Also, nothing in the GPL requires that your software be publicly available. That's another important fact that I feel should be mentioned.

e: tl;dr software licensing is a confusing mess of legal terms, if you want to avoid potential legal hurdles then don't use GPL-licensed libraries in your closed source project. PySide is LGPL, so it would be safe to use

QuarkJets fucked around with this message at 21:39 on Jan 24, 2015

Cingulate
Oct 23, 2012

by Fluffdaddy
I'm using Anaconda for my Python distribution. To use the Intel MKL on Python, I either have to by Anaconda's optimizer package thing, or compile Numpy manually, correct? And the latter option is probably highly dispreferred as I'll have a good chance messing up Anaconda's infrastructure?

BigRedDot
Mar 6, 2008

Cingulate posted:

I'm using Anaconda for my Python distribution. To use the Intel MKL on Python, I either have to by Anaconda's optimizer package thing, or compile Numpy manually, correct? And the latter option is probably highly dispreferred as I'll have a good chance messing up Anaconda's infrastructure?
Well, you can create isolated environments with conda so there is really no chance of mucking things up:
code:
conda create -n mytestbed python=3.4
Now you can install whatever you please into the "mytestbed" environment and it won't interfere with anything else at all.

However, MKL is a commercial library originally sold by Intel, it's not part of "stock" NumPy. We are licensed to re-distribute MKL (and we do, through the add-on package we sell). If you want to use MKL "by hand" you definitely can, but you'd have to not just compile NumPy yourself, but also purchase MKL directly from Intel, and then configure NumPy to use it (the default build settings use an OSS linear algebra library).

Edit: though maybe you are asking because you already own an MKL license and want to use it. If so, it would make perfect sense to want to compile your own. Let me know if you have any specific questions, I haven't built NumPy myself in a while but I'm sure I could ping someone who does. :)

BigRedDot fucked around with this message at 18:47 on Jan 27, 2015

Cingulate
Oct 23, 2012

by Fluffdaddy
Yes, I already have the MKL and actually just compiled R to make use of it (... instead of going the comfortable route and downloading Revolution Analytics' R distribution).
I've also set up a few conda envs (thanks to this thread) - though may I ask in this context how I can remove an entire environment at once over the CLI?

I'm just wondering if a mostly computer-illiterate person such as I should even bother trying to get MKL and an Anaconda Python to play along nicely by hand (e.g. by manually compiling Numpy), or if I should just go for my credit card.

I understand correctly you're working for continuum.io?

Cingulate fucked around with this message at 19:51 on Jan 27, 2015

Adbot
ADBOT LOVES YOU

pmchem
Jan 22, 2010


Cingulate posted:

I understand correctly you're working for continuum.io?

I was noticing that too, it's pretty nice to have a guy from there in this thread if true. I use anaconda regularly for work. Spyder owns and it's nice to have all the modules I need in one stack.

  • Locked thread