Problems with Local Variable Scope. How to Solve It

Problems with local variable scope. How to solve it?

You have a scope problem indeed, because statement is a local method variable defined here:

protected void createContents() {
...
Statement statement = null; // local variable
...
btnInsert.addMouseListener(new MouseAdapter() { // anonymous inner class
@Override
public void mouseDown(MouseEvent e) {
...
try {
statement.executeUpdate(query); // local variable out of scope here
} catch (SQLException e1) {
e1.printStackTrace();
}
...
});
}

When you try to access this variable inside mouseDown() method you are trying to access a local variable from within an anonymous inner class and the scope is not enough. So it definitely must be final (which given your code is not possible) or declared as a class member so the inner class can access this statement variable.

Sources:

  • Anonymous Classes
  • How are Anonymous (inner) classes used in Java?

How to solve it?

You could...

Make statement a class member instead of a local variable:

public class A1 { // Note Java Code Convention, also class name should be meaningful   
private Statement statement;
...
}

You could...

Define another final variable and use this one instead, as suggested by @HotLicks:

protected void createContents() {
...
Statement statement = null;
try {
statement = connect.createStatement();
final Statement innerStatement = statement;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
}

But you should...

Reconsider your approach. If statement variable won't be used until btnInsert button is pressed then it doesn't make sense to create a connection before this actually happens. You could use all local variables like this:

btnInsert.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
try {
Class.forName("com.mysql.jdbc.Driver");
try (Connection connect = DriverManager.getConnection(...);
Statement statement = connect.createStatement()) {

// execute the statement here

} catch (SQLException ex) {
ex.printStackTrace();
}

} catch (ClassNotFoundException ex) {
e.printStackTrace();
}
});

Variable scope issues

By having var variable inside your local_var_dec, you're shadowing the global with an entirely different local variable. That means the global isn't available within local_var_dec. And because var variables are hoisted, it's not available anywhere in local_var_dec, exactly as though it looked like this:

function local_var_dec(){
var variable; // ***
console.log("local: "+ variable);
if(typeof variable === 'undefined'){
variable = 2; // ***
}
}

So that means when you assign to it, you're assigning to the local variable, not the global; doing that has no effect at all on the global, which is why when you call global_var_global later, you see the global's original value.

Although you can still access the global, you can't access it as a variable. Implicit globals¹ such as yours (and ones declared with var at global scope) are properties of the global object, and so can be accessed via the global object, which is accessible as window on browsers. So window.variable would access it within local_var_dec on browsers. In other environments, there may or may not be a global for the global object defined by the environment. On NodeJS for instance, there's global. You can always get a reference to the global object, though, from this at global scope (assuming the environment allows you to run code at global scope; NodeJS doesn't, for instance).

Fundamentally, though, avoid shadowing variables if you need to access them, since that feature of globals is A) Specific to globals, B) Not really a good idea, and C) Not available with the new let and const declarations.

Here's a snippet annotated with what exactly is happening, and showing using window.variable (although again, ideally just use a different name):

// This creates an *implicit global* by assigning// to an undeclared identifiervariable = 1;local_var_dec();global_var_global(); function local_var_dec(){    // This shows `undefined` because `variable` in the below is the *local*    // variable you've declared with `var`, even though the `var` hasn't    // been reached yet. `var` is *hoisted* to the top of the function.    console.log("local: "+ variable);    // This is still the local, so it's still `undefined`    if(typeof variable === 'undefined'){        // This sets the *local* variable to 2; it has no effect at all on        // the global        var variable = 2;    }      // If you wanted, you could use `window.variable` here    console.log("window.variable = " + window.variable);} function global_var_global(){    // Because there's no `var` in this function, this us using the global    // `variable`    console.log("global: "+ variable);    if(typeof variable === 'undefined'){        variable = 2;    }}

Problem with local variable. NameError: name 'b' is not defined in python

You should define what does your b and j mean in string 10:
For python you are giving noting to function, but this function is asking for some value (a), it should be like this:

def first(a):
a = 0
b = 3
return b
def second(a):
a = 0
j = 7
return j
def result():
b = 123 # Defining what are we giving to our functions
j = 5

return first(b) * second(j) # Now it will work
print(result())

So you can use b and j value, and access return values:

    b = 3
return b

j = 7
return j

Think like this, when you're returning some value, it fully replaces function with that value.

Why won't this variable reference to a non-local scope resolve?

The Problem:

When trying to resolve a variable reference, Python first checks in the local scope and then in the local scope of any enclosing functions. For example this code:

def foo():
x=23
def bar():
return x +1
return bar

print(foo()())

Will run and print out 24 because when x is referenced inside of bar, since there is no x in the local scope it finds it in the scope of the enclosing function (foo). However, as soon as you try to assign to a variable, Python assumes it is defined in the local scope. So this:

def foo():
x=23
def bar():
x = x + 1
return x
return bar

print(foo()())

Will throw an UnboundLocalError because I am trying to assign to x which means it is going to be looked up in the local scope, but the value I'm trying to assign to it is based on the x from the enclosing scope. Since the assignment limits the search for x to the local scope, it can't be found and I get the error.

So your error is coming up because of the testerNum -= 1 line in your else clause, it is limiting the search for testerNum to the local scope where it doesn't exist.

The Fix:

The global declaration isn't right since, as you noted, testerNum isn't defined in the global scope. I'm not familiar with Spyder and don't know why it worked there but it seems like it somehow got a testerNum variable in its global scope.

If you're using Python3 you can get around this by changing your global testerNum line to nonlocal testerNum which just tells Python that, despite being assigned to, testerNum isn't defined in the local scope and to keep searching outwards.

def foo():
x=23
def bar():
nonlocal x
x = x + 1
return x
return bar

>>> print(foo()())
24

Another option that would work in Python 2 or 3 is to pass around testerNum as Brambor outlined in their answer.

Can two local variable blocks call each other? Scope issue due to order of declaration

Captures are by value with Blocks unless the variable is marked as __block. That's the correct solution here.

If you declare lower as a __block variable, it will be captured as a reference rather than taken as a copy, and the upper will see its "current" value when called:

__block BOOL proceedWithInfiniteRegress = YES;
__block dispatch_block_t lower;

dispatch_block_t upper = ^{
if( proceedWithInfiniteRegress ){
lower();
}
};

lower = ^{
proceedWithInfiniteRegress = NO;
NSLog(@"Hello, reference cycle!");
upper();
};

upper();

How to solve the problem that the global variable is not defined in python?

You got the scoping wrong. Python is a lexically scoped language.

Without knowing, you are writing closures. Meaning you use variables in simpleBuyStrategy_split and simpleSellStrategy_split which are not in the function argument list - but outside the function definition.

Basically

    buySellTable = dict()
hold = False
count = 0
startIdx = 0

You treat them as if they would have dynamic scoping.
(that they would change dependent where these two functions are called).

Since python arguments are mostly call-by-reference (due to performance reasons) - so they work like C pointers, the arguments themselves are changed if they are changed in the function body - except when they are deep-copied explicitely in the function body.

Therefore you could use them as if they are dynamically scoped, if you just pass them as function arguments.

Like this:

# first define them globally

buySellTable = dict()
hold = False
count = 0
startIdx = 0

# then in each function definition, pass them as function arguments

def simpleRSIstrategy_split(indicator, threshold1 = 50, threshold2 = 40, days = 3, buySellTable=buySellTable, hold=hold, count=count, startIdx=startIdx):

while True:

simpleBuyStrategy_split(indicator, threshold1, buySellTable=buySellTable, hold=hold, count=count, startIdx=startIdx)

simpleSellStrategy_split(indicator, threshold1, threshold2, days, buySellTable=buySellTable, hold=hold, count=count, startIdx=startIdx)

if startIdx == len(indicator)-1:
break

return buySellTable

def simpleBuyStrategy_split(indicator, threshold1, buySellTable=buySellTable, hold=hold, count=count, startIdx=startIdx):

for i in range(startIdx, len(indicator)):
if indicator['RSI7'][i] > threshold1 and not hold:
date = indicator.index[i]
buySellTable[date] = 'Buy'
hold = True
startIdx = i+1
break

def simpleSellStrategy_split(indicator, threshold1, threshold2, days, buySellTable=buySellTable, hold=hold, count=count, startIdx=startIdx):

