#πŸ”’ Scope

117 messages Β· Page 1 of 1 (latest)

west hollow
#
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        index = len(candidates) - 1
        ans = []

        def recursiveAlgo(currIndex):
            if currVal == target:
                ans.append(currValList.copy())
                return
            if currVal > target:
                currValList.pop()
                currVal =- candidates[currIndex]
                return
            currVal += candidates[currIndex]
            currValList.append(candidates[currIndex])
            attemptedIndex = currIndex
            while attemptedIndex == currIndex:
                recursionAlgo(attemptedIndex)
                attemptedIndex -= 1
            currValList.pop()
            currVal -= nums[currIndex]

        while index >= 0:
            currVal = 0
            currValList = []
            recursiveAlgo(index)
            index -= 1

        return ans

This code is giving me an unboundlocal error at currVal == target: but i don't really understand. When the function gets called, currVal and currValList would've been executed already and so it should have access to it since it's called right after. Could someone explain how scoping works here?

amber isleBOT
#

@west hollow

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

rose karma
#

by attempting to do so, you've declared that variable as local to the recursiveAlgo function

west hollow
#
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        subset = []

        def computeSubsets(index):

            if index >= len(nums):
                res.append(subset.copy())
                return 

            subset.append(nums[index])
            computeSubsets(index + 1)

            subset.pop()
            computeSubsets(index + 1)
        
        computeSubsets(0)

        return res

Then why does this work?

rose karma
#

!e

def foo():
    x = 5
    def bar():
        print(x)
        x = 10
    bar()


foo()

amber isleBOT
# rose karma !e ```py def foo(): x = 5 def bar(): print(x) x = 10 ...

:x: Your 3.13 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 9, in <module>
003 |     foo()
004 |     ~~~^^
005 |   File "/home/main.py", line 6, in foo
006 |     bar()
007 |     ~~~^^
008 |   File "/home/main.py", line 4, in bar
009 |     print(x)
... (truncated - too many lines)

Full output: https://paste.pythondiscord.com/S7ACZFSE247QG2VZKQRWLSVVIY

rose karma
#

here's a simplified version of your issue

west hollow
#

is it because i'm mutating the state referred to by the variable and not changing the variable's value?

rose karma
west hollow
#

ahhh i see

rose karma
#

you could use the nonlocal keyword to get around this

#

it will tell the inner function that your reference comes from the outer scope

west hollow
#

one sec looking at the examples you made above

rose karma
#

!e

def foo():
    print(x)

x = 10
foo()
amber isleBOT
rose karma
#

this is ok

#

!e

def foo():
    print(x)
    x = 5

x = 10
foo()
amber isleBOT
# rose karma !e ```py def foo(): print(x) x = 5 x = 10 foo() ```

:x: Your 3.13 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 6, in <module>
003 |     foo()
004 |     ~~~^^
005 |   File "/home/main.py", line 2, in foo
006 |     print(x)
007 |           ^
008 | UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
rose karma
#

this is not. It's a very common "gotcha"

#

as soon as the function contains a reassignment, it assumes all references to that variable are from its scope

#

it's aware of its local variables before it's even called

west hollow
#
def foo():
    x = 5
    def bar():
        print(x)
        x = 10
    bar()


