1

Let's say we have a simple python model class.

 class Library:

     def __init__():
         self.library_name = None
         self.books = []

We would use that by:

new_library = Library()
new_library.library_name = "Delhi International Library"

This would be an empty library with no books. Is this safe? I know you shouldn't use mutable types in the method signature due to when it is evaluated.

5
  • 1
    new_library.library_name = "Delhi International Library" would be fine, I'm guessing .name is a typo? Commented Mar 25, 2020 at 17:17
  • thanks, I updated the typo. Commented Mar 25, 2020 at 17:23
  • 1
    The problem is when you use a mutable value as the default value for a parameter, not when you pass a mutable value as an argument. Commented Mar 25, 2020 at 17:29
  • Perfect, I thought it was OK. So setting self.books = [] as part of the init but not as an argument is OK. Commented Mar 25, 2020 at 17:32
  • 1
    Correct. Every instance of Library will then have its own (initially empty) list of books, rather than sharing a reference to a single central book list. Commented Mar 25, 2020 at 17:34

2 Answers 2

4

The idiomatic way to use a mutable type for a default value is to use a None default value:

class Library:
     def __init__(self, name, books=None):
         self.library_name = name
         self.books = [] if books is None else books


new_library = Library("Delhi International Library")

Here name is a required param because IMHO a library should have a name, but you could also use a default if you later will have to create a library with no parameters.

And books is optional. If it is not given, you will get en empty library, and if you pass it on first time, it will not become the default because None is not mutable...

Sign up to request clarification or add additional context in comments.

4 Comments

How about init(self, name, books=[ ]) and self.books=books ?
are there any performance benefits to doing it that way then not having it in the initilizer and instead doing it the way I did in. In reality there are 20 or so variables and I find it get's messy?
There are neither benefit nor drawback on a performance point of view. What matters is what is more readable or easy to use, and it really depends on the use case. Sometimes you will declare default values, sometimes you will declare no parameters...
1

you can use:

class Library:
    def __init__(self, library_name, books=None):
        self.library_name = library_name
        self.books = books or []

and then instantiate like:

new_library = Library("Delhi International Library")

4 Comments

Using a list as a default value for an argument isn't a good idea, see stackoverflow.com/questions/1132941/…
Thanks - are there any performance benefits to doing it that way then not having it in the initilizer and instead doing it the way I did in. In reality there are 20 or so variables and I find it get's messy.
It's rarely necessary to make a copy of whatever list you do pass; it's often a temporary object that would be garbage-collected if self.book didn't save a referent to it. Use books=None, then set self.books = [] if books is None else book (or an equivalent)
That is, if someone creates a Library and doesn't want that object to make changes to its existing list, the caller passes a copy as an argument, rather than assuming Library will make its own copy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.