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

Cukel posted:

Unless there's a way to run the object database next to an SQL database in Django... and even that seems like a lot of effort.

Yeah, I'm suggesting to use more than one database. A key/value store sounds like exactly what you want to do.

duck monster posted:

You can actually do some pretty funky things with XML blobs in some of the more recent mysql/pgsql/etc databases, like include Xpath terms in search queries and the like, letting you do low-rent schema-less stuff, although I still think NoSQL/schemaless stuff is the devil

If he wants to make a schema, he surely could just make a table for sessions.

Adbot
ADBOT LOVES YOU

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES

Bazanga posted:

Nice. That works wonderfully for my purposes, but is the subprocess module generally the best thing to use when interacting with system commands? For instance, the point of the script is to parse configuration files and generate arguments for openssl commands. Basically, it's a menu-driven OpenSSL frontend that I'm going to use to generate self-signed certificates in large quantities for testing systems. Am I pretty much stuck with using the subprocess module for more custom system commands? Hope that makes sense.

Yes, and instead of using os.cwd() as suggested, I suggest using subproc. I recently had an issue with this sort of crap recently, and have recently settled on doing something like this:


import subprocess as subp
base_dir = subp.check_output("pwd").splitlines()[0]


Where there splitlines()[0] is much more of a convention for me.



import subprocess as subp
base_dir = subp.check_output("pwd")


Will give you:
'/path/to/file\n'

Whereas splitlines will split the output (in this case getting rid of any \n you get back), and then I just ask for the 0th indicie of the array.

I suppose, upon writing this post, it would be cleaner to just do this:


import subprocess as subp
base_dir = subp.check_output("pwd")[:-2]


Which will, in this case, return the same thing. I guess I just like the other version because (a) I don't have to worry about efficiency and (b) I can read that line in the code weeks later and get it, whereas I could see myself scratching my head over [:-2].

OnceIWasAnOstrich
Jul 22, 2006

JetsGuy posted:

Which will, in this case, return the same thing. I guess I just like the other version because (a) I don't have to worry about efficiency and (b) I can read that line in the code weeks later and get it, whereas I could see myself scratching my head over [:-2].

'\n' is only one character, so [:-2] would remove the last character before the linebreak. Additionally it would be simpler just to use subp.check_output("pwd").strip().

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES

OnceIWasAnOstrich posted:

'\n' is only one character, so [:-2] would remove the last character before the linebreak. Additionally it would be simpler just to use subp.check_output("pwd").strip().

:doh: good catch!

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
code:
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> L = [5, 6, 7]
>>> [x ** 2 for x in L]
[25, 36, 49]
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> for x in L:
...     x ** 2
...
25
36
49
>>> x
7
>>> x = [0]
>>> [x[0] ** 2 for x[0] in L]
[25, 36, 49]
>>> x
[7]
>>> [x ** 2 for x in L]
[25, 36, 49]
>>> x
[7]
>>>
I can't make sense of this behaviour. If you use a for loop, then the iteration dummy variable is visible after the loop and has its value from the last loop iteration. But if you use a list comprehension, then it is not visible (or is unchanged, if it existed). Except that for some expressions it will modify dummy variables that share a name used outside of the list comprehension? This seems rather inconsistent.

ynohtna
Feb 16, 2007

backwoods compatible
Illegal Hen
List comprehensions are a shorthand for lambda functions and thus create a new scope in which their variables exist.

Hammerite
Mar 9, 2007

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

ynohtna posted:

List comprehensions are a shorthand for lambda functions and thus create a new scope in which their variables exist.

Oh OK, so it's like I wrote a loop inside a function (or I'm running a function inside a loop) that uses the variable x or refers to x[0], and in the second case Python can't make sense of x[0] using the function's set of names so looks up into the global scope and finds x there.

I am just going to share this because I found it funny:

