Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing object variables - a Java approach, a Python approach?

Tags:

python

I have an object that needs to have some 4-5 values passed to it. To illustrate:

class Swoosh():
    spam = ''
    eggs = ''
    swallow = ''
    coconut = ''

    [... methods ...]

Right now, the way to use Swoosh is:

swoosh = Swoosh()
swoosh.set_spam('Spam!')
swoosh.set_eggs('Eggs!')
swoosh.set_swallow('Swallow!')
swoosh.set_coconut('Migrated.')

I'm having doubts whether this is Pythonic or is this too much Java influence. Or is it just necessary? Also, in case you're wondering why I'm using setters instead of simply accessing the object variables - some basic validation has to be done there, hence the set_ methods.

I reckon I could provide a different way to initialize a Swoosh - provide an __init__() that would accept a dict/list?

Anyway, I'm just looking for help/advice from someone more experienced with this stuff.

Thanks in advance for any input on this.

like image 334
maligree Avatar asked Jul 01 '11 11:07

maligree


1 Answers

Firstly you're using old style classes. You really, really should be using new style classes that inherit from object:

class Swoosh(object):

Defining an __init__ method that takes arguments is definitely the Pythonic way of doing things:

def __init__(self,spam,eggs,swallow,coconut):
    self.spam = spam
    self.eggs = eggs
    self.swallow = swallow
    self.coconut = coconut

This would allow you to do:

s = Swoosh('Spam!','Eggs','Swallow','Migrated')

Like any other Python function the __init__ method can have default values for arguments, e.g.

def __init__(self,spam,eggs,swallow,coconut='Migrated.'):
        self.spam = spam
        self.eggs = eggs
        self.swallow = swallow
        self.coconut = coconut

If you want to validate attributes as they're set you should use standard property attributes rather than creating your own setters. If you do it this way you can use myobject.spam in your code like with an ordinary attribute but your setter method is still run.

For example:

@property
def spam(self):
    """I'm the 'spam' property."""
    return self._spam

@spam.setter
def spam(self, value):
    if not value.endswith("!"):
        raise ValueError("spam must end with !")
    # Store the value in "private" _spam attribute
    self._spam = value

@spam.deleter
def spam(self):
    del self._spam

Note: property will not work unless you're using new-style classes as described above.

In your example you have:

class Swoosh():
    spam = ''
    eggs = ''
    swallow = ''
    coconut = ''

This is often presented as a quick way of setting defaults for attributes for an object. It's fine but you need to understand what is actually happening. What's going on is that you're setting attributes on the class. If an object doesn't have an attribute Python will look to see if it's defined on the class and return the value from there (as this is what you want for methods).

If you want to set default values for object attributes you're much better off setting default values for the arguments in __init__ as described above rather than using class attributes.

like image 133
Dave Webb Avatar answered Oct 15 '22 14:10

Dave Webb