Beginners sometimes ask how a function can be made to return "more than one object". The strict answer is that it can't. The single object it returns can be a container, though, allowing several values to be extracted from the returned object. If you want a function to return three values the easiest way to arrange this is to have it return a three-element tuple, and then extract the individual values using an unpacking assignment. Here's a simple example.
def powers(a):
return a, a*a, a*a*a
a, square, cube = powers(10)
print(a, square, cube)
def make_fun(power, debug=False):
def pow(x):
result = x ** power
if debug:
print("power(%s, %s) returned" % (x, power), result)
return result
return pow
squarer = make_fun(2)
cuber = make_fun(3, True)
print([f(9) for f in (squarer, cuber)])
The output from this is
power(9, 3) returned 729
[81, 729]
You may be familiar with the concept of a mixin class. Such classes are designed to take advantage of Python's multiple inheritance features to add functionality to any chosen classes, by creating a new class which is a subclass of both the mixin and the chosen class. You can see an exellent example of this in the socket library, where a ThreadingMixIn class is defined and can be used to extend the features of the basic UDPServer class like this:
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
In the same way that we can parameterize functions, however, we can parameterize classes as well. Suppose we want to provide a trivial mixin to print the class's name in either upper- or lower-case. Not very inspiring, but the simplest example I could think of to get the point over, so please bear with me if you can think of simpler ways to do this. One possibility is this.
def mixin(cls, lcase=True):
class Mixin:
def nprint(self):
if lcase:
print(str(cls).lower())
else:
print(str(cls).upper())
class Result(Mixin, cls):
pass
return Result
class FirstClass:
pass
Cl1 = mixin(FirstClass, True)
cl1 = Cl1()
cl1.nprint()
mixin(FirstClass, False)().nprint()
Here the function first defines a mixin class, then creates a new class from the mixin and the base class provided as an argument. The interpreter cares not at all where the class definitions come from - classes are first-class objects just like functions and strings, and can just as easily be passed as function arguments as obtained any other way.
The output from the program, which I am sure you are waiting for with bated breath, is
<class '__main__.firstclass'>
<CLASS '__MAIN__.FIRSTCLASS'>
Now you might choose to argue that this isn't a very natural example, and I'd be inclined to agree with you. All I have to say besides that is, you try coming up with these examples and see how you like it. If anyone chooses to contribute a more natural example that can be expressed without too much extra code I'll be happy to write about it.
3 comments:
You might be interested in my factory module, an OO approach to factories: http://pypi.python.org/pypi/Factory/
In the mixin() function, you could put the test on lcase outside of the nprint() definition:
if lcase:
class Mixin:…
else:
class Mixin:…
Thus, creating new Mixin instances is faster, as no test on lcase is performed. This may matter.
@EOL. That's a good point. If the function is called many times there'd be a definite small win.
Probably the biggest gain is the improvement in readability. Your solution puts the computation where (and when) it belongs, since the decision is properly made ance and for all when the factory function is called.
Post a Comment