code:
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> [x + y for x in range(y) for y in range(10) if (x + y) % 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> [x + y for y in range(10) for x in range(y) if (x + y) % 2]
[1, 3, 3, 5, 5, 7, 5, 7, 9, 7, 9, 11, 7, 9, 11, 13, 9, 11, 13, 15, 9, 11, 13, 15
, 17]
>>>
I couldn't work out what was happening until I realised that it expects the for clauses to be in a strange order.

ynohtna
Feb 16, 2007

backwoods compatible
Illegal Hen

Hammerite posted:

Oh OK, so it's like I wrote a loop inside a function (or I'm running a function inside a loop) that uses the variable x or refers to x[0], and in the second case Python can't make sense of x[0] using the function's set of names so looks up into the global scope and finds x there.

Yeah, that's my understanding of it although I'm sure there are probably some subtleties and gotchas to it in complex cases.

Cat Plus Plus
Apr 8, 2011

:frogc00l:

Hammerite posted:

I couldn't work out what was happening until I realised that it expects the for clauses to be in a strange order.

It's actually the same order as always, if you look at it this way:

code:
# for y in range(10) for x in range(y)
for y in range(10):
    for x in range(y):
        ...

Hammerite
Mar 9, 2007

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

PiotrLegnica posted:

It's actually the same order as always, if you look at it this way:

code:
# for y in range(10) for x in range(y)
for y in range(10):
    for x in range(y):
        ...

No, it's not the same order, because if it was in that order then the "x + y" would have to go at the end of the list comprehension expression. What you posted there represents something like this:

code:
# for y in range(10) for x in range(y)
for y in range(10):
    for x in range(y):
        do a thing with x and y
That would only be in the same order if the list comprehension looked like this:

[for y in range(10) for x in range(y) do a thing with x and y]

But it doesn't, the "do a thing" appears at the start and not at the end.

The reason the order is strange to me is that the expression "x + y" is maximally general, with 2 indeterminates. It's followed by the range of y-values, which has no indeterminates, and then by the range of x-values, which is in between the two in terms of generality (it depends on one indeterminate, y). So the order (of expression clauses by number of indeterminates) goes 2, 0, 1. That's a bizarre order.

It's only a nitpick, but it is a counter-intuitive order for the clauses to have to appear in.

Jewel
May 2, 2009

Hammerite posted:

No, it's not the same order, because if it was in that order then the "x + y" would have to go at the end of the list comprehension expression. What you posted there represents something like this:

code:
# for y in range(10) for x in range(y)
for y in range(10):
    for x in range(y):
        do a thing with x and y
That would only be in the same order if the list comprehension looked like this:

[for y in range(10) for x in range(y) do a thing with x and y]

But it doesn't, the "do a thing" appears at the start and not at the end.

The reason the order is strange to me is that the expression "x + y" is maximally general, with 2 indeterminates. It's followed by the range of y-values, which has no indeterminates, and then by the range of x-values, which is in between the two in terms of generality (it depends on one indeterminate, y). So the order (of expression clauses by number of indeterminates) goes 2, 0, 1. That's a bizarre order.

It's only a nitpick, but it is a counter-intuitive order for the clauses to have to appear in.

Naw, the order isn't strange because, I don't think? Think of it this way:

code:
array = [x + y for y in range(10) for x in range(y) if (x + y) % 2]
Is equivalent to

code:
array = []

for y in range(10):
    for x in range(y):
        if (x+y) % 2:
            array.append(x+y)
It's saying "put 'x+y' in the array FOR this statement IF this is true"

Cat Plus Plus
Apr 8, 2011

:frogc00l:

Hammerite posted:

No, it's not the same order, because if it was in that order then the "x + y" would have to go at the end of the list comprehension expression. What you posted there represents something like this:

I only referred to the order of for components in the comprehensions. That expression goes first is just a common convention, going all the way back to math notation.

Hammerite
Mar 9, 2007

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

Jewel posted:

Naw, the order isn't strange because, I don't think? Think of it this way:

code:
array = [x + y for y in range(10) for x in range(y) if (x + y) % 2]
Is equivalent to

code:
array = []

for y in range(10):
    for x in range(y):
        if (x+y) % 2:
            array.append(x+y)

If you make a point of writing it this way then that to me represents more an argument that the "x + y" should appear at the end of the expression, after the if clause.

quote:

It's saying "put 'x+y' in the array FOR this statement IF this is true"

Whereas if you say it this way, then the ordering of the for clauses should still to me be in decreasing order in number of indeterminates (because the maximally general clause, "x + y", is furthest left). The if statement belongs after the for clause to which it applies because it's a further (optional) restriction on the set of values that make it to the "x + y" expression.

To argue by analogy: we write



we don't write

Hammerite
Mar 9, 2007

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

PiotrLegnica posted:

I only referred to the order of for components in the comprehensions. That expression goes first is just a common convention, going all the way back to math notation.

Sure, but given that the expression comes first, the nested for clauses should not appear in the same order as the header lines would in the corresponding explicit nested for loop. Rather, they should sensibly appear in the reverse order, for reasons I have expressed.

Jewel
May 2, 2009

Hammerite posted:

If you make a point of writing it this way then that to me represents more an argument that the "x + y" should appear at the end of the expression, after the if clause.


Whereas if you say it this way, then the ordering of the for clauses should still to me be in decreasing order in number of indeterminates (because the maximally general clause, "x + y", is furthest left). The if statement belongs after the for clause to which it applies because it's a further (optional) restriction on the set of values that make it to the "x + y" expression.

To argue by analogy: we write



we don't write



Yes but we also don't write x=y; y=5;

What I said was "append X for every iteration of Y, if Z condition is true"

X being (x+y)
Y being
code:
for y in range(10):
    for x in range(y):
Z being
code:
if (x+y) % 2

Jewel fucked around with this message at 12:31 on Jun 22, 2012

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
List comprehensions do not exist in a new scope.

Python code:
>>> a = [1, 2, 3]
>>> [n*2 for n in a]
[2, 4, 6]
>>> n
3

Civil Twilight
Apr 2, 2011

It's a python2/3 difference.

Guido van Rossum posted:

We also made another change in Python 3, to improve equivalence between list comprehensions and generator expressions. In Python 2, the list comprehension "leaks" the loop control variable into the surrounding scope:
Python code:
x = 'before'
a = [x for x in 1, 2, 3]
print x # this prints '3', not 'before'
This was an artifact of the original implementation of list comprehensions; it was one of Python's "dirty little secrets" for years. It started out as an intentional compromise to make list comprehensions blindingly fast, and while it was not a common pitfall for beginners, it definitely stung people occasionally. For generator expressions we could not do this. Generator expressions are implemented using generators, whose execution requires a separate execution frame. Thus, generator expressions (especially if they iterate over a short sequence) were less efficient than list comprehensions.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Aha, thanks for that.

Sephiroth_IRA
Mar 31, 2010
Ok, Idiot here. I've downloaded python 2.7 and the newest version of Cream (Apparently a simpler version of VIM) and I'm loving lost. How do I actually compile my source code?

edit:
Guess I shouldn't have skipped exercise 0

quote:

If a programmer tells you to use vim or emacs, tell them, "No." These editors are for when you are a better programmer. All you need right now is an editor that lets you put text into a file. We will use gedit because it is simple and the same on all computers. Professional programmers use gedit so it's good enough for you starting out.

I'll try it his way when I get home from work.

Sephiroth_IRA fucked around with this message at 17:03 on Jun 22, 2012

etcetera08
Sep 11, 2008

Orange_Lazarus posted:

Ok, Idiot here. I've downloaded python 2.7 and the newest version of Cream (Apparently a simpler version of VIM) and I'm loving lost. How do I actually compile my source code?

