Re: Problem with a dialog

2014-12-11 Thread Steven D'Aprano
ast wrote:


> Since try() is a callback function called when a button is pushed,
> with the effect to open a dialog, I tried to define MyDialog class
> inside try(). The program is the following and it works. I no
> longer need to define test as global.
> Is it a good practice to define a class inside a function ?

Your question is too general. It *can* be good practice, or it can be bad
practice.

Classes are "first class values" (pun not intended) in Python, which means
you can pass them to functions and you can generate them on the fly and
return them from functions too. There is a downside to that: classes are
fairly hefty objects compared to instances, so if every time you call a
function you create an instance of a brand new class instead of re-using
the same class, your memory consumption will be much higher.

In your case, it probably doesn't matter: you only create a single MyDialog
instance, so it shouldn't matter that the class is created dynamically
inside the function. But I'm going to suggest a more object oriented
solution that avoids the local/global scoping issue completely:

* Make test an attribute of MyDialog (what some other languages 
  call "an instance variable").


from tkinter import *
import tkinter.simpledialog

class MyDialog(tkinter.simpledialog.Dialog):
test = True
def body(self, master):
print(self.test)
def apply(self):
pass


def try_():
setup = MyDialog(root)
 
root = Tk()
try_()



Technically, what I have done here is make "test" a class attribute, that
is, it will be shared by all MyDialog instances. But since there is only
one instance, that doesn't matter.

Another approach is to forgo the line "test = True" inside the class, and
set a per-instance attribute when the instance is created. Add this method
to the class:

def __init__(self):
self.test = True


Generally speaking, the __init__ method approach is more common.





-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Problem with a dialog

2014-12-11 Thread ast


"Steven D'Aprano"  a écrit dans le message de 
news:54898820$0$12989$c3e8da3$54964...@news.astraweb.com...



You can make "test" global by declaring it global:

def try_():
   global test
   test = True
   setup = MyDialog(root)



If that solves your problem to your satisfaction, you can stop reading now.



Since try() is a callback function called when a button is pushed,
with the effect to open a dialog, I tried to define MyDialog class
inside try(). The program is the following and it works. I no
longer need to define test as global.
Is it a good practice to define a class inside a function ?


from tkinter import *
import tkinter.simpledialog

def try_():

   class MyDialog(tkinter.simpledialog.Dialog):

   def body(self, master):
   print(test)

   def apply(self):
   pass


   test = True
   setup = MyDialog(root)


root = Tk()
try_() 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Problem with a dialog

2014-12-11 Thread ast


"Steven D'Aprano"  a écrit dans le message de 
news:54898820$0$12989$c3e8da3$54964...@news.astraweb.com...




As I said, most programming languages work like this. But a small minority
use a different system, called "dynamic scoping". In dynamic scoping, it
doesn't matter *where* a function is defined, only where it is called. With
dynamic scoping, your code would have worked correctly.



Thank you  very much.

This is my mistake
I knew that a function defined in a scope "knows" the variables defined
in that scope, at least for reading (for writing, it is more complicated).
I didnt realize that my function/class was called, not defined in that
scope. 


--
https://mail.python.org/mailman/listinfo/python-list


Re: Problem with a dialog

2014-12-11 Thread Steven D'Aprano
ast wrote:

> Hello
> 
> I provide two almost identical small test case programs.
> The first one works as expected, 'True' is printed on the
> console.
> With the second one Python complains that 'test' is not
> known. I dont understand why.


> #
> ## Second
> #
>  
> from tkinter import *
> import tkinter.simpledialog
> 
> class MyDialog(tkinter.simpledialog.Dialog):
> 
> def body(self, master):
> print(test)

Here, "test" must be a global variable. Since the body() method doesn't
assign to the name "test" (e.g. a line like "test = 23") that makes it a
global.


> def apply(self):
> pass
> 
> def try_():
> test = True
> setup = MyDialog(root)

Here, the try_() function creates two local variables, "test" and "setup".
The important thing here is that "test" is local to the function, not
global.

That means that when MyDialog's body() method runs, it looks for a global
variable "test", but there isn't one. The local variable inside try_() is
invisible to it.

You can make "test" global by declaring it global:

def try_():
global test
test = True
setup = MyDialog(root)



If that solves your problem to your satisfaction, you can stop reading now.



Still here? Good :-)

To be a little more advanced for a moment... what you tried to do (possibly
inadvertently?) is possible in some computer languages, but not Python. In
most languages, the rule is that functions (and methods) can see the
following variables:

- variables inside the function itself (local variables)

- variables inside nested functions [see below], sometimes 
  called "nonlocal variables"

- global variables defined at the top level of the module or 
  program (outside of any function)


but not variables inside functions that *call* your function. This is
called "static scoping" or "lexical scoping".

What's a nested function? That's just when you put a function inside another
function:

def outer():
x = 23
def inner():
return 3*x
return inner() + 1


In this case, inner() is nested inside outer(), so it can see outer()'s
local variables, such as "x". Nothing else can see inner(), since it is
local to outer().

As I said, most programming languages work like this. But a small minority
use a different system, called "dynamic scoping". In dynamic scoping, it
doesn't matter *where* a function is defined, only where it is called. With
dynamic scoping, your code would have worked correctly.

If you are used to languages like Javascript, you may have done that
deliberately, thinking Python worked the same way. It doesn't.


-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Problem with a dialog

2014-12-11 Thread ast

Hello

I provide two almost identical small test case programs.
The first one works as expected, 'True' is printed on the
console.
With the second one Python complains that 'test' is not 
known. I dont understand why.


Python 3.4, windows


#
## First
#

from tkinter import *
import tkinter.simpledialog

class MyDialog(tkinter.simpledialog.Dialog):

   def body(self, master):
   print(test)
   
   def apply(self):

   pass

root = Tk()
test = True
setup = MyDialog(root)

# 'True' is printed on the console. Works !



#
## Second
#

from tkinter import *
import tkinter.simpledialog

class MyDialog(tkinter.simpledialog.Dialog):

   def body(self, master):
   print(test)
   
   def apply(self):

   pass

def try_():

   test = True 
   setup = MyDialog(root)



root = Tk()
try_()

# NameError: name 'test' is not defined
--
https://mail.python.org/mailman/listinfo/python-list