Extending bp's answer, I wanted to show you what he meant by immutable types.
First, this is okay:
>>> class TestB():
... def __init__(self, attr=1):
... self.attr = attr
...
>>> a = TestB()
>>> b = TestB()
>>> a.attr = 2
>>> a.attr
2
>>> b.attr
1
However, this only works for immutable (unchangable) types. If the default value was mutable (meaning it can be replaced), this would happen instead:
>>> class Test():
... def __init__(self, attr=[]):
... self.attr = attr
...
>>> a = Test()
>>> b = Test()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[1]
>>>
Note that both a and b have a shared attribute. This is often unwanted.
This is the Pythonic way of defining default values for instance variables, when the type is mutable:
>>> class TestC():
... def __init__(self, attr=None):
... if attr is None:
... attr = []
... self.attr = attr
...
>>> a = TestC()
>>> b = TestC()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[]
The reason my first snippet of code works is because, with immutable types, Python creates a new instance of it whenever you want one. If you needed to add 1 to 1, Python makes a new 2 for you, because the old 1 cannot be changed. The reason is mostly for hashing, I believe.
Answer from Xavier Ho on Stack Overflowclass - How should I declare default values for instance variables in Python? - Stack Overflow
Python: Are these default values being passed to the __init__ function necessary? - Stack Overflow
class init method: best way for default value assignments
python - How to assign "default" values in class? - Stack Overflow
I'm wondering if this is the right way to do this. It seems... odd somehow to assign default values in the class definition, then default None in the constructor. I suppose I could give the same default values in both places, but again, this feels like unnecessarily repeating myself.
class MyClass:
name = 'Undefined'
number = -1
def __init__(self, name=None, number=None):
if name is not None:
self.name = name
if number is not None:
self.number = numberDon't use class attributes for that, that's not what they are there for. Use default arguments:
def __init__(self, name='Undefined', number=-1):
self.name = name
self.number = number
If any of the arguments are mutable, then you need to use the usual idiom:
def __init__(self, foo=None):
self.foo = [] if foo is None else foo
do you need these vars on the class level, given that they are supposed to be relevant on a per instance basis?
class MyClass:
def __init__(self, name='Undefined', number=-1):
self.name = name
self.number = number
def __str__(self):
return '{0.__class__.__name__}(name={0.name}, number={0.number})'.format(self)
print(MyClass())
print(MyClass(name='Joe'))
print(MyClass(number=11))
print(MyClass(name='Joe', number=11))
Extending bp's answer, I wanted to show you what he meant by immutable types.
First, this is okay:
>>> class TestB():
... def __init__(self, attr=1):
... self.attr = attr
...
>>> a = TestB()
>>> b = TestB()
>>> a.attr = 2
>>> a.attr
2
>>> b.attr
1
However, this only works for immutable (unchangable) types. If the default value was mutable (meaning it can be replaced), this would happen instead:
>>> class Test():
... def __init__(self, attr=[]):
... self.attr = attr
...
>>> a = Test()
>>> b = Test()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[1]
>>>
Note that both a and b have a shared attribute. This is often unwanted.
This is the Pythonic way of defining default values for instance variables, when the type is mutable:
>>> class TestC():
... def __init__(self, attr=None):
... if attr is None:
... attr = []
... self.attr = attr
...
>>> a = TestC()
>>> b = TestC()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[]
The reason my first snippet of code works is because, with immutable types, Python creates a new instance of it whenever you want one. If you needed to add 1 to 1, Python makes a new 2 for you, because the old 1 cannot be changed. The reason is mostly for hashing, I believe.
The two snippets do different things, so it's not a matter of taste but a matter of what's the right behaviour in your context. Python documentation explains the difference, but here are some examples:
Exhibit A
class Foo:
def __init__(self):
self.num = 1
This binds num to the Foo instances. Change to this field is not propagated to other instances.
Thus:
>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.num = 2
>>> foo2.num
1
Exhibit B
class Bar:
num = 1
This binds num to the Bar class. Changes are propagated!
>>> bar1 = Bar()
>>> bar2 = Bar()
>>> bar1.num = 2 #this creates an INSTANCE variable that HIDES the propagation
>>> bar2.num
1
>>> Bar.num = 3
>>> bar2.num
3
>>> bar1.num
2
>>> bar1.__class__.num
3
Actual answer
If I do not require a class variable, but only need to set a default value for my instance variables, are both methods equally good? Or one of them more 'pythonic' than the other?
The code in exhibit B is plain wrong for this: why would you want to bind a class attribute (default value on instance creation) to the single instance?
The code in exhibit A is okay.
If you want to give defaults for instance variables in your constructor I would however do this:
class Foo:
def __init__(self, num = None):
self.num = num if num is not None else 1
...or even:
class Foo:
DEFAULT_NUM = 1
def __init__(self, num = None):
self.num = num if num is not None else DEFAULT_NUM
...or even: (preferrable, but if and only if you are dealing with immutable types!)
class Foo:
def __init__(self, num = 1):
self.num = num
This way you can do:
foo1 = Foo(4)
foo2 = Foo() #use default
I am learning linked lists in python using classes.
One place that I am learning from is doing:
class Node:
def __init__(self, value):
self.value = value
self.next = NoneThe other place is doing:
class Node:
def __init__(self, value, next = None):
self.value = value
self.next = nextI can't figure out what difference it makes to use either init method. I tried to search this answer out using StackOverflow, but I had no luck.
I get that one is able to define 'next' during instantiation and the other would need to be defined after instantiation, but when would and why would you use one over the other?
edit: Thanks all. I am just starting to understand classes and still overthinking a little.
Mutable default arguments don't generally do what you want. Instead, try this:
class Node:
def __init__(self, wordList=None, adjacencyList=None):
if wordList is None:
self.wordList = []
else:
self.wordList = wordList
if adjacencyList is None:
self.adjacencyList = []
else:
self.adjacencyList = adjacencyList
Let's illustrate what's happening here:
Python 3.1.2 (r312:79147, Sep 27 2010, 09:45:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
... def __init__(self, x=[]):
... x.append(1)
...
>>> Foo.__init__.__defaults__
([],)
>>> f = Foo()
>>> Foo.__init__.__defaults__
([1],)
>>> f2 = Foo()
>>> Foo.__init__.__defaults__
([1, 1],)
You can see that the default arguments are stored in a tuple which is an attribute of the function in question. This actually has nothing to do with the class in question and goes for any function. In python 2, the attribute will be func.func_defaults.
As other posters have pointed out, you probably want to use None as a sentinel value and give each instance it's own list.
One solution is to factor the default values to constants:
DEFAULT_ONE = 1
DEFAULT_TWO = 2
class A:
def __init__(self, one=DEFAULT_ONE, two=DEFAULT_TWO):
pass
Use the constants in class C as well.
You can use inspect.signature to obtain the parameters of the __init__ method of each "base" class of class C, and let C.__init__ accept variable keyword arguments, so that it can iterate through the "base" classes and pass to the __init__ method of each just what it needs and what the given keyword arguments have. Use itertools.islice to ignore the first parameter, which is always self:
import inspect
from itertools import islice
class C:
bases = A, B
params = {}
for cls in bases:
params[cls] = inspect.signature(cls.__init__).parameters
def __init__(self, **kwargs):
for cls in self.bases:
setattr(self, cls.__name__, cls(**{key: kwargs[key] for key in
islice(self.params[cls], 1, None) if key in kwargs}))
so that:
c = C(one=3,value='hi')
print(c.A.one)
print(c.A.two)
print(c.B.value)
outputs:
3
2
hi