By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,587 Members | 1,711 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,587 IT Pros & Developers. It's quick & easy.

More __init__ methods

P: n/a
Hi,
I know there can be only one __init__ method (at least, I think).

Often I need an object to be created in different ways, for example
passing a string as argument, or an integer, or another object. To
achieve this I put the default value of the arguments to None and then
I some if...elif inside the __init__.

Is this a good practice? It actually works, but sometimes I think that
in this way the __init__ method can become too complicated, for
example when an object can be created using more than one argument and
in different combinations.

Hope my doubt is clear.
Nov 6 '08 #1
Share this Question
Share on Google+
18 Replies


P: n/a
On Thu, 06 Nov 2008 16:49:08 +0100, Mr.SpOOn wrote:
I know there can be only one __init__ method (at least, I think).

Often I need an object to be created in different ways, for example
passing a string as argument, or an integer, or another object. To
achieve this I put the default value of the arguments to None and then I
some if...elif inside the __init__.

Is this a good practice? It actually works, but sometimes I think that
in this way the __init__ method can become too complicated, for example
when an object can be created using more than one argument and in
different combinations.
I'm usually using `classmethod()`\s as alternative "constructors" then.
For example:

class A(object):
def __init__(self, a, b, c):
self.a = a
# ...

@classmethod
def from_string(cls, s):
# ...
return cls(a, b, c)

Ciao,
Marc 'BlackJack' Rintsch
Nov 6 '08 #2

P: n/a
On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
class A(object):
def __init__(self, a, b, c):
self.a = a
# ...

@classmethod
def from_string(cls, s):
# ...
return cls(a, b, c)
Thanks.
I think it's time to study decorators.
Nov 6 '08 #3

P: n/a
Mr.SpOOn wrote:
On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
>class A(object):
def __init__(self, a, b, c):
self.a = a
# ...

@classmethod
def from_string(cls, s):
# ...
return cls(a, b, c)

Thanks.
I think it's time to study decorators.

While that's no bad thing, you don't really need to do
that simply to understand these examples: they're just
saying "do whatever you need to to make these method
class methods, not instance methods".

TJG
Nov 6 '08 #4

P: n/a
On Thu, Nov 6, 2008 at 7:44 PM, Tim Golden <ma**@timgolden.me.ukwrote:
While that's no bad thing, you don't really need to do
that simply to understand these examples: they're just
saying "do whatever you need to to make these method
class methods, not instance methods".
Yes.

I think this changes the design of my class.

I mean, till now I had something like:

class foo:
def __init__(self, string=None, integer=None, someinstance=None):
self.a = 0
self.b = 0

if string:
# do something to calculate "a and b"
elif integer:
# do something else to calculate "a and b"
...
...

So I used different methods to calculate the same variables.

Now I must pass a and b to the main constructor and calculate them in
the classmethods.

class foo:
def __init__(self, a, b):
self.a = a
self.b = b

@classmethod
def from_string(self, ..):
...
...

What I mean is: I can't use anymore __init__ as the default
constructor, but I always have to specify the way I'm creating my
object. Am I right? I'm asking just to be sure I have understood.
Nov 6 '08 #5

P: n/a
Mr.SpOOn wrote:
On Thu, Nov 6, 2008 at 7:44 PM, Tim Golden <ma**@timgolden.me.ukwrote:
>While that's no bad thing, you don't really need to do
that simply to understand these examples: they're just
saying "do whatever you need to to make these method
class methods, not instance methods".

Yes.

I think this changes the design of my class.

I mean, till now I had something like:

class foo:
def __init__(self, string=None, integer=None, someinstance=None):
self.a = 0
self.b = 0

if string:
# do something to calculate "a and b"
elif integer:
# do something else to calculate "a and b"
...
...

So I used different methods to calculate the same variables.

Now I must pass a and b to the main constructor and calculate them in
the classmethods.

class foo:
def __init__(self, a, b):
self.a = a
self.b = b

@classmethod
def from_string(self, ..):
...
...

What I mean is: I can't use anymore __init__ as the default
constructor, but I always have to specify the way I'm creating my
object. Am I right? I'm asking just to be sure I have understood.
Is there some reason not to use something like the following?

class foo:
def __init__(self, val):
self.a = 0
self.b = 0

if isinstance(val, basestring):
#
# do something to calculate "a and b"
#

elif isintance(val, int):
#
# do something else to calculate "a and b"
#

elif isinstance(val, someinstance)
#
# do something else to calculate "a and b"
#

else:
#
# Don't know what to do with unknown type
#
raise ValueError()

-Larry
Nov 6 '08 #6

P: n/a
Mr.SpOOn <mr********@gmail.comwrites:
On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
class A(object):
def __init__(self, a, b, c):
self.a = a
# ...

@classmethod
def from_string(cls, s):
# ...
return cls(a, b, c)

Thanks.
I think it's time to study decorators.
Studying decorators is a good idea, but in this instance it's not
necessary. The above is merely using decorator syntax to apply the
‘classmethod’ type to a function.

All you need to know to understand the above is that it will have
essentially the same result as:

class A(object):
# ...

def _from_string(cls, s):
# ...
return cls(a, b, c)
from_string = classmethod(_from_string)
del _from_string

without the intermediate binding of the ‘_from_string’ name.

--
\ “The best way to get information on Usenet is not to ask a |
`\ question, but to post the wrong information.” —Aahz |
_o__) |
Ben Finney
Nov 6 '08 #7

P: n/a
Ben Finney <bi****************@benfinney.id.auwrites:
[...]
All you need to know to understand the above is that it will have
essentially the same result as:

class A(object):
# ...

def _from_string(cls, s):
# ...
return cls(a, b, c)
from_string = classmethod(_from_string)
del _from_string

without the intermediate binding of the ‘_from_string’ name.
So you mean it is the same as:

class A(object):
# ...

def from_string(cls, s):
# ...
from_string = classmethod(from_string)

:)

--
Arnaud
Nov 6 '08 #8

P: n/a
Mr.SpOOn <mr********@gmail.comwrites:
class foo:
def __init__(self, a, b):
self.a = a
self.b = b

@classmethod
def from_string(self, ..):
...
...

What I mean is: I can't use anymore __init__ as the default
constructor, but I always have to specify the way I'm creating my
object. Am I right? I'm asking just to be sure I have understood.
Yes, that's what the above design requires. You code ‘foo.__init__’
for the common use case, and create ‘foo.from_bar’ classmethod factory
functions for other cases. The caller then needs to specify which case
is being requested.

--
\ “I was in the first submarine. Instead of a periscope, they had |
`\ a kaleidoscope. ‘We're surrounded.’” —Steven Wright |
_o__) |
Ben Finney
Nov 6 '08 #9

P: n/a
Larry Bates <la*********@vitalEsafe.comwrites:
Is there some reason not to use something like the following?

class foo:
def __init__(self, val):
self.a = 0
self.b = 0

if isinstance(val, basestring):
#
# do something to calculate "a and b"
#

elif isintance(val, int):
#
# do something else to calculate "a and b"
#

elif isinstance(val, someinstance)
#
# do something else to calculate "a and b"
#

else:
#
# Don't know what to do with unknown type
#
raise ValueError()
Yes, the main reason is that it kills duck typing. The initialiser
should *use* the parameters passed, and allow exceptions to propagate
back to the caller if the parameters don't behave as expected.

Another good reason to avoid the above style is that it's far too
complex. Different behaviours should be in different functions.

--
\ “Friendship is born at that moment when one person says to |
`\ another, ‘What! You too? I thought I was the only one!’” —C.S. |
_o__) Lewis |
Ben Finney
Nov 6 '08 #10

P: n/a
Arnaud Delobelle <ar*****@googlemail.comwrites:
Ben Finney <bi****************@benfinney.id.auwrites:
[...]
All you need to know to understand the above is that it will have
essentially the same result as:

class A(object):
# ...

def _from_string(cls, s):
# ...
return cls(a, b, c)
from_string = classmethod(_from_string)
del _from_string

without the intermediate binding of the ‘_from_string’ name.

So you mean it is the same as:

class A(object):
# ...

def from_string(cls, s):
# ...
from_string = classmethod(from_string)
Sure, but I figured I would make the steps more explicit.

--
\ “Writing a book is like washing an elephant: there no good |
`\ place to begin or end, and it's hard to keep track of what |
_o__) you've already covered.” —anonymous |
Ben Finney
Nov 6 '08 #11

P: n/a
On Thu, Nov 6, 2008 at 11:00 PM, Ben Finney
<bi****************@benfinney.id.auwrote:
Yes, the main reason is that it kills duck typing. The initialiser
should *use* the parameters passed, and allow exceptions to propagate
back to the caller if the parameters don't behave as expected.

Another good reason to avoid the above style is that it's far too
complex. Different behaviours should be in different functions.
Ok, thanks.
Is there a good book or source where I can read about such topics?
Core Python Programming doesn't seem to talk about decorators. Maybe
it's too old?
Nov 7 '08 #12

P: n/a
On Thu, Nov 6, 2008 at 11:00 PM, Ben Finney
<bi****************@benfinney.id.auwrote:
Yes, the main reason is that it kills duck typing. The initialiser
should *use* the parameters passed, and allow exceptions to propagate
back to the caller if the parameters don't behave as expected.

Another good reason to avoid the above style is that it's far too
complex. Different behaviours should be in different functions.
Sorry for double posting, but in this way it seems I can't use
instance method inside the classmethod. Probably it is the right
behavior, but if I use this @classmethod style to simplify the
__init__ method, now I should move code from instance method inside
the classmethods.

In this way I'm kinda mixing things. I mean, if to construct an object
I have to use different methods, what can I do? Or am I missing
something, as usual?
Nov 7 '08 #13

P: n/a
Mr.SpOOn <mr********@gmail.comwrote:
Now I must pass a and b to the main constructor and calculate them in
the classmethods.

class foo:
def __init__(self, a, b):
self.a = a
self.b = b

@classmethod
def from_string(self, ..):
...
...

What I mean is: I can't use anymore __init__ as the default
constructor, but I always have to specify the way I'm creating my
object. Am I right? I'm asking just to be sure I have understood.
There is a really big advantage to being explicit in this situation: you no
longer have to make sure that all your constructors use a unique set of
types. Consider:

class Location(object):
def __init__(self, lat, long): ...

@classmethod
def from_city(name): ...

@classmethod
def from_postcode(name): ...

'from_string' is a bad name here for your factory method: you should try to
make it clear what sort of string is expected.

--
Duncan Booth http://kupuguy.blogspot.com
Nov 7 '08 #14

P: n/a
On Fri, 07 Nov 2008 15:16:29 +0000, Duncan Booth wrote:
'from_string' is a bad name here for your factory method: you should try
to make it clear what sort of string is expected.
When I use a `from_string()` factory I usually make sure it can parse the
`str()` form of that type or that there is a `to_string()` as reverse
operation.

Ciao,
Marc 'BlackJack' Rintsch
Nov 7 '08 #15

P: n/a
On Fri, Nov 7, 2008 at 4:16 PM, Duncan Booth
<du**********@invalid.invalidwrote:
There is a really big advantage to being explicit in this situation: you no
longer have to make sure that all your constructors use a unique set of
types. Consider:

class Location(object):
def __init__(self, lat, long): ...

@classmethod
def from_city(name): ...

@classmethod
def from_postcode(name): ...

'from_string' is a bad name here for your factory method: you should try to
make it clear what sort of string is expected.
Yes, that's what I was going to do.
But, for example, I have a parse method to create such object from a
string. So I need to call this method to actually create the object.
Now I must put the code of the parse method into the @classmethod
constructor.

What if I need the parse method to be called in other parts of the program?
Nov 7 '08 #16

P: n/a
On Fri, 07 Nov 2008 17:23:21 +0100, Mr.SpOOn wrote:
On Fri, Nov 7, 2008 at 4:16 PM, Duncan Booth
<du**********@invalid.invalidwrote:
>There is a really big advantage to being explicit in this situation:
you no longer have to make sure that all your constructors use a unique
set of types. Consider:

class Location(object):
def __init__(self, lat, long): ...

@classmethod
def from_city(name): ...

@classmethod
def from_postcode(name): ...

'from_string' is a bad name here for your factory method: you should
try to make it clear what sort of string is expected.

Yes, that's what I was going to do.
But, for example, I have a parse method to create such object from a
string. So I need to call this method to actually create the object. Now
I must put the code of the parse method into the @classmethod
constructor.
You can still spread it over other `classmethod()`\s or `staticmethod()`s
or even plain functions at module level.
What if I need the parse method to be called in other parts of the
program?
I don't understand!? Then you call it from those other parts.

Ciao,
Marc 'BlackJack' Rintsch
Nov 7 '08 #17

P: n/a
Duncan Booth wrote:
Mr.SpOOn <mr********@gmail.comwrote:
>Now I must pass a and b to the main constructor and calculate them in
the classmethods.

class foo:
def __init__(self, a, b):
self.a = a
self.b = b

@classmethod
def from_string(self, ..):
...
...

What I mean is: I can't use anymore __init__ as the default
constructor, but I always have to specify the way I'm creating my
object. Am I right? I'm asking just to be sure I have understood.

There is a really big advantage to being explicit in this situation: you no
longer have to make sure that all your constructors use a unique set of
types. Consider:

class Location(object):
def __init__(self, lat, long): ...

@classmethod
def from_city(name): ...

@classmethod
def from_postcode(name): ...

'from_string' is a bad name here for your factory method: you should try to
make it clear what sort of string is expected.
One built-in model for .__init__ + .from_data is dict. __init__ can
take either one iterable or several keywords. In either case, it gets a
set of key:value pairs. .from_keys take a set of keys and an optional
value to override None that is matched with all keys.

Nov 7 '08 #18

P: n/a
On Fri, Nov 7, 2008 at 7:02 PM, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
>What if I need the parse method to be called in other parts of the
program?

I don't understand!? Then you call it from those other parts.
Yes, you're right. Don't know why, but I was thinking to use
@classmethod just for the alternative constructors.
Nov 7 '08 #19

This discussion thread is closed

Replies have been disabled for this discussion.