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
Modern Pragmatist
Aug 20, 2008

Drunk Badger posted:

Things I don't know if I really need because I'm new to this and have no formal training?

You don't need them at all. In fact, pep8 explicitly says to not use them.

Adbot
ADBOT LOVES YOU

Drunk Badger
Aug 27, 2012

Trained Drinking Badger
A Faithful Companion

Grimey Drawer
Good to know, thanks

good jovi
Dec 11, 2000

'm pro-dickgirl, and I VOTE!

pep8 being the official Python style guide: http://www.python.org/dev/peps/pep-0008/

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES
I need to get better at remembering PEP8.

That code I posted above is a pretty fair approximation of how I stylistically code, for whatever that's worth.

vikingstrike
Sep 23, 2007

whats happening, captain

JetsGuy posted:

I need to get better at remembering PEP8.

That code I posted above is a pretty fair approximation of how I stylistically code, for whatever that's worth.

I code similarly. I think it's just carry over from Matlab warping my brain.

Emacs Headroom
Aug 2, 2003
There are packages to turn on PEP8 warning for Emacs and Vim, and probably most other editors. It does help a bit to have your editor nagging you not to code like a mook.

Thermopyle
Jul 1, 2003

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

PyCharm does PEP8 evaluations as well.

Speaking of PyCharm, I bought it when they were doing that $25 sale a couple months ago. I've been using it exclusively since then. My review: it's pretty great! Definitely my favorite Python IDE.

tef
May 30, 2004

-> some l-system crap ->

Drunk Badger posted:

Things I don't know if I really need because I'm new to this and have no formal training?

Python uses the newline as a terminator, so you only need to use semi-colons if you're banging poo poo into one line (don't do this)

They're harmless, so don't worry about it too much. If anything they just demonstrate you're new to python (and that's ok!)

evilentity
Jun 25, 2010

Drunk Badger posted:

Here's an example from a routing simulator I'm building.

What I want it to do is give me a new set of numbers on each cycle of the while loop. Running that just produces the same random numbers while the program is run.


It seems to be running the function for each element in 'noderoute = [...', once it gets to that line of code, as I can put a print function and it will display 6 lines of text before it starts putting out the numbers. I know I can just do a bunch of if loops, but I'm wondering if there's a shorter way to do what I want.

As was said above, you get same values each time because they are evaluated when you add them to the list not in the loop.
This does what you want:

Python code:
import random

class Node:
    def __init__(self, r):
        self.routes = r
        self.hopcount = 0

def nexthop(routes):
    return routes[random.randrange(len(routes))]

node1 = Node([2])
node2 = Node([1,3,4,5])
node3 = Node([2,4,5])
node4 = Node([2,3,5])
node5 = Node([2,3,4,6])
node6 = Node([5])

noderoutes = [node1.routes, node2.routes, node3.routes,
    	      node4.routes, node5.routes, node6.routes]

while True:
    for noderoute in noderoutes:
        print(nexthop(noderoute))
    print('end')
It will print random number each time.

You can also randomize initial nodes with something like that:
Python code:
maxCount = 10
noderoutes = []
for x in xrange(6):
    node = Node(sorted(random.sample(range(1, maxCount),
                random.randint(1, maxCount-1))))
    noderoutes.append(node)
With time you will purify.

evilentity fucked around with this message at 19:51 on Feb 14, 2013

Foiltha
Jun 12, 2008

JetsGuy posted:

I need to get better at remembering PEP8.

That code I posted above is a pretty fair approximation of how I stylistically code, for whatever that's worth.

I usually just run this before committing code and fix the flaws it points out: https://github.com/jcrocholl/pep8

Maybe it's time to hook up some Vim scripts do that while editing though.

Drunk Badger
Aug 27, 2012

Trained Drinking Badger
A Faithful Companion

Grimey Drawer

evilentity posted:

Amazing words

That looks like it will work, thanks!

For the most part Python is making sense, I'm taking a (unrelated) cryptography course that requires coding so I'm using that as a way to force myself into finally learning it. I'm at the point where I want to move from just writing code that doesn't produce errors or start computers on fire to writing more efficient error-resistant and fireproof code, so I figured there was a better way than giant for clusters to do what I wanted.

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES
Does anyone else have random issues with emacs deciding to indent too far, too little or whatever?