for i in range(startIdx, len(indicator)):
if indicator['RSI7'][i] < threshold1 and hold:
count += 1
if count == days or indicator['RSI7'][i] < threshold2:
date = indicator.index[i]
buySellTable[date] = 'Sell'
hold = False
count = 0
startIdx = i+1
break
if indicator['RSI7'][i] > threshold1 and hold:
count = 0

I see, somehow you realized that they have globally to refer,
but then, the simpleRSI function split must also do it:


buySellTable = dict()
hold = False
count = 0
startIdx = 0

def simpleRSIstrategy_split(indicator, threshold1 = 50, threshold2 = 40, days = 3):
global buySellTable, hold, count, startIdx

while True:

simpleBuyStrategy_split(indicator, threshold1)

simpleSellStrategy_split(indicator, threshold1, threshold2, days)

if startIdx == len(indicator)-1:
break

return buySellTable

And the other two functions then as you had them. This might also work.

But this is not so nice. Because one should avoid global variables.

Solution: Encapsulate Using Classes

In Python, you would avoid global variables by using classes.
You could create a class where the global variables are class Attributes. (prepended by: self.
And these three functions are methods of the class.
Since they have then to refer to these four variables using self.
you don't need the 'global' delcarations in them.
And the class itself is encapsulated.

Like this:

class SimpleRSITrader:
def __init__(self, indicator, threshold1 = 50, threshold2 = 40, days = 3, rsi='RSI7'):
self.buy_sell_table = {}
self.hold = False
self.count = 0
self.start_idx = 0
self.indicator = indicator
self.thresh1 = threshold1
self.thrseh2 = threshold2
self.days = days
self.rsi = rsi

def run(self):
while True:
self.buy()
self.sell()
if self.startIdx == len(self.indicator)-1:
break
return self.buy_sell_table

def buy(self):
for i in range(self.start_idx, len(self.indicator)):
if self.indicator[self.rsi][i] > self.thresh1 and not self.hold:
date = self.indicator.index[i]
self.buy_sell_table[date] = 'Buy'
self.hold = True
self.start_idx = i + 1
break

def sell(self):
for i in range(self.start_idx, len(self.indicator)):
if self.hold:
if self.indictaor[self.rsi] < self.thresh1:
self.count += 1
if count == self.days or self.indictoar[self.rsi][i] < self.thresh2:
date = self.indicator.index[i]
self.buy_sell_table[date] = 'Sell'
self.hold = False
self.count = 0
self.start_idx = i + 1
break
if self.indicator[self.rsi][i] > self.thresh1:
self.count = 0

The good thing of this is, you can anytime from outside check the status of the attributes. And thus also communicate with other parts of the program - while you don't have global variables - because the previously global variables are now encapsulated in the class - therefore packed into objects.

So the idea is that for each indicator with new threshold settings and day settings you create a new instance for the simple RSI strategy.

This class, you can reuse even for different RSI's (other than 'RSI7').

Through encapsulation, the context for your buy and sell becomes clear - thus the method names or attribute names become simpler too - therefore everything more easily readable and your code is structured - every former global variables and functions are now encapsulated into the class - thus the code is clearly structured and the context of each of them clear - therefore you can be shorter with your names.

How to access local and global variable with same name in C

You could cheat and create a pointer to the global i before declaring the local i:

void fun2( void )
{
int *ip = &i; // get address of global i
int i = 50; // local i ”shadows" global i

printf( "local i = %d, global i = %d\n", i, *ip );
}

EDIT

Seeing as this answer got accepted, I must emphasize that you should never write code like this. This is a band-aid around poor programming practice.

Avoid globals where possible, and where not possible use a naming convention that clearly marks them as global and is unlikely to be shadowed (such as prefixing with a g_ or something similar).

I can't tell you how many hours I've wasted chasing down issues that were due to a naming collision like this.

Problems with returning references to local variables...?

Is this complaint correct?

Yes it is. _handles is an automatic variable, and you return a range referring to it. Ranges are basically abstractions over pairs of iterator + sentinel. The returned range will be invalid outside the function.

And how can I solve this

A correct implementation would be to return a transforming adaptor range. Possibly something along the lines of:

return _collection | boost::adaptors::map_keys;


Related Topics



Leave a reply



Submit