foo()```
#

so the x=10 makes the bar() aware that x exists locally before that line is even executed.

#

thus print(x) tries to refer to local variable x

rose karma
#

exactly, which is why it complains about print(x)

#

it knows that there will eventually be a local assignment to x

west hollow
#

but i thought python was executed at runtime

#

and doesn't compile beforehand

rose karma
#

it won't error out as the function is being defined

#

I don't know the exact specifics behind the scene, but the function has information about expected scopes at runtime

west hollow
#

ohh okay wait

rose karma
#

I just know how to avoid the pitfalls πŸ˜…

west hollow
#

is the function body only executed during runtime

rose karma
#

yes

#

it's executed when called

#
def foo():
    print(abc)
#

this won't error simply by defining it

#

it will only error once called

west hollow
#

oh wait im a lil confused

#

when you say error out by defining it

rose karma
#

as far it knows, a variable abc could be created before the function is called

west hollow
#

what do you mean by defining it?

rose karma
#

def defines a function

west hollow
#

when does python ever error out while defining something? Wouldn't that imply a compile time check

#

or am i misunderstanding something

rose karma
#

it doesn't

#

that's what I'm saying

west hollow
#

ah okay

rose karma
#

when the function is called, it goes and figures out what variable represents what scope

#

with a priority of local/nonlocal/global

west hollow
#

so my idea behind how the general scoping works is correct

rose karma
#

which idea exactly?

#

"you can mutate but not reassign" is the gist

west hollow
#
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        index = len(candidates) - 1
        ans = []

        def recursiveAlgo(currIndex):
            if currVal == target:
                ans.append(currValList.copy())
                return
            if currVal > target:
                currValList.pop()
                currVal =- candidates[currIndex]
                return
            currVal += candidates[currIndex]
            currValList.append(candidates[currIndex])
            attemptedIndex = currIndex
            while attemptedIndex == currIndex:
                recursionAlgo(attemptedIndex)
                attemptedIndex -= 1
            currValList.pop()
            currVal -= nums[currIndex]

        while index >= 0:
            currVal = 0
            currValList = []
            recursiveAlgo(index)
            index -= 1

        return ans
#

defining currVal and currValList right before calling recursiveAlgo so that it knows what im referring to when the function is called

west hollow
rose karma
#

it will always assume an assignment is local unless you use nonlocal or global

#

your -= and += are assignments

west hollow
#

say i didnt do any assignments

rose karma
#

remember currVal += is the same as currVal = currVal +

west hollow
#

i just want to make sure my expectation of how scoping works (ignoring the pitfall i fell into) is correct

rose karma
#

as long as it doesn't have a local assignment to a variable of the same name

#

!e

def foo():
    print(x)

x = 10
foo()
amber isleBOT
rose karma
#

!e

def foo():
    x = 5
    print(x)

x = 10
foo()
amber isleBOT
rose karma
#

as soon as there's a local var with the same name, it takes priority

west hollow
#

got it

rose karma
#

the same thing is happening in yours, but instead of local and global, it's local and nonlocal

west hollow
#

so when we define a function, does it sorta just mark where to go to when it actually sees that function being called?

rose karma
#

it's simply a collection of instructions that execute when called

#

again I'm not really sure of the behind the scenes specifics πŸ˜…

west hollow
#

no worries no worries

#

high level wise, you're validating what im thinking so im happy with just that

#

appreciate you taking the time to help me out

rose karma
#

np!

#

it's a bit tricky to wrap your head around at first

west hollow
#

oh wait 1 last question

#

the line where it pointed the error to was when this statement was executed if currVal == target:

rose karma
#

yeah, it's the first line of your function (and the first time currVal is trying to be accessed within that scope)

west hollow
#

but if currVal == target: is only performing a read and comparison, not reassignment

rose karma
#

yes but your function hasn't had an assignment to currVal yet

#

it can't mix and match scopes

west hollow
#

ohhh

#

fuck me

#

oay i get it

rose karma
#

it doesn't think "oh I'll use the nonlocal one until the local one is assigned"

west hollow
#

i perform a reassignment somewhere so it expects currVal to be local

rose karma
#

!e

def foo():
    print(x)
    x = 5
    

x = 10
foo()
amber isleBOT
# rose karma !e ```py def foo(): print(x) x = 5 x = 10 foo() ```

:x: Your 3.13 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 7, in <module>
003 |     foo()
004 |     ~~~^^
005 |   File "/home/main.py", line 2, in foo
006 |     print(x)
007 |           ^
008 | UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
rose karma
#

that's what this gotcha is all about

west hollow
#

and thats where i first use it

rose karma
#

it doesn't say "I'll print global x and then reassign local x"

#

it says "hey x comes later in the function, so you can't use it yet"

cursive sedge
#

so the thing is, python is compiled into bytecode. it is then the bytecode that is interpreted. Determining if a variable is local is part of the compilation, which is why the function somehow "knows" that it gets assigned later

west hollow
#

okay got it

#

sorry that was pretty dumb after you just explained it

#

took a sec for it to clock

rose karma
#

"gotchas" aren't always easy to understand πŸ™‚

west hollow
#

okay fairs fairs that makes sense then

rose karma
#

so yeah, just a simple added nonlocal currVal will fix that up

west hollow
#

aight aight

#

appreciate it

#

have a good one ;d

rose karma
#

you too!

neon arrow
amber isleBOT
#
Python help channel closed for inactivity

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.