[Tutor] class attribute to initiate more classes

Vincent Davis vincent at vincentdavis.net
Sat Oct 31 17:07:22 CET 2009


>
>
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20091031/ce3d0549/attachment.htm>


More information about the Tutor mailing list