Dynamic class methods misunderstanding

Discussion in 'Python' started by Bill Mill, Jan 28, 2005.

  1. Bill Mill

    Bill Mill Guest

    Hello all,

    I have a misunderstanding about dynamic class methods. I don't expect
    this behavior:

    In [2]: class test:
    ...: def __init__(self, method):
    ...: self.method = method
    ...: self.method()
    ...:

    In [3]: def m(self): print self
    ...:

    In [4]: test(m)
    ---------------------------------------------------------------------------
    exceptions.TypeError Traceback (most recent call
    last)

    /cygdrive/c/Documents and Settings/Wmill/<console>

    /cygdrive/c/Documents and Settings/Wmill/<console> in __init__(self, method)

    TypeError: m() takes exactly 1 argument (0 given)
    -----------------------------------------------------------------------------

    Why doesn't m get the implicit self parameter in the self.method()
    call? How would I make it a proper member of the class, so that a
    self.method() call would work with the above "m" function?

    Peace
    Bill Mill
    bill.mill at gmail.com
    Bill Mill, Jan 28, 2005
    #1
    1. Advertising

  2. Bill Mill

    F. Petitjean Guest

    Le Fri, 28 Jan 2005 10:20:30 -0500, Bill Mill a écrit :
    > Hello all,
    >
    > I have a misunderstanding about dynamic class methods. I don't expect
    > this behavior:
    >
    > In [2]: class test:
    > ...: def __init__(self, method):
    > ...: self.method = method
    > ...: self.method()
    > ...:
    >
    > In [3]: def m(self): print self
    > ...:
    >
    > In [4]: test(m)
    > ---------------------------------------------------------------------------
    > exceptions.TypeError Traceback (most recent call
    > last)
    >
    > /cygdrive/c/Documents and Settings/Wmill/<console>
    >
    > /cygdrive/c/Documents and Settings/Wmill/<console> in __init__(self, method)
    >
    > TypeError: m() takes exactly 1 argument (0 given)
    > -----------------------------------------------------------------------------
    >
    > Why doesn't m get the implicit self parameter in the self.method()
    > call? How would I make it a proper member of the class, so that a
    > self.method() call would work with the above "m" function?

    The "def m(self):" was not properly indented. So here, "m" is a module level
    function, not a method of your class.
    >
    > Peace
    > Bill Mill
    > bill.mill at gmail.com
    F. Petitjean, Jan 28, 2005
    #2
    1. Advertising

  3. >
    > Why doesn't m get the implicit self parameter in the self.method()
    > call? How would I make it a proper member of the class, so that a
    > self.method() call would work with the above "m" function?


    Use new.instancemethod:

    import new

    class Test:
    def __init__(self, method):
    self.m = new.instancemethod(method, self, Test)

    def m(self):
    print self

    Test(m).m()


    --
    Regards,

    Diez B. Roggisch
    Diez B. Roggisch, Jan 28, 2005
    #3
  4. Bill Mill

    Kamilche Guest

    I see what you're attempting to do. However, your code, if it DID run,
    would result in a method being added to the object, not the object's
    class! Modify the class itself, not the object, as follows:

    |class Test:
    | def __init__(self):
    | self.method()
    |
    |def m(self):
    | print self
    |
    |setattr(Test, 'method', m)
    |Test()
    Kamilche, Jan 28, 2005
    #4
  5. Bill Mill

    Hans Nowak Guest

    Bill Mill wrote:
    > Hello all,
    >
    > I have a misunderstanding about dynamic class methods. I don't expect
    > this behavior:
    >
    > In [2]: class test:
    > ...: def __init__(self, method):
    > ...: self.method = method
    > ...: self.method()
    > ...:
    >
    > In [3]: def m(self): print self
    > ...:

    [...]
    >
    > TypeError: m() takes exactly 1 argument (0 given)
    > -----------------------------------------------------------------------------
    >
    > Why doesn't m get the implicit self parameter in the self.method()
    > call? How would I make it a proper member of the class, so that a
    > self.method() call would work with the above "m" function?


    m is a function. When you assign it to self.method, it's still a
    function. You don't create a new method that way; all you have is a new
    attribute called 'method' containing the function.

    To add m as a new method to the *class*, do this:

    >>> class test:

    .... def __init__(self, method):
    .... self.__class__.method = method
    .... self.method()
    ....
    >>> def m(self): print self

    ....
    >>> test(m)

    <__main__.test instance at 0x0192ED78>
    <__main__.test instance at 0x0192ED78>
    >>>


    To add m as a new method to the *instance*, use new.instancemethod, as
    Diez B. Roggisch already pointed out.

    HTH,

    --
    Hans Nowak
    http://zephyrfalcon.org/
    Hans Nowak, Jan 28, 2005
    #5
  6. Bill Mill

    Bill Mill Guest

    Diez,

    On Fri, 28 Jan 2005 16:57:37 +0100, Diez B. Roggisch <> wrote:
    > >
    > > Why doesn't m get the implicit self parameter in the self.method()
    > > call? How would I make it a proper member of the class, so that a
    > > self.method() call would work with the above "m" function?

    >
    > Use new.instancemethod:
    >
    > import new
    >
    > class Test:
    > def __init__(self, method):
    > self.m = new.instancemethod(method, self, Test)
    >


    Beautiful! thank you very much. Looking into the "new" module in
    python 2.4, that's equivalent to:

    self.m = type(self.__init__)(method, self, Test)

    I didn't know that you could call types to create another type.

    Peace
    Bill Mill
    bill.mill at gmail.com
    Bill Mill, Jan 28, 2005
    #6
  7. Bill Mill

    Bill Mill Guest

    Hans,


    On Fri, 28 Jan 2005 11:09:16 -0500, Hans Nowak <> wrote:
    <snip>
    >
    > m is a function. When you assign it to self.method, it's still a
    > function. You don't create a new method that way; all you have is a new
    > attribute called 'method' containing the function.
    >


    I figured as much; I just didn't know how to add it as a method.

    > To add m as a new method to the *class*, do this:
    >
    > >>> class test:

    > ... def __init__(self, method):
    > ... self.__class__.method = method
    > ... self.method()
    > ...
    > >>> def m(self): print self

    > ...
    > >>> test(m)

    > <__main__.test instance at 0x0192ED78>
    > <__main__.test instance at 0x0192ED78>


    When I run it, I only get one call to m, which is how I would expect
    python to work; I assume the double printing here is a typo?

    > >>>

    >
    > To add m as a new method to the *instance*, use new.instancemethod, as
    > Diez B. Roggisch already pointed out.
    >


    Thanks, you helped me understand it a lot.

    Peace
    Bill Mill
    bill.mill at gmail.com
    Bill Mill, Jan 28, 2005
    #7
  8. Bill Mill

    Bill Mill Guest

    Kamilche,


    On Fri, 28 Jan 2005 08:10:07 -0800 (PST), Kamilche
    <> wrote:
    > I see what you're attempting to do. However, your code, if it DID run,
    > would result in a method being added to the object, not the object's
    > class! Modify the class itself, not the object, as follows:
    >
    > |class Test:
    > | def __init__(self):
    > | self.method()
    > |
    > |def m(self):
    > | print self
    > |
    > |setattr(Test, 'method', m)
    > |Test()
    >


    beautiful; so this appears to be equivalent to the __class__ method
    that Hans suggested.

    Thanks a lot.

    Peace
    Bill Mill
    bill.mill at gmail.com

    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
    Bill Mill, Jan 28, 2005
    #8
  9. Bill Mill

    Hans Nowak Guest

    Bill Mill wrote:

    > On Fri, 28 Jan 2005 11:09:16 -0500, Hans Nowak <> wrote:
    > <snip>
    >
    >>To add m as a new method to the *class*, do this:
    >>
    >> >>> class test:

    >>... def __init__(self, method):
    >>... self.__class__.method = method
    >>... self.method()
    >>...
    >> >>> def m(self): print self

    >>...
    >> >>> test(m)

    >><__main__.test instance at 0x0192ED78>
    >><__main__.test instance at 0x0192ED78>

    >
    >
    > When I run it, I only get one call to m, which is how I would expect
    > python to work; I assume the double printing here is a typo?


    Actually, no. I'm using the interactive interpreter, so doing test(m)
    results in two lines: the first one is printed by m, the second one is
    the __repr__ of the test instance that was created, displayed by the
    interpreter. Compare:

    >>> x = test(m)

    <__main__.test instance at 0x0192ED78>
    >>> x

    <__main__.test instance at 0x0192ED78>

    --
    Hans Nowak
    http://zephyrfalcon.org/
    Hans Nowak, Jan 28, 2005
    #9
  10. Bill Mill

    Bill Mill Guest

    On Fri, 28 Jan 2005 11:59:50 -0500, Hans Nowak <> wrote:
    > Bill Mill wrote:
    >
    > > On Fri, 28 Jan 2005 11:09:16 -0500, Hans Nowak <> wrote:
    > > <snip>
    > >
    > >>To add m as a new method to the *class*, do this:
    > >>
    > >> >>> class test:
    > >>... def __init__(self, method):
    > >>... self.__class__.method = method
    > >>... self.method()
    > >>...
    > >> >>> def m(self): print self
    > >>...
    > >> >>> test(m)
    > >><__main__.test instance at 0x0192ED78>
    > >><__main__.test instance at 0x0192ED78>

    > >
    > >
    > > When I run it, I only get one call to m, which is how I would expect
    > > python to work; I assume the double printing here is a typo?

    >
    > Actually, no. I'm using the interactive interpreter, so doing test(m)
    > results in two lines: the first one is printed by m, the second one is
    > the __repr__ of the test instance that was created, displayed by the
    > interpreter. Compare:
    >
    > >>> x = test(m)

    > <__main__.test instance at 0x0192ED78>
    > >>> x

    > <__main__.test instance at 0x0192ED78>
    >


    d'oh; that's how I ran it. Thanks a lot.

    > --
    > Hans Nowak
    > http://zephyrfalcon.org/
    >
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
    Bill Mill, Jan 28, 2005
    #10
  11. Bill Mill

    Craig Ringer Guest

    On Fri, 2005-01-28 at 11:17 -0500, Bill Mill wrote:

    > Beautiful! thank you very much. Looking into the "new" module in
    > python 2.4, that's equivalent to:
    >
    > self.m = type(self.__init__)(method, self, Test)
    >
    > I didn't know that you could call types to create another type.


    Well, a type is essentially a class (in the OOP sense, not the python-
    specific classobj sense). You can call a type or class to create an
    instance of that class or type. Here, you call the 'instancemethod' type
    to create an instance of type 'instancemethod'. Makes sense ... in
    hindsight.

    --
    Craig Ringer
    Craig Ringer, Jan 28, 2005
    #11
  12. Bill Mill

    Terry Reedy Guest

    "Kamilche" <> wrote in message
    news:...
    >I see what you're attempting to do. However, your code, if it DID run,
    > would result in a method being added to the object, not the object's
    > class! Modify the class itself, not the object, as follows:
    >
    > |class Test:
    > | def __init__(self):
    > | self.method()
    > |
    > |def m(self):
    > | print self
    > |
    > |setattr(Test, 'method', m)


    # this is a longwinded way to say
    Test.method = m

    setattr is for when you do *not* know the attribute name at coding time but
    will have it in a string at run time, as in

    methodname = 'method'
    .......# some time later
    setattr(Test, methodname, m)

    Sometime Python makes things easier than people are initially willing to
    believe ;-)

    > |Test()


    Terry J. Reedy
    Terry Reedy, Jan 28, 2005
    #12
  13. Bill Mill

    Bill Mill Guest

    On Fri, 28 Jan 2005 14:41:16 -0500, Terry Reedy <> wrote:
    >
    > "Kamilche" <> wrote in message
    > news:...
    > >I see what you're attempting to do. However, your code, if it DID run,
    > > would result in a method being added to the object, not the object's
    > > class! Modify the class itself, not the object, as follows:
    > >
    > > |class Test:
    > > | def __init__(self):
    > > | self.method()
    > > |
    > > |def m(self):
    > > | print self
    > > |
    > > |setattr(Test, 'method', m)

    >
    > # this is a longwinded way to say
    > Test.method = m


    That is the blindingly simple method that I wanted. I didn't know
    before that I wanted it, but I'm sure of it now. Thank you very much,
    terry.

    >
    > setattr is for when you do *not* know the attribute name at coding time but
    > will have it in a string at run time, as in
    >
    > methodname = 'method'
    > ......# some time later
    > setattr(Test, methodname, m)
    >
    > Sometime Python makes things easier than people are initially willing to
    > believe ;-)


    I felt like there had to be a simpler solution.

    Peace
    Bill Mill
    bill.mill at gmail.com
    Bill Mill, Jan 28, 2005
    #13
  14. Bill Mill <> wrote:
    ...
    > > class Test:
    > > def __init__(self, method):
    > > self.m = new.instancemethod(method, self, Test)

    >
    > Beautiful! thank you very much. Looking into the "new" module in
    > python 2.4, that's equivalent to:
    >
    > self.m = type(self.__init__)(method, self, Test)


    Another approach with the same result is to exploit the fact that a
    function is a descriptor:

    self.m = method.__get__(self, Test)


    Alex
    Alex Martelli, Jan 29, 2005
    #14
  15. On Sat, 29 Jan 2005 10:24:27 +0100, rumours say that
    (Alex Martelli) might have written:

    >Bill Mill <> wrote:
    > ...
    >> > class Test:
    >> > def __init__(self, method):
    >> > self.m = new.instancemethod(method, self, Test)

    >>
    >> Beautiful! thank you very much. Looking into the "new" module in
    >> python 2.4, that's equivalent to:
    >>
    >> self.m = type(self.__init__)(method, self, Test)


    >Another approach with the same result is to exploit the fact that a
    >function is a descriptor:
    >
    >self.m = method.__get__(self, Test)


    Almost true; not all builtin functions are descriptors though.

    ..>> import new
    ..>> f= new.instancemethod(divmod, 7, object)
    ..>> map(f, range(1,10,2))
    [(7, 0), (2, 1), (1, 2), (1, 0), (0, 7)]
    ..>> f= divmod.__get__(7)

    Traceback (most recent call last):
    File "<pyshell#16>", line 1, in -toplevel-
    f= divmod.__get__(7)
    AttributeError: 'builtin_function_or_method' object has no attribute
    '__get__'

    I didn't run an extensive test, but it's possible that all builtin
    functions are not descriptors.
    --
    TZOTZIOY, I speak England very best.
    "Be strict when sending and tolerant when receiving." (from RFC1958)
    I really should keep that in mind when talking with people, actually...
    Christos TZOTZIOY Georgiou, Jan 31, 2005
    #15
  16. Christos TZOTZIOY Georgiou <> wrote:
    ...
    > >> > class Test:
    > >> > def __init__(self, method):
    > >> > self.m = new.instancemethod(method, self, Test)

    ...
    > >self.m = method.__get__(self, Test)

    >
    > Almost true; not all builtin functions are descriptors though.

    ...
    > AttributeError: 'builtin_function_or_method' object has no attribute
    > '__get__'
    >
    > I didn't run an extensive test, but it's possible that all builtin
    > functions are not descriptors.


    Indeed, many callables (builtin-functions, types, ...) are not
    descriptors, so you can't call __get__ on them. But then, many
    descriptors (statimethods, classmethods, ...) are not callable, so you
    can't pass them as the first argument to instancemethod. Not having any
    indication of what the author of class Test means to pass in as
    "method", it's not clear whether Test(divmod) or Test(staticmethod(foo))
    is more likely to be of interest to them as a use case. If ``method''
    is a function, which is both a descriptor AND callable, either approach
    works; otherwise, one has to pick an approach, or try both approaches
    with a try/except.


    Alex
    Alex Martelli, Jan 31, 2005
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark Hobley

    vec - a misunderstanding

    Mark Hobley, Mar 18, 2006, in forum: Perl
    Replies:
    1
    Views:
    2,600
    John Bokma
    Mar 18, 2006
  2. Kevin Spencer

    Re: Class property misunderstanding

    Kevin Spencer, Jun 26, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    824
    Kevin Spencer
    Jun 26, 2003
  3. Philip Tripp

    View State Misunderstanding

    Philip Tripp, Jul 24, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    518
    Philip Tripp
    Jul 26, 2004
  4. Oltmans
    Replies:
    6
    Views:
    327
    Terry Reedy
    Mar 11, 2009
  5. Kenneth McDonald
    Replies:
    5
    Views:
    301
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page