Sometimes I'll start a block like:

if whatever > this:
and emacs will decide to give it a two tab indent instead of a one tab indent

It seems completely random as to when it happens!

Another thing that really hacks me off is sometimes when I comment out a line of code and emacs randomly decides that it should be indenting that too.

Also, definitely using the pep8 package, but every instruction I've been looking at to integrate it into emacs is awfully written, so I guess I'll just use it in the terminal.

EDIT
Christ on a cracker, PEP8 likes to bitch about "mixing tabs with spaces" on lines where I'm continuing a previous one. I suppose the "acceptable" route is to go just spaces here?

JetsGuy fucked around with this message at 21:53 on Feb 14, 2013

BeefofAges
Jun 5, 2004

Cry 'Havoc!', and let slip the cows of war.

Configure your editor to output four spaces when you hit tab.

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES

BeefofAges posted:

Configure your editor to output four spaces when you hit tab.

EDIT:
:doh: confusing tabs with indention settings

Munkeymon
Aug 14, 2003

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



BeefofAges posted:

Configure your editor to output four spaces when you hit tab.

My only problem with using spaces like that is that a depressing number of editors can't be configured to delete back to a tab stop, even when they have an option to insert spaces when you hit tab. Having to remove a single keystroke with four just annoys the poo poo out of me (because I'm a big whiny baby, obviously, but that's not going to change).

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES
So I've tracked down why emacs decides to randomly indent commented lines of code. It happens when I comment out a block that follow a loop.

So for example:
code:
for i in range(0,10,1):
    print i

some
other
code
Will go to something like:
code:
for i in range(0,10,1):
    print i

    #some
#other
#code
It appears emacs is assuming the comment belongs to the loop above somehow.

Munkeymon posted:

My only problem with using spaces like that is that a depressing number of editors can't be configured to delete back to a tab stop, even when they have an option to insert spaces when you hit tab. Having to remove a single keystroke with four just annoys the poo poo out of me (because I'm a big whiny baby, obviously, but that's not going to change).

Maybe I'm misunderstanding, but my emacs seems to do "insert x space" fine, and once it understands what kind of code you're writing, it'll let you delete back to the last tab stop (instead of deletex4) if you want to get out of a nested loop or something.

(I use aquamacs emacs if that makes a difference)

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Munkeymon posted:

My only problem with using spaces like that is that a depressing number of editors can't be configured to delete back to a tab stop, even when they have an option to insert spaces when you hit tab. Having to remove a single keystroke with four just annoys the poo poo out of me (because I'm a big whiny baby, obviously, but that's not going to change).
The solution is to not use terrible editors. Anything that doesn't properly support spaces for indentation is almost certainly a toy anyway.

fritz
Jul 26, 2003

Sailor_Spoon posted:

pep8 being the official Python style guide: http://www.python.org/dev/peps/pep-0008/

I've never liked PEP8, there's some good stuff in there but also a lot of crap ("When writing English, Strunk and White apply.")

Emacs Headroom
Aug 2, 2003

fritz posted:

I've never liked PEP8, there's some good stuff in there but also a lot of crap ("When writing English, Strunk and White apply.")

Strunk and White being a rule is probably the best argument in favor of PEP8 possible.

FoiledAgain
May 6, 2007

Emacs Headroom posted:

Strunk and White being a rule is probably the best argument in favor of PEP8 possible.

Actually, S&W had no formal training in grammar. That book has an undeserved reputation, and those guys were hardly the masters of English that most people think they were.

Thermopyle
Jul 1, 2003

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

What really matters is that PEP8 helps consistency. I'd rather have consistently styled code than code that matches every programmers personal desires.

Emacs Headroom
Aug 2, 2003

Neither did Shakespeare. :colbert:

