conditionally creating functions within a class?

Steve Holden steve at holdenweb.com
Fri May 25 22:14:21 EDT 2007


kaens wrote:
> So, I have a class that has to retrieve some data from either xml or
> an sql  database.
> This isn't a problem, but I was thinking "hey, it would be cool if I
> could just not define the functions for say xml if I'm using sql", so
> I did some fiddling around with the interpreter.
> 
> First, I try conditionally creating a function, period:
> 
> a = 'a'
> 
> if(a == 'a')
>     def b:
>         print "hello"
> else:
>     def c:
>         print "goodbye"
> 
> this works fine. b is defined, c is not. change the value of a and b
> gets defined and not c (sorry for the one-letter variables here, but
> for these little examples I don't think they detract much)
> 
> then I try doing this within a function:
> 
> class test:
>     def __init__(self,which):
>         self.which = which
> 
>     if(self.which == 'a'):
>         def b:
>             print "hello"
>     else:
>         def c:
>             print "goodbye"
> 
The problem here is that the "if" statement executes in class scope, 
which means at the same level at which the "def" statements define the 
methods.

Unfortunately there is no "self" defined, as "self" is a method argument 
(whose value is provided automatically by the interpreter when a method 
call is made on a specific instance of the class). So it's out of scope.

You could try to define the methods inside __init__, but that isn't 
really appropriate because __init__ runs each time a new instance 
requires initialization, and one of the primary ideas behind object 
orientation is that the class defines the same methods for all instances.

You could override the methods in each instance, but this is all taking 
you further and further away from your relatively simple engineering goal.

> tester = test('a')
> tester.b()
> 
> This doesn't "compile", says "Name 'self' is not defined". I assume
> this is because of scope, something like it hasn't made the object
> yet, so there is no self attribute. . . but I thought that python
> wouldn't even bother reading that class statement until I tried to
> make a test object, and that it would do the __init__ function before
> anything else, so I'm a bit fuzzy here.
> 
In Python the only non-executable statement is "global", so the class 
definition is executed when it's encountered. This is what give rise to 
the problems, which you have correctly diagnosed as being related to 
scoping issues.

> Next I try creating the functions through functions:
> 
> class test:
>     def __init__(self, which):
>         self.which = which
>         self.chooser()
> 
>     def chooser(self):
>         if( self.which == 'a'):
>             def b(self):
>                 print "hello"
>         else:
>             def c(self):
>                 print "goodbye"
> 
> tester = test('a')
> tester.b()
> 
> this tells me "instance has no attribute b.
> 
And it isn't lying. The problem is that "def b" is executed within the 
chooser() method, so it's local to that method and invisible to the 
class scope.

> I'm pretty sure this is all a scoping error of some sort (I could be
> wrong), but I don't have my head wrapped around it at all. Anyone with
> more knowledge care to explain what's going on?
> 
> Also, would there be a way to conditionally create functions in a
> class? It doesn't really matter, but it'd be nice if I weren't
> creating functions that I absolutely will not need for certain
> instances at runtime

Here I'd ask you to take a step back. What you really need is two 
parallel modules or classes, one of which handles SQL inputs and the 
other of which handles XML inputs.

My own approach would be to define two modules with the same API and 
then import one or the other. Something like this:

if intype == "a":
     import sqlmodule as myinmod
     # do SQL-specific stuff, if any
else:
     import xmlmodule as myinmod
     # do XML-specific stuff, if any

You can then call the functions and classes defined in the imported 
module as

     myinmod.func()

and

     someinstance = myinmod.classname()

Since you only import one module, you don't execute the definitions in 
the unused module at all, and as long as the APIs really are parallel 
you can write code that doesn't care which one it uses.

There are other approaches you could take, but if this would answer your 
needs then I'd suggest you consider it.

regards
  Steve
-- 
Steve Holden        +1 571 484 6266   +1 800 494 3119
Holden Web LLC/Ltd           http://www.holdenweb.com
Skype: holdenweb      http://del.icio.us/steve.holden
------------------ Asciimercial ---------------------
Get on the web: Blog, lens and tag your way to fame!!
holdenweb.blogspot.com        squidoo.com/pythonology
tagged items:         del.icio.us/steve.holden/python
All these services currently offer free registration!
-------------- Thank You for Reading ----------------




More information about the Python-list mailing list