instance + classmethod question

Steven Bethard steven.bethard at gmail.com
Sun Dec 11 11:10:30 EST 2005


Laszlo Zsolt Nagy wrote:
> 
>  Hello,
> 
> Is it possible to tell, which instance was used to call the classmethod 
> that is currently running?
> 
[snip]
> 
> processor = SQLProcessors.StdOutProcessor() # Print to stdout
> PostgreSQLConnection.process_create_tables(processor,dbdef)  # This 
> sould create all tables, using the processor
> 
> processor = SQLProcessors.DirectProcessor(conn) # Execute directly
> conn.process_create_tables(processor,dbdef) # This should create 
> non-existing tables only, using the processor
> 
> Is this possible?

It looks like you want a method that accepts either a class or an 
instance.  I would typically create two methods, one for the class-based 
table-creating, and one for the instance-based table-creating.  However, 
if you *have* to do it this way, you can introduce your own descriptor 
which should give you the behavior you want::

 >>> class ClassOrInstanceMethod(object):
...     def __init__(self, func):
...         self.func = func
...         self.classfunc = classmethod(func)
...     def __get__(self, obj, objtype=None):
...         func = obj is None and self.classfunc or self.func
...         return func.__get__(obj, objtype)
...
 >>> class C(object):
...     @ClassOrInstanceMethod
...     def f(*args):
...         print args
...
 >>> C.f()
(<class '__main__.C'>,)
 >>> C().f()
(<__main__.C object at 0x00E73D90>,)

Basically, if the descriptor is called from a type (and thus ``obj is 
None``), we return a bound classmethod, and if the descriptor is called 
from an instance, we return a bound instance method.  Of course this now 
means you should write your code something like::

@ClassOrInstanceMethod
def process_create_tables(cls_or_self, processor, dbdef):
     ...

whose "cls_or_self" parameter gives me a bad code smell.  YMMV.

STeVe



More information about the Python-list mailing list