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