frazman
frazman

Reputation: 33243

Python: flexible way to declare constructors

What is a clean way to declare multiple constructors for one class?

For example, let's say I have an Item class. One way to create an Item (for example is)

item = Item(product_id, name, description,price)

another way to do the same thing might

item = Item(otherItem)

And then another way to do this.. maybe in some cases I don't have the price so I want to pass just

item = Item(product_id, name,description)

and yet another case might be

item = Item(product_id,price)

The other question I have is: There are some private variables which might be initialized during runtime. Let's say I have some random variable itemCount and I want to keep a track of it internally.

How do I declare it that I dont have to put it in initialization mode, but rather, somewhere in the run time.. I can do something like

self._count +=1

Thanks

Upvotes: 2

Views: 657

Answers (3)

Matt Fenwick
Matt Fenwick

Reputation: 49085

You could use default arguments:

class Item(object):

  def __init__(self, product_id = None, name = None, description = None, price = None)
      ... implementation ...

You can substitute in any value you want for None, if the default value should be something different.

Example usage:

item1 = Item(product_id = 4, price = 13) # use the field name!
item2 = Item(name = "hammer", description = "used to belong to Thor")

For the copy constructor, item = Item(otherItem), @Raymond's suggestions of class methods and factory functions may be the most Pythonic way to go.


Update: here's a question about multiple constructors in Python. It also mentions using *args and **kwargs.

Upvotes: 1

Sven Marnach
Sven Marnach

Reputation: 601609

Copying is usually done by a copy() method on instances instead of by providing a "copy constructor", so it's

item = other_item.copy()

instead of

item = Item(other_item)

All the other constructor signatures you mentioned easily be handled by default arguments and keyword arguments:

def __init__(self, product_id, name=None, description=None, price=None):
    ...

If you want another constructor with completely different code, than a classmethod is the right approach -- see the answer by Raymond Hettinger.

Upvotes: 1

Raymond Hettinger
Raymond Hettinger

Reputation: 226316

The two most common approaches for providing multiple constructors are:

  1. class methods and
  2. factory functions

Here is an example taken from the standard library showing how collections.OrderedDict uses a classmethod to implement fromkeys() as an alternate class constructor:

@classmethod
def fromkeys(cls, iterable, value=None):
    '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
    If not specified, the value defaults to None.

    '''
    self = cls()
    for key in iterable:
        self[key] = value
    return self

As an example of the other common approach, here's a factory function used in symtable.py in the standard library:

class SymbolTableFactory:
    def __init__(self):
        self.__memo = weakref.WeakValueDictionary()

    def new(self, table, filename):
        if table.type == _symtable.TYPE_FUNCTION:
            return Function(table, filename)
        if table.type == _symtable.TYPE_CLASS:
            return Class(table, filename)
        return SymbolTable(table, filename)

Upvotes: 4

Related Questions