That book is genius (along with Orwell's essay "Politics and the English Language"), I don't care what anyone says.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
The notion of having an "official style guide" is awful. The idea that you're not free to adopt your own set of formatting conventions for your project, no matter that they're consistent and work well for you, because some busybodies decided to codify what they think everyone else's code should look like.

Thermopyle
Jul 1, 2003

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

Hammerite posted:

The notion of having an "official style guide" is awful. The idea that you're not free to adopt your own set of formatting conventions for your project, no matter that they're consistent and work well for you, because some busybodies decided to codify what they think everyone else's code should look like.

I agree if you're not doing open source work.

Hammerite
Mar 9, 2007

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

Thermopyle posted:

I agree if you're not doing open source work.

Why on Earth would that make a difference to anything?

I think if I were to have read PEP 8 and discovered that quite by coincidence my preferred formatting conventions matched its prescriptions to a tee, I should have chosen to alter key elements so that they no longer matched, purely out of principle.

FoiledAgain
May 6, 2007

Emacs Headroom posted:

Neither did Shakespeare. :colbert:

That book is genius (along with Orwell's essay "Politics and the English Language"), I don't care what anyone says.

Shakespeare wasn't offering grammatical advice. Elements of Style is full of mistakes you don't care about English grammar if you think that's a good book. But now I'm in angry linguist rant mode in the wrong thread. I promise to stop the derail now.

Emacs Headroom
Aug 2, 2003

FoiledAgain posted:

Elements of Style is [so] full of mistakes [that] you don't care about English grammar if you think that's a good book.

Yeah that's probably right.

edit: not trying to be snarky, legitimately agreeing

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Strunk and White is basically Poe's Law applied to prescriptive linguistics.

Gaukler
Oct 9, 2012


Hammerite posted:

Why on Earth would that make a difference to anything?

I think if I were to have read PEP 8 and discovered that quite by coincidence my preferred formatting conventions matched its prescriptions to a tee, I should have chosen to alter key elements so that they no longer matched, purely out of principle.

Lots of languages have them, both official and unofficial. Do you have something against a starting point for good code formatting? There's no one forcing PEP8 compliance on things you write; the interpreter won't throw it back at you. PEP8 just gives Python a default style guide to follow when contributing code rather than "whatever the other code is like, except where it's different".

tef
May 30, 2004

-> some l-system crap ->

Hammerite posted:

The notion of having an "official style guide" is awful. The idea that you're not free to adopt your own set of formatting conventions for your project, no matter that they're consistent and work well for you, because some busybodies decided to codify what they think everyone else's code should look like.

Use a language with braces if you want to have your snowflake whitespace formatting :q:

Suspicious Dish
Sep 24, 2011

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

Hammerite posted:

The notion of having an "official style guide" is awful. The idea that you're not free to adopt your own set of formatting conventions for your project, no matter that they're consistent and work well for you, because some busybodies decided to codify what they think everyone else's code should look like.

You're free to completely ignore PEP8 for whatever reasons you want. The code will still work.

BeefofAges
Jun 5, 2004

Cry 'Havoc!', and let slip the cows of war.

There is no "best style convention". An official style guide is useful because it makes everyone's code look the same, so that you can forget about style and just think about logic.

Munkeymon posted:

My only problem with using spaces like that is that a depressing number of editors can't be configured to delete back to a tab stop, even when they have an option to insert spaces when you hit tab. Having to remove a single keystroke with four just annoys the poo poo out of me (because I'm a big whiny baby, obviously, but that's not going to change).

Most editors support hitting shift-tab to delete a tab.

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.

Suspicious Dish posted:

You're free to completely ignore PEP8 for whatever reasons you want. The code will still work.

Yeah, I really don't see how having an optional yet official style guide for a language is anything but a good thing for a language's growth. New people get a baseline style to use for their coding, and adoption in Open Source projects make it easier for contributors to get involved.

If you start on a new language, either you use existing code as examples and guess proper style based on your own preconceptions, or you find a document that spells it out for you. I would've thought the latter is more appropriate.

Lysidas
Jul 26, 2002

John Diefenbaker is a madman who thinks he's John Diefenbaker.
Pillbug

Hammerite posted:

Why on Earth would that make a difference to anything?

I think if I were to have read PEP 8 and discovered that quite by coincidence my preferred formatting conventions matched its prescriptions to a tee, I should have chosen to alter key elements so that they no longer matched, purely out of principle.

What is wrong with you?

PEP 8 posted:

A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.

But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask!

Yes, this definitely means that you're not free to decide on your own style for your project :rolleyes:

PEP 8 is a guide. If you're new to programming and don't really have a coding style, or you're new to Python and are tempted to carry over style habits that don't really apply to Python's syntax, PEP 8 is a good place to start.

PEP 8 pretty much says says "do whatever you want; these are recommendations from people who write a lot of Python code".

Hammerite
Mar 9, 2007

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

Lysidas posted:

What is wrong with you?

A lot of the responses to what I posted (or comments that may have been partially prompted by what I wrote) have been along the lines of "look guy, you aren't obliged to follow the suggestions in PEP 8. They're a default for people to start out with". Or similar. If that's all it was then I wouldn't have a problem with it. But that's not all it is, because as soon as you endorse a default style you get people saying snarky things like

xtal posted:

Special cases aren't special enough to break the rules. :)

My problem isn't with anyone who really does just see it as a suggestion. My problem is that people think it's a set of rules and that it's wrong to "break" those rules (as opposed to them merely being guidelines that you can disregard if you like). If you're not one of those people then great.

Maybe my post was immature, but I guess I have a streak of bloody-mindedness that prompts me to resent being told I have to format my code in a certain way when I like another way better!

Innocent Bystander
May 8, 2007
Born in the LOLbarn.
Can someone explain to me the way that Python variables behave in closure like situations?

code:
def function():
    myLat = []
    a = 1
    myLat.append(lambda: someFunc(a))
    myLat.append(lamdda: someOtherFunc(a))
    a = 2
    return myLat
When this gets called, someFunc and someOtherFunc get called with a = 2, rather than a = 1, and I consider my understanding of when Python uses pointer-like variable and when it doesn't my weak suit. Anyone care to explain?

Hammerite
Mar 9, 2007

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

Innocent Bystander posted:

Can someone explain to me the way that Python variables behave in closure like situations?

code:
def function():
    myLat = []
    a = 1
    myLat.append(lambda: someFunc(a))
    myLat.append(lamdda: someOtherFunc(a))
    a = 2
    return myLat
When this gets called, someFunc and someOtherFunc get called with a = 2, rather than a = 1, and I consider my understanding of when Python uses pointer-like variable and when it doesn't my weak suit. Anyone care to explain?

It looks like the functions stored in myLat evaluate their return values when called, not when defined. Since the variable "a" referenced in each function is still needed, a reference to that variable sticks around, and of course it has the last value it was given, which is 2.

It looks like there is an accepted way to get Python to accept the value of "a" that was in place at the time the function was defined. You declare it as an argument with a default value. The default value is evaluated at function definition time. So your function would become

code:
def function():
    myLat = []
    a = 1
    myLat.append(lambda a = a: someFunc(a))
    myLat.append(lamdda a = a: someOtherFunc(a))
    a = 2
    return myLat
which has the same effect as

code:
def function():
    return [lambda a = 1: someFunc(a), lamdda a = 2: someOtherFunc(a)]

Suspicious Dish
Sep 24, 2011

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

Hammerite posted:

code:
def function():
    return [lambda a = 1: someFunc(a), lamdda a = 2: someOtherFunc(a)]

No, it's:

code:
def function():
    return [lambda a = 1: someFunc(a), lambda a = 1: someOtherFunc(a)]

tef
May 30, 2004

-> some l-system crap ->

Innocent Bystander posted:

Can someone explain to me the way that Python variables behave in closure like situations?

I hope so, but I may have gone into a little too much detail. Hopefully this is correct, but I could be confused too.

quote:

I consider my understanding of when Python uses pointer-like variable and when it doesn't my weak suit. Anyone care to explain?

Python always uses pointer like variables.

Essentially, python has names, and objects. Names store a value, which is the address of an object stored in memory. List and Dict objects can contain values, but these values are always the addresses of python objects in memory. Python doesn't have value types, it only has reference types. Unlike java, c# it has no primitives (and like ruby), just objects.

code:
x = 2 # the name x points to the object 2
y = (1,2) # y points to the tuple pointing to the objects 1, 2
z = (y,y) # z points to a tuple, both elements pointing to the same object y does

def foo(a): # 
    a = 4 # the name a now points to the object 4
    return a  # return the address of the 4 object.

g = 1
f = foo(g) # f points to the object 4, g still points to the object 1
When you call a function, the addresses of the arguments are copied and then passed to the function. Inside the function foo above, changing what a points to doesn't change what g points to—the value of g is still the address of the object 1. Python is call by value, but the values are always addresses of object, and this is often called 'call by object' to make it distinct.

Thing is, if python used primitives, instead of pointers and an object, the code above would look the same and act the same, but only because the objects we're using are immutable. Objects like Strings, numbers, tuples, and others in python are immutable—you cannot change them after you have created them. Lists, dicts, on the other hand, can be mutated to point to different objects after they are created. To demonstrate the difference between changing a name, and changing an object-

code:
def foo(a):
    a = [] # we change what address a points to
    a.append(1) # we change the object pointed to by a
    return a 

def bar(a):
    a.append(1) # we change the object pointed to by a
    return a

a = [1,2]
foo(a) # returns [1], a still points to [1,2]

bar(a) # mutates the list pointed to by a, and returns it. 
# a and the return value point to the same list, now containing pointers to 1,2,3
It's easy to think that immutable objects behave like values, and mutable ones behave like references, but in reality, everything is a reference underneath. The illusion of value semantics is the root cause of the python gotcha a = []*2 (which is really _=[]; a = [_,_], and confused for _1 = []; _2 = []; a = [_1, _2]).

To recap: python has names and objects. names store the addresses of objects in memory. calling a function copies the addresses passed to it, returning an address. some objects are mutable, some are immutable. changing what address a name stores doesn't change the objects underneath.


Now we understand names and objects, next is to understand how names are resolved in python. Python uses a series of nested environments, which store names and the objects they point to, a bit like a dictionary in python.

By default, names live in the top level environment, or the global scope. When you define a function, you create a new inner environment, a local scope for resolving names, that falls back to the outer environments when the name doesn't exist. When you use the same name inside and outside a function, python uses a few rules to decide if the name is going to be local to the function, or use the existing name outside, working back up to the top-level environment.

code:
x = 1 # the name x is in the global scope

def a(x): # function argument names are in a function's local scope. 
    x = 2 # changing what x points to here, doesn't change what the outer x points to
    return x

def b(): 
    return x + 1 # x hasn't been bound, so this x is looked up outside the function

def c(): 
    global x # we explicitly say we want the outer x
    x = 2 # this means the x in the outer enviroment
    return x

a(x)
# returns 2, x is still pointing to 1
b()
# returns 2, x is still pointing to 1
c()
# returns 2, x points to the same '2' object.
Argument names are always local. If you assign a name within a function it is a local name, unless made explicitly global. If you only lookup a name, the name is looked up in the outer environments, rather than locally within the functions environment. Calling a function is also looking up a name, and follows the same rules.

If you try and update an outer name and look it up, you'll run into problems.

code:
x = 0
def d():
    x = x + 1 # this errors. by assigning to x, x is a local name, and is unbound.
Operations like y+=[1] can be confusing under this rule, because although they can change they object, they assign to the name, making it local.

code:
y = []

def f():
    y.append(1)  # y is global here

def g():
    y+=[2] # this, like y = y + [2], treats y as a local name, and is unboard. like above


f() # the object pointed to by y, now points to the objects  1,2
g() # this is an error - y exists in g's environment, and does not point to an object.
Recap time—Names are stored in environments. Environments can nest. Functions create new environments. Defining a name through function arguments, or assignment, creates the name in the local environment. Just reading a name will make it look in the outer functions. You can force it to use the outermost environment with the global statement.

Now we understand names, objects, and environments, we can see how they work for closures, or functions inside functions.

code:
def f():
    x = [] # the name x is local to f
    def g():
        x.append(1) # x is looked up in f's environment
        return x
    x = [0]
    return g

g = f()
g() # returns [0,1]
g() # returns [0,1,1]

h = f() # this creates a new local environment,
h() # returns [0,1] 
h() # returns [0,1,1]
When you call a function, a new local environment is created. Because the names inside f can be looked up after f is called, this environment is kept alive. Calling f again creates a new, separate environment.

Let's look at some similar code to your example, now with our knowledge of environments, names and objects, and how they fit together.

code:
def f():
    x = [] # the name x is local to f
    def g():
        x.append(1) # x is looked up in f's environment, not g's
        return x
    x = [0]
    def h():
        x.append(2) # again, f is looked up in f's environment, not h's
        return x
    return g, h

g,h = f()
g() # returns [0,1]
h() # returns [0,1,2]
You can hopefully see now where the problem is. We want g and h to use separate objects, but they share the same name, and thus the same object, found in the outer function f.

To share different objects, we need to create a different environment for g and h, rather than them both sharing f's. We can create a different environment, by wrapping g and h in another function.


code:
def f():
    x = []
    def _g(x): # x is local to _g
        def g():
            x.append(1) # x is looked up in _g's environment, not f's
            return x
        return g

    g = _g(x) # _g creates a local environment, stores the address stored in x

    def _h(x):
        def h():
            x.append(2) # x is looked up in _h's environment, not f
            return x
        return h

    x = [0] # x now points to a new object

    h = _h(x)  # _h creates a new local environment, stores the address stored in x

    return g, h

g,h = f()
g() # returns [1]
h() # returns [0,2]
We can do a similar thing with a nested lambda foo = (lambda x: lambda y: y+x)(x). Another way to do it is through default arguments. Default arguments are evaluated when the function is defined, not called, so the objects stored for the default arguments are shared for each subsequent call. Changing what the name points to doesn't persist though calls though.

code:
def f():
    x = [] # the name x is local to f
    def g(x=x): # we copy the address of x into the default argument environment for g
        x.append(1)  # x is local name to g, but points to the object set as the default.
        return x
    x = [0] # we change what x points to
    def h(x=x): 
        x.append(2)  # the x here is local to h, and uses a different object from g
        return x
    return g, h

g,h = f()
g() # returns [1]
h() # returns [0,2]
This only works because we change which object x points to, before defining the function. If we mutate the object instead, we have the same problem as before.

code:
def f():
    x = [] # the name x is local to f
    def g(x=x): # we copy the address of x into the default argument environment
        x.append(1)  # x is local name to g, but points to the object set as the default.
        return x
    x.append(0) # x still points to the same object, and we change it
    def h(x=x): # again we copy the address of x
        x.append(2) # we only read, so x is looked up in g's environment, not f's
        return x
    return g, h

g,h = f()
g() # returns [0,1]
h() # returns [0,1,2]
Although g and h have separate environments, both names still point to the same object because we mutated x instead of creating a new object. This is the classic trap of mutable default arguments in a more roundabout way.

If we used immutable objects instead of mutable objects, we would't have to worry about sharing them, but we are faced with a different problem—How do you rebind a name in closure, and keep this change between calls?

We might try using default variables, but changing a name doesn't last between calls

code:
def f():
    x = 1
    def g(x=x):
        x = x + 1 # this changes the local x, not the default argument object 
        return x
    return g

g = f()
g() # returns 2
g() # returns 2 # not what we wanted!
Or we can try reassigning inside the closure, but that causes the name to be in the local environment, and we encounter a now familiar issue.

code:
def f():
    x = 1
    def g():
        x = x + 1 # x is a local name
        return x
    return g

g = f()
g() # error, x is unbound!
For python 2.x you must work around this, and wrap the immutable object inside a list, and change what the list points to.

For python 3 users, we can use the 'nonlocal' keyword.


code:
def f():
    x = 1 # the name x is local to f
    def g(): 
        nonlocal x # python 3 magic
        x = x + 1
        return x
    return g

g,h = f()
g() # returns 2
g() # returns 3
That should just about cover it, but I haven't got on to how names work in class statements :3:

(http://docs.python.org/2/reference/executionmodel.html should answer any further questions)

tef fucked around with this message at 11:10 on Feb 15, 2013

Adbot
ADBOT LOVES YOU

Jewel
May 2, 2009

drat that was a good writeup, A++ for effort and clarity :swoon:

  • Locked thread