Welcome, guest | Sign In | My Account | Store | Cart

I needed to define a universal class with some methods known at construction time. It has to be possible to check whether a method exists in the instance.

Python, 26 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class C:
   def __init__(self, methodNames):
      for name in methodNames:
         setattr(C, name, self.methodClosure(name))
   def methodClosure(self, name):
      def method(*args, **kwargs):
         print name, args, kwargs
      return method

# test code
if __name__ == "__main__":
   c = C(['m1'])
   print hasattr(c,'m1')
   print hasattr(c,'m2')
   c.m1(0, a=10)
   c.m2(0, a=10)


# output of test code:
# True
# False
# m1 (<__main__.C instance at 0x12345678>, 0) {'a': 10}
# Traceback (most recent call last):
#   File "test.py", line 16, in ?
#     c.m2(0, a=10)
# AttributeError: C instance has no attribute 'm2'

I had a similar problem as the problem presented in recipe 307618 (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/307618). This recipe was very helpful in finding the solution to my problem. My problem was different with respect to two aspects: 1. I know the methods the class has at construction time. 2. I need a class with methods for a set of names, but other methods must not exist. Reason: Another module checks whether some method to be called exists in the corresponding instance. The latter aspect required to modify recipe 307618. I applied the same trick, one method returns a closure with another method. Using setattr it is possible to assign a name to the method. This is done in the constructor. After having constructed the instance of class C in the example, it is possible to check the existence of a method in advance using hasattr.

1 comment

Steven Bethard 19 years, 1 month ago  # | flag

setting methods for all instances. By putting the setattr code in __init__, you change all instances with each new instantiation of C:

py> class C:
...    def __init__(self, methodNames):
...       for name in methodNames:
...          setattr(C, name, self.methodClosure(name))
...    def methodClosure(self, name):
...       def method(*args, **kwargs):
...          print name, args, kwargs
...       return method
...
py> c1 = C(['m1'])
py> c2 = C(['m2'])
py> hasattr(c1, 'm2')
True
py> hasattr(c2, 'm1')
True

Is this intentional? Seems like maybe you want a separate type for each set of methods instead. Perhaps something like:

py> def c_factory(method_names):
...     def method_closure(name):
...         def method(*args, **kwargs):
...             print name, args, kwargs
...         return method
...     class C(object):
...         pass # define methods here if necessary
...     for name in method_names:
...         setattr(C, name, method_closure(name))
...     return C
...
py> C = c_factory(['m1'])
py> c1 = C()
py> C = c_factory(['m2'])
py> c2 = C()
py> hasattr(c1, 'm2')
False
py> hasattr(c2, 'm1')
False
Created by Jens Liebehenschel on Mon, 28 Feb 2005 (PSF)
Python recipes (4591)
Jens Liebehenschel's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks