> > > Vincent Davis wrote: > >> DaveA posted >> import random, functools >> >> class Person: >> def __init__(self, size): >> self.size = size >> >> def __str__(self): >> return "Person of size %s" % self.size >> >> class MakePeople: >> def __init__(self, random_func): >> self.random_func = random_func >> >> def make_them(self, count): >> return [Person(self.random_func()) for i in xrange(count)] >> >> people_maker = MakePeople(functools.partial(random.gauss, 100, 2)) >> persons = people_maker.make_them(100) >> for person in persons: >> print person.size >> >> I changed the last line, from >> print person >> print person.size >> >> So this does what I want, but I am not sure why. >> I read the entry about functools.partial but it was not very clear to me. >> If I >> people_maker = MakePeople(random.gauss(100, 2)) >> then I only get 1 random #. >> and if I >> MakePeople('random.gauss(100, 2)') >> then I just a fix string >> So DaveA uses >> >> functools.partial(random.gauss, 100, 2) >> >> not obvious to me from that it should not be >> >> functools.partial(random.gauss(100, 2)) >> >> and I guess the other key is >> >> Person(self.random_func()) >> >> Also now this >> people_maker = MakePeople(123) >> >> does not work, which is not terrible. >> >> Anyone have some more to add, I would not have confidence in applying this >> to new situations and it seems. >> >> Also I thank DaveA improving my Python conventions. I am really bad about >> that. Is there a cheat sheet for Python conventions. >> >> Like class (Capitals), def (two_words), I guess I should make my own. >> >> Thanks >> Vincent Davis >> 720-301-3003 >> >> <snip> >> >> >> > For the official Python style guide, see > http://www.python.org/dev/peps/pep-0008/ > > There are a couple of things going on in my code sample, and I'll try to > elaborate on them. I'm not claiming it's the 'right' answer, just that it > satisfies what I think were the most important goals you had. But if you > want to save the list in the MakePeople() instance, you'd add an additional > parameter to its constructor, and combine the second method into __init__(). > But as someone else points out, at that point, it's then hardly worth > making a class out of it. > > First the tough part. In your original code, your caller was doing: > > > > listofp = makepeople(random.guass(100, 2)) > > But that passes only a single value into the makepeople constructor. If > you're always going to use gaussian, then you can just move the function > call into the make_them() loop. But if you want to do the same thing, but > with a different distribution, you need to pass a function object instead. > Learning about function objects is very useful. You should really play > with them in a simpler situation, to get an idea how they work. > > At its simplest, a function object is just the function name, without > parentheses. You can store it (and pass it as a parameter to another > function) just like any other object. And then when you actually want to > call it, you can use the new name with parentheses, kind of like an alias to > the original function name. > > import math > > def indirection(funcobject, argument): > return funcobject(math.pi/180 * argument) > > print indirection(math.sin, 30) > print indirection(math.cos, 30) > > > Now what happens here? The indirection() function calls an entirely > different function the two times it's called, one time it calls sin, and the > other time it calls cos. As long as all the arguments to the function are > going to be supplied here, there's no confusion. Try the same thing with > any other set of functions, given that all of them take the same number and > types of arguments. > > This opens the door to all sorts of things, such as a mini-calculator > (following is mostly pseudo-code): > > funcname = getnamefrom user() > angleinradians = getnumberfromuser() > > converter_dict = { "sin": math.sin, "cos":math.cos } > print converter_dict[funcname](angleinradians) > > So the values of the dictionary are actual function objects, ready to be > called. > > What happens if some of the function parameters are known to the caller, > and not to the callee? I'll use the random.gauss example again. If we want > the caller to be able to specify them, we could do something like the > following: > > def print_indirection(funcobject, arg1, arg2, count): > for i in xrange(count): > print funcobject(arg1, arg2) > > and call it: > print_indirection(random.gauss, 100, 2, 44) > > to get 44 values with a gaussian distributon. But now suppose we wanted to > be able to use the same function with random.getrandbits() ? That function > only takes a single parameter, so the print funcobject() would blow up. > > functools.partial lets us bind a function object with some or all of its > arguments already attached. So in our case, the caller (who knows what the > arguments look like) gets to lay them out, without being stuck with any > particular ones. > > So, we rewrite print_indirection something like this: > > def print_indirection(funcobject, count): > for i in xrange(count): > print funcobject() > > and call it like: > print_indirection(functools.partial(random.gauss, 100, 2), 44) > print_indirection(functools.partial(random.getrandbits, 17), 44) > > The key here is that > > functools.partial(random.gauss, 100, 2) > is a function object that takes no parameters, because the 2 parameters of > the underlying function have already been bound. > > Now this can be generalized a bit, but I hope you understand it better than > before. You have to play with it. Make lists or dicts of your own > functions, with or without binding parameters. The key is that such a list > should have uniform signatures, which in the examples I've shown means none > of the function objects take any (more) arguments. > > DaveA > > DaveA thanks for the time you spent on that reply. I think it will take much me longer to understand it all than it took you to write it, But that is good.
Thanks Vincent
_______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor