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

Sometimes your class design warrants the definition of multiple construction methods for a class, such as rebuilding from a serialized form vs. normal internal construction with explicit parameters. This recipe gives an example of using class level methods to create such constructors.

Python, 31 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
27
28
29
30
31
# example class with ordinary constructor and class-level factory method
class Color:
  """class for specifying colors while drawing BitMap elements"""
  def __init__( self, r=0, g=0, b=0 ):
    self.red = r
    self.grn = g
    self.blu = b
    
  def __str__( self ):
    return "R:%d G:%d B:%d" % (self.red, self.grn, self.blu )
  
  def toLong( self ):
    return ( long(self.blu)       ) + \
           ( long(self.grn) <<  8 ) + \
           ( long(self.red) << 16 )

  def fromLong( cls, lng ):
    blu = lng & 0xff
    lng = lng >> 8
    grn = lng & 0xff
    lng = lng >> 8
    red = lng & 0xff
    return cls( red, grn, blu )
  fromLong = classmethod( fromLong )


c = Color( 255, 0, 0 ) # red
print c
colorInt = c.toLong()
print colorInt
print Color.fromLong( colorInt )

This is sort of a C++-ish technique (but I've seen it in Smalltalk too), and it requires using a small wrapper class to convert the defined instance function into a class function, but I think it works well.

This is a simple example of a Color class with an ordinary initializer taking 3 integers, each for red, green, and blue, and then a class level factory method named fromLong that takes a single long integer (such as might be found in a bitmap palette).

6 comments

mike mazurek 18 years, 2 months ago  # | flag

Why not use static method for fromLong. I don't understand the utility of you wrapper class...

Paul McGuire (author) 18 years, 2 months ago  # | flag

Legacy workarounds never die, they just keep cropping up in new code... I borrowed this wrapper class from another recipe, out of ignorance of "recent" Python features. "classmethod" would work just fine, I just didn't know it existed.

Paul McGuire (author) 18 years, 2 months ago  # | flag

So corrected... (and I removed the extraneous commentary for the now unnecessary class)

Paul McGuire (author) 18 years, 2 months ago  # | flag

Ooops, still wrong... Not "classmethod" I meant "staticmethod". No reason to involve the class.

Georg Brandl 16 years, 5 months ago  # | flag

Why not classmethod? I think it's even better with classmethod. Your initializer then does not break when you rename the class.

Paul McGuire (author) 13 years, 4 months ago  # | flag

To mike mazurek: This is not a wrapper class, it is just a small excerpt of a larger class, illustrating two different construction interfaces. And just defining a global method "fromLong" doesn't help the user of this class very much - scoping as a staticmethod or classmethod within the Color class helps maintain the connection between this method and the class for which it acts as a factory method. The user's code calling a global method:

background_color = fromLong(save_color_value)

is more self-explanatory when included with the Color class:

background_color = Color.fromLong(save_color_value)

To Goerg Brandl: Point taken, changed back to a classmethod.

Created by Paul McGuire on Thu, 18 Sep 2003 (PSF)
Python recipes (4591)
Paul McGuire's recipes (5)

Required Modules

  • (none specified)

Other Information and Tasks