Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 object construction: which is the most Pythonic / the accepted way?

Having a background in Java, which is very verbose and strict, I find the ability to mutate Python objects as to give them with fields other than those presented to the constructor really "ugly".

Trying to accustom myself to a Pythonic way of thinking, I'm wondering how I should allow my objects to be constructed.

My instinct is to have to pass the fields at construction time, such as:

def __init__(self, foo, bar, baz=None):
    self.foo = foo
    self.bar = bar
    self.baz = baz

But that can become overly verbose and confusing with many fields to pass. To overcome this I assume the best method is to pass one dictionary to the constructor, from which the fields are extracted:

def __init__(self, field_map):
    self.foo = field_map["foo"]
    self.bar = field_map["bar"]
    self.baz = field_map["baz"] if baz in field_map else None

The other mechanism I can think of is to have the fields added elsewhere, such as:

class Blah(object):

    def __init__(self):
        pass

...

blah = Blah()
blah.foo = var1

But as that feels way too loose for me.

(I suppose the issue in my head is how I deal with interfaces in Python...)

So, to reiterate the question: How I should construct my objects in Python? Is there an accepted convention?

like image 900
Humphrey Bogart Avatar asked Feb 28 '10 23:02

Humphrey Bogart


People also ask

What is the method in Python?

A method is a function that “belongs to” an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have methods called append, insert, remove, sort, and so on.

What is a class in Python 3?

Class − A user-defined prototype for an object that defines a set of attributes that characterize any object of the class. The attributes are data members (class variables and instance variables) and methods, accessed via dot notation. Class variable − A variable that is shared by all instances of a class.

Why using class in Python?

Classes are great if you need to keep state, because they containerize data (variables) and behavior (methods) that act on that data and should logically be grouped together. This leads to code that is better organized (cleaner) and easier to reuse.

What is object in Python with example?

Python is an object-oriented programming language. Everything is in Python treated as an object, including variable, function, list, tuple, dictionary, set, etc. Every object belongs to its class. For example - An integer variable belongs to integer class.


2 Answers

The first you describe is very common. Some use the shorter

class Foo:
   def __init__(self, foo, bar):
       self.foo, self.bar = foo, bar

Your second approach isn't common, but a similar version is this:

class Thing:
   def __init__(self, **kwargs):
       self.something = kwargs['something']
       #..

which allows to create objects like

t = Thing(something=1)

This can be further modified to

class Thing:
   def __init__(self, **kwargs):
       self.__dict__.update(kwargs)

allowing

t = Thing(a=1, b=2, c=3)
print t.a, t.b, t.c # prints 1, 2, 3

As Debilski points out in the comments, the last method is a bit unsafe, you can add a list of accepted parameters like this:

class Thing:
    keywords = 'foo', 'bar', 'snafu', 'fnord'
    def __init__(self, **kwargs):
        for kw in self.keywords:
            setattr(self, kw, kwargs[kw])

There are many variations, there is no common standard that I am aware of.

like image 156
Otto Allmendinger Avatar answered Nov 13 '22 03:11

Otto Allmendinger


I’ve not seen many of your field_maps in real life. I think that would only make sense if you were to use the field_map at some other place in your code as well.

Concerning your third example: Even though you don’t need to assign to them (other than None), it is common practice to explicitly declare attributes in the __init__ method, so you’ll easily see what properties your object has.

So the following is better than simply having an empty __init__ method (you’ll also get a higher pylint score for that):

class Blah(object):
    def __init__(self):
        self.foo = None
        self.bar = None

blah = Blah()
blah.foo = var1

The problem with this approach is, that your object might be in a not well-defined state after initialisation, because you have not yet defined all of your object’s properties. This depends on your object’s logic (logic in code and in meaning) and how your object works. If it is the case however, I’d advise you not to do it this way. If your object relies on foo and bar to be meaningfully defined, you should really put them inside of your __init__ method.

If, however, the properties foo and bar are not mandatory, you’re free to define them afterwards.

If readability of the argument lists is an issue for you: Use keyword arguments.

like image 38
Debilski Avatar answered Nov 13 '22 03:11

Debilski