edit:
Guess I shouldn't have skipped exercise 0


I'll try it his way when I get home from work.

You don't compile Python code. You can execute a file with python my_program.py

edit: Realized you may be on Windows / more of a newbie than I thought, in which case you should probably try out IDLE until you get your feet underneath you.

etcetera08 fucked around with this message at 18:46 on Jun 22, 2012

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES

quote:

Professional programmers use gedit so it's good enough for you starting out.

:laugh:

Yes, all professional programmers use the same editor, and it's not at all an argument between coders as to what's the "best" editor. :v: Ironically, the rest of that instruction is completely correct, vim and emacs are for when you are more comfortable coding. I just find it funny that they then say "everyone uses gedit".

On a serious note, I completely agree, use IDLE until you get used to it. It will be *worlds* better for your first foray into coding.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
He didn't say all. He said "professional programmers use gedit". Yes, there are professional programmers that use gedit.

It's 2012. The editor war died in the 1990s after people stopped caring.

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES
I have a stupid question regading user input for the creation of output files. When allowing users to define the output file, I may do something like:

code:
tmp_outfile = "woo.txt"
while writefile == False:
     if os.path.exists(tmp_outfile) == False:
          self.outfile = tmp_outfile
          writefile = True

     if os.path.exists(tmp_outfile) == True:
          print "This will write file: "+str(tmp_outfile)
          rsp = raw_input("You have run this for this data.  Overwrite? (yes/no):  ")
          if rsp.lower() == "yes":
               print "Ok. Overwriting...\n"
               self.outfile = tmp_outfile
               writefile = True
          elif rsp.lower() == "no":
               sys.exit("Ok, killing process.")
          else:
               print "Please provide a yes or no response!\n"
My question is: is this a security risk? Could someone enter something like "sudo rm -r *.* as a file name and gently caress the system? I tried testing this in a bit of a controlled environment (e.g. *.txt), and it seemed to just make a stupidly named file. However, I'm sure there's much more creative ways to gently caress things up here, and I was just curious if that's a opening and if it is, how would I better write that to stop it?

(ps - yes, I do give the option to use the non-default file name, just giving an example here)

Sephiroth_IRA
Mar 31, 2010

etcetera08 posted:

You don't compile Python code. You can execute a file with python my_program.py

edit: Realized you may be on Windows / more of a newbie than I thought, in which case you should probably try out IDLE until you get your feet underneath you.

If someone is really committed to learning Python (and computer programming/science in general) should they get a spare computer setup (or dual boot) linux? Or is it ok to use Windows?

tef
May 30, 2004

-> some l-system crap ->
Python is fine on windows. Some third party libraries may be less than cooperative.

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES

Orange_Lazarus posted:

If someone is really committed to learning Python (and computer programming/science in general) should they get a spare computer setup (or dual boot) linux? Or is it ok to use Windows?

I found no problems when I was using my old windows machine and Python. I was using 2.6/2.7 at the time, and the following packages that don't come built-in.

NumPy
SciPy
matplotlib

I don't think I was using PyFits at that point, but I doubt it'd be an issue.

etcetera08
Sep 11, 2008

Orange_Lazarus posted:

If someone is really committed to learning Python (and computer programming/science in general) should they get a spare computer setup (or dual boot) linux? Or is it ok to use Windows?

No, you'll be fine. I didn't mean to imply that using Windows == being more of a newbie than I thought, but that they're two separate scenarios in which using IDLE to begin is a good idea.

spankweasel
Jan 4, 2006

JetsGuy posted:

I have a stupid question regading user input for the creation of output files. When allowing users to define the output file, I may do something like:

code:
tmp_outfile = "woo.txt"
while writefile == False:
     if os.path.exists(tmp_outfile) == False:
          self.outfile = tmp_outfile
          writefile = True

     if os.path.exists(tmp_outfile) == True:
          print "This will write file: "+str(tmp_outfile)
          rsp = raw_input("You have run this for this data.  Overwrite? (yes/no):  ")
          if rsp.lower() == "yes":
               print "Ok. Overwriting...\n"
               self.outfile = tmp_outfile
               writefile = True
          elif rsp.lower() == "no":
               sys.exit("Ok, killing process.")
          else:
               print "Please provide a yes or no response!\n"
My question is: is this a security risk? Could someone enter something like "sudo rm -r *.* as a file name and gently caress the system? I tried testing this in a bit of a controlled environment (e.g. *.txt), and it seemed to just make a stupidly named file. However, I'm sure there's much more creative ways to gently caress things up here, and I was just curious if that's a opening and if it is, how would I better write that to stop it?

(ps - yes, I do give the option to use the non-default file name, just giving an example here)

The thing is that you're not executing arbitrary code (via subprocess and friends). You're simply opening a file on the filesystem. This typically has far fewer security issues but you *might* want to double check things base directory permissions.

code:
root, filename = os.path.split(user_provided_filename)
if not os.access(root, os.W_OK):
    raise DerpError("user can not write to:  %s" % root)
and things like this.

Note that using os.access does introduce a very very small chance for errors because of the timing between checking for permission and actually writing the file.

Rohaq
Aug 11, 2006

spankweasel posted:

The thing is that you're not executing arbitrary code (via subprocess and friends). You're simply opening a file on the filesystem. This typically has far fewer security issues but you *might* want to double check things base directory permissions.

code:
root, filename = os.path.split(user_provided_filename)
if not os.access(root, os.W_OK):
    raise DerpError("user can not write to:  %s" % root)
and things like this.

Note that using os.access does introduce a very very small chance for errors because of the timing between checking for permission and actually writing the file.
If you were checking if a file is writeable, wouldn't it be more Pythonic, and more importantly, more readable and avoid a race condition, to do the following?:
code:
try:
    fh = open(filepath, 'w')
except IOError:
    sys.exit('Can't open file ' + filepath + ' for writing.')
This works for me, at least.

Rohaq fucked around with this message at 22:54 on Jun 22, 2012

geonetix
Mar 6, 2011


It's a popular idiom in Python to try first and ask forgiveness later. It's usually faster to skip all the permission-asking too. Just be careful not to overuse it and put yourself into impossible situations or create vulnerabilities by not doing proper sanitization.

FoiledAgain
May 6, 2007

Rohaq posted:

If you were checking if a file is writeable, wouldn't it be more Pythonic, and more importantly, more readable and less likely to result in a race condition, to do the following?:
code:
try:
    fh = open(filepath, 'w')
except:
    sys.exit('Can't open file ' + filepath + ' for writing.')
This works for me, at least.

I'm not a super experienced python programmer, but as far as I understand it, it's dangerous to do a blanket except because then you might exit on errors which have nothing to do with trying to open a file; errors you might like to know about. For instance, if filepath is an integer, you get TypeError, which means that something else probably went way wrong earlier, and you might like to know that. So it would be better to set that to except IOError

edit: though I guess that example is irrelevant here because it prints out filepath for you to see, and you'd hit another error trying to concatenate. I hope my underlying point wasn't lost.

FoiledAgain fucked around with this message at 22:44 on Jun 22, 2012

Rohaq
Aug 11, 2006

FoiledAgain posted:

I'm not a super experienced python programmer, but as far as I understand it, it's dangerous to do a blanket except because then you might exit on errors which have nothing to do with trying to open a file; errors you might like to know about. For instance, if filepath is an integer, you get TypeError, which means that something else probably went way wrong earlier, and you might like to know that. So it would be better to set that to except IOError
That's true, I admit I was being a bit lazy and didn't look up the specific exception error to put into my quick example. I'll amend it.

It's still a much easier way of doing what you're trying to do though. Pre-checks are all well and good to avoid issues, but there's always the risk of a race condition; the precheck passes, but then something changes in your environment before you actually start writing.

The above checks that the file is writeable whilst opening the filehandle for writing, leaving you with a writeable filehandle as a result of the check, and erroring out if it does not, rather than checking if a file is writeable and then simply assuming that the same condition is true when you attempt to open the filehandle for writing.

No Safe Word
Feb 26, 2005

geonetix posted:

It's a popular idiom in Python to try first and ask forgiveness later. It's usually faster to skip all the permission-asking too. Just be careful not to overuse it and put yourself into impossible situations or create vulnerabilities by not doing proper sanitization.

For the uninitiated, the acronym you may sometimes see for this (since programmers love acronyms) is EAFP - Easier to Ask Foregiveness than Permission

spankweasel
Jan 4, 2006

I do all of my python at the system level. No web stacks for me. I absolutely hate seeing try/except used as a control structure. There are functions designed for asking permission and it leads to better code, especially in a team of 20 people, 15 of which hadn't seen python before 2 years ago.

Legibility of code counts for more for me because people come and go. The code has to live for awhile and if have anything to say about, I'll try to make it as clean and well organized as I can so the other folks on my team can maintain the code after I'm gone.

Hammerite
Mar 9, 2007

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

spankweasel posted:

I do all of my python at the system level. No web stacks for me. I absolutely hate seeing try/except used as a control structure. There are functions designed for asking permission and it leads to better code, especially in a team of 20 people, 15 of which hadn't seen python before 2 years ago.

Legibility of code counts for more for me because people come and go. The code has to live for awhile and if have anything to say about, I'll try to make it as clean and well organized as I can so the other folks on my team can maintain the code after I'm gone.

I can understand the sentiment but, speaking as someone who has only just started learning python, it seems like there is an established culture of "exceptions as tools of control flow". e.g. exceptions are how you know how an iteration is finished, etc.

And what would you say in reply to the point that if you "check, then do", something could happen in between the checking and the doing? In contrast if you wrap the "do" in a try then you are free of that worry and you handle the failure case just fine.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Outside of trivial cases like checking if a variable is None, trying to check if something will work before doing it mostly just results in duplicated error handling or race conditions.

spankweasel
Jan 4, 2006

You're not wrong. Checking before doing *can* introduce a race condition. It's not about that, however. In my code base, legibility counts for everything especially because people I work with do not know Python (and typically are the type of people who fight tooth and nail to not learn new things - which is a different issue altogether).

Checking before doing is a simpler way for them to be able to support the code indefinitely. My disdain of using try/except as a control structure stems from being in this environment for quite some time. I suspect that if/when I move on to something else, I'll drop my concern for this (and a few other things I'm pedantic about).

Opinion Haver
Apr 9, 2007

Orange_Lazarus posted:

If someone is really committed to learning Python (and computer programming/science in general) should they get a spare computer setup (or dual boot) linux? Or is it ok to use Windows?

I don't know how good Python is on Windows but I do know that you can run a Debian virtual machine on any computer that's not powered by a potato battery.

Opinion Haver fucked around with this message at 17:15 on Jun 23, 2012

Suspicious Dish
Sep 24, 2011

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

yaoi prophet posted:

I don't know how good Python is but I do know that you can run a Debian virtual machine on any computer that's not powered by a potato battery.

I'm quite sure someone ran Debian Potato on an actual potato at some point.

Adbot
ADBOT LOVES YOU

xtal
Jan 9, 2011

by Fluffdaddy

Orange_Lazarus posted:

If someone is really committed to learning Python (and computer programming/science in general) should they get a spare computer setup (or dual boot) linux? Or is it ok to use Windows?

I've used Python for years on Windows without issue. The problems I've run into are primarily with extras like virtualenv and git (which are wholly recommended, but expect to be a second-class citizen.)

It's advisable to code on Linux or a Mac, but it's not impossible on Windows.

  • Locked thread