Fields
Fields

Reputation: 23

Python: Are these default values being passed to the __init__ function necessary?

Here is a screenshot from a lecture that I am going through at school:

screenshot from my class lecture

My question is, if the class data fields are already being defined:

slices=16
temperature=75.0

Do those values (16 and 75.0) also need to be passed to the __init__ method or can you just pass the variables names, because they are already assigned to those values?

Not sure why/if you would need to pass the default values when they are the exact same as what the variables are already set to? so instead of:

def __init__(self, slices=16, temperature=75.0)

Could you just do:

def __init__(self, slices, temperature)

Updated new question If you removed the initial class-level variables at the top, and are only defining them in the constructor class, are they only scoped to the constructor class? Or are they available throughout the entire class, even though you didn't define them at the very top (class-level)?? Example:

Class Pizza(object):
    # no class-level slice or temp variables
        def __init__(self, slices=16, temperature=75.0):
            self.slices = slices
            self.temperature = temperature

Or, because you are defining them as "self.slices", they are by default passed to all of the other methods when you pass (self) into the other methods?

Upvotes: 0

Views: 914

Answers (2)

ShadowRanger
ShadowRanger

Reputation: 155546

The class defined in your lecture is dumb (not very dumb, just pointless and misleading, as you've clearly been misled by it). There is zero reason to define class attributes that happen to share the same value as the default arguments to the initializer. The only thing doing that accomplishes is:

  1. You can do Pizza.slices and Pizza.temperature and see that the abstract concept of a pizza (not a specific pizza) somehow has a known number of slices and a known temperature, and
  2. If someone using the class, for whatever reason, does del mypizza.slices, then future access to mypizza.slices will still "work", but will retrieve the value from the class attribute (since the instance attribute was blown away). Sane code should almost never do this.

In all other ways, there is no relationship between the class level attributes and the defaults defined for the __init__ initializer method; the moment __init__ assigns to self.slices and self.temperature, it shadows the class level attributes so they cannot be directly accessed from that instance of the class (without deleting the instance attributes or bypassing the instance to look at the values on the class itself).

So no, you can't do:

def __init__(self, slices, temperature):
    self.slices = slices
    self.temperatue = temperature

because the arguments named slices and temperature have nothing to do with the class attributes. By removing their defaults, the user of your class is forced to provide their own values, and there is no default that will be provided (they could, I suppose, do Pizza(Pizza.slices, Pizza.temperature), but that's an insane way to handle defaults).

To your updated question, even without the class variables,

class Pizza:
    # no class-level slice or temp variables
    def __init__(self, slices=16, temperature=75.0):
        self.slices = slices
        self.temperature = temperature

works just fine. Outside of any methods of the class, slices and temperature won't exist, but any other methods you define on Pizza will be able to access that instance's slice and temperature attributes by looking them up on self, just like __init__ did when it assigned to them (with self.slices or self.temperature), and anyone who creates an instance of Pizza, say, with mypizza = Pizza(12, 140), can do mypizza.slices to see the attribute for the instance they hold.


A note on the class attributes: In normal cases, they're stupid and nonsensical. There is an exception for dataclasses though, where you define them at class level for the express purpose of helping the dataclasses module dynamically generate your code, removing the need to write a __init__ with separate defaults entirely. For example:

from dataclasses import dataclass

@dataclass
class Pizza:
    slices: int = 16
    temperature: float = 75.0

is a perfectly reasonable way to write the baseline class, and it uses those annotations and defaulted assignments to generate as __init__ for you (along with reasonable default implementations of __repr__ and __eq__, and other special methods if you pass specific arguments to the @dataclass decorator, saving you a ton of boilerplate required for minimal expected class functionality). It does leave the class attributes in place, which is arguably a bad idea, but at least you're getting something useful out of the deal, it's not just repeating the same defaults in two essentially unrelated places, one of which is completely useless.

Upvotes: 0

Chris
Chris

Reputation: 36621

If you use:

def __init__(self, slices, temperature)

Then slices and temperature are parameters that must be specified.

What you can do is create a variable, and then use that as the default for the function parameter.

a = "foo"

def b(c=a):
    print(c)

Just keep in mind that if you redefine that variable, it does not affect the default value for the function.

>>> a = "foo"
>>> def b(c=a):
...     print(c)
...
>>> b()
foo
>>> a = 42
>>> b()
foo

Upvotes: 0

Related Questions