unexpected behaviour in class variables

Andrew Dalke dalke at acm.org
Mon Jun 26 13:29:38 EDT 2000


Hello,

I found an unexpected behaviour in which C-based functions as class
attributes are treated different than user-defined (python-based) functions.
This case is documented, so I guess it's my misunderstanding.  However,
the docs also say the behaviour should occur for instance attributes and
it doesn't.  A detailed description is below.

I have a wrapper around a set of C-based extension functions.  Objects
in the C library must be freed when no longer needed, so I wrote a class
which looks like:

import dayswig_python
class smart_ptr:
  dt_dealloc = dayswig_python.dt_dealloc
  def __init__(self, handle):
    self.handle = handle
  def __del__(self):
    self.dt_dealloc(self.handle)

I keep a reference to dt_dealloc in the class namespace because the order
of module cleanup is not defined, and it is possible that dayswig_python
is cleaned up before this smart_ptr module.

This approach works fine, so long as dt_dealloc is not a user-defined
function (that it, it is an extension object in C rather than in Python).

I started writing a emulator dayswig_python.py file which implements just
enough of the extension library to be useful for testing.  Now my smart_ptr
class fails because it converts my user-defined dayswig_python.dt_dealloc
function into a method.  Here's an example:

import math
def eggs(x):
 pass

class Spam:
 builtin_func = math.cos
 def_func = eggs
 def p(self):
  print self.builtin_func
  print self.def_func
  print math.cos

>>> spam = Spam()
>>> spam.p()
<built-in function cos>
<method Spam.eggs of Spam instance at 1064060>
<built-in function cos>
>>> spam.builtin_func is math.cos
1
>>> spam.def_func is eggs
0

When the class attribute is a user-defined function, it is treated as a
member function.  When it is a function from an C extension, no conversion
occurs.

Looking in the manual I see this is documented:
> When a class attribute reference would yield a user-defined function
> object, it is transformed into an unbound user-defined method object
> (see above).

The "(see above)" says:
> User-defined method objects are created in two ways: when getting an
> attribute of a class that is a user-defined function object, or when
> getting an attributes of a class instance that is a user-defined function
> object.
and
> Also notice that this transformation only happens for user-defined
> functions; other callable objects (and all non-callable objects) are
> retrieved without transformation.

So my situation is the documented case of "getting an attribute of a
class that is a user-defined function object".  Don't know why this
must be the case -- is that an indication of how Python internally stores
member functions?

Note, however, that the other case of "getting an attribute [sic] of a
class instance that is a user-defined function object" is not the
implemented
behaviour!

import math

def eggs(x):
    return math.sin(x)

class Spam:
    def __init__(self):
        self.sin = eggs
        self.cos = math.cos

>>> spam = Spam()
>>> print spam.sin(0)
0.0
>>> print spam.cos(0)
1.0

As I read the documentation, spam.sin is an attribute of a class instance
and it is a user defined function, so it should be converted to a member
function.  But it isn't converted.

So:
  1) it is unexpected to me that class attributes which are user-defined
functions get coerced into member functions.  Can someone explain why that
is appropriate?  Not having the special case would be my (so far only)
Python3K wish :)

  2) The docs say class instance attributes which are user-defined functions
should be similarly coerced.  They do not appear to be coerced, so either
the implementation is wrong or the docs are wrong.  Could someone verify
that my interpretation is correct, so I can properly forward this to either
the bugs or the docs email?

Regarding my original problem, the fix is to turn the deallocator into:

  def __del__(self, dt_dealloc = dayswig_python.dt_dealloc):
    dt_dealloc(self.handle)

                    Andrew
                    dalke at acm.org






More information about the Python-list mailing list