conditionally creating functions within a class?

Steve Holden steve at holdenweb.com
Sat May 26 11:37:26 EDT 2007


kaens wrote:
> Thanks a lot. What actually got me started on this whole thing was a
> mention in pythons tutorial on classes that you could conditionally
> create classes (which you can).
> 
> Anyhow, yes this is cleared up.
> 
> I'll probably go with using inheritance for this, as it makes sense
> for my program overall, unless there's some huge disadvantage to using
> it. Is there any way to make something like interfaces - or say
> "objects that inherit from this class need to implement these
> functions" in python? It's not really an issue for me, but if someone
> else ends up wanting to extend my code it could be useful.
> 
> I guess I could do something like
> 
> class a:
>    def __init__(self):
>        raise NotImplementedError
>    def required_function:
>       raise NotImplementedError
> 
> kinda mimicking abstract classes, unless there's a builtin way to do
> this (looks like there's not but it may make it into python 3000)
> 
> I'd rather not make seperate modules for these functions, as the class
> that requires them does a good bit of other stuff as well (and will
> definitely be using one type of data retrieval or another), and I
> think this would make it easiest to extend in the future.
> 
> If you think I'm on the wrong track here, let me know.
> 
I have taken the liberty of copying this back to the list, since other 
people may have stringer opinions than I on your approach.

Frankly, I wouldn't worry about the "expense" of declaring two classes. 
If you need SQL-handling and XML-handling code then just declare two 
classes (with inheritance from a common class if that makes sense) and 
stop worrying about cost. It really doesn't make sense to try and fiddle 
the class methods to accommodate the needs of a single instance.

"Premature optimization is the root of all evil".

regards
  Steve

PS: Many people prefer it when newsgroup conversations read linearly, 
with the most recent contributions at the bottom. That way a reader can 
easily "pick up the story".



> On 5/25/07, Steve Holden <steve at holdenweb.com> wrote:
>> 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.
>>
-- 
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