How to declare default values ​​for instance variables in Python?

Should I give default class values ​​as follows:

class Foo: num = 1 

or how is it?

 class Foo: def __init__(self): self.num = 1 

In this question, I found that in both cases

 bar = Foo() bar.num += 1 

- a well-defined operation.

I understand that the first method will give me a class variable, and the second will not. However, if I do not need a class variable, but only need to set a default value for my instance variables, are both methods equally good? Or is one of them more "pythonic" than the other?

One thing I noticed is that in the Django tutorial they use the second method to declare models. Personally, I think the second method is more elegant, but I would like to know what the "standard" method is.

+53
python oop class
Apr 21 '10 at 8:11
source share
5 answers

An extension of the bp answer, I wanted to show you what he meant by immutable types.

Firstly, this is normal:

 >>> 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 (non-rewritable) types. If the default value was volatile (which means replacing it), this will 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 common attribute. This is often undesirable.

This is the Python way to determine default values ​​for instance variables when the type is changed:

 >>> 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 code snippet works is because with immutable types, Python creates a new instance whenever it wants. If you need to add 1 to 1, Python will make new 2 for you, because old 1 cannot be changed. I suppose the reason is mostly related to hashing.

+82
Apr 21 '10 at 9:02
source share

Two passages do different things, so this is not a matter of taste, but a matter of proper behavior in your context. The Python documentation explains the difference, but here are a few examples:

Exposition A

 class Foo: def __init__(self): self.num = 1 

This binds num to Foo instances . Changing this field does not apply to other instances.

In this way:

 >>> foo1 = Foo() >>> foo2 = Foo() >>> foo1.num = 2 >>> foo2.num 1 

Illustration B

 class Bar: num = 1 

This binds num to the Foo class . Changes are spreading!

 >>> 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 don't need a class variable, but only need to set a default value for my instance variables, are both methods equally good? Or is one of them more "pythonic" than the other?

The code in exponent B is not right for this: why do you want to bind a class attribute (the default value when creating an instance) to one instance?

The code in exhibitor A is fine.

If you want to specify default values ​​for instance variables in your constructor, I would do this:

 class Foo: def __init__(num = None): self.num = num if num is not None else 1 

... or even:

 class Foo: DEFAULT_NUM = 1 def __init__(num = None): self.num = num if num is not None else DEFAULT_NUM 

... or even: (preferable, but if and only if you are dealing with immutable types!)

 class Foo: def __init__(num = 1): self.num = num 

That way you can:

 foo1 = Foo(4) foo2 = Foo() #use default 
+36
Apr 21 '10 at 8:20
source share

Using class members for default values ​​for instance variables is not a good idea, and this is the first time I've seen this idea at all. It works in your example, but in many cases a crash may occur. For example, if a value is changed, changing it on an unmodified instance will change the default value:

 >>> class c: ... l = [] ... >>> x = c() >>> y = c() >>> xl [] >>> yl [] >>> xlappend(10) >>> yl [10] >>> cl [10] 
+3
Apr 21 '10 at 8:24
source share

Using class members to set default values ​​works very well only if you are careful only for this with immutable values. If you try to do this with a list or dict, it will be pretty deadly. It also works where an instance attribute is a reference to a class only as long as the default value is None.

I saw that this method was very successfully used in repos, which is the foundation that runs on top of Zope. The advantage here is not only that when your class is stored in the database, you need to save only non-default attributes, but also when you need to add a new field to the schema, all existing objects see a new field with its default value of without the need to actually modify the stored data.

I find that it also works well in more general coding, but it is a style. Use everything you are happy with.

+3
Apr 21 '10 at 8:35
source share

You can also declare class variables as None, which will prevent propagation. This is useful when you need a well-defined class and you want to prevent AttributeErrors. For example:

 >>> class TestClass(object): ... t = None ... >>> test = TestClass() >>> test.t >>> test2 = TestClass() >>> test.t = 'test' >>> test.t 'test' >>> test2.t >>> 

Also, if you need the default values:

 >>> class TestClassDefaults(object): ... t = None ... def __init__(self, t=None): ... self.t = t ... >>> test = TestClassDefaults() >>> test.t >>> test2 = TestClassDefaults([]) >>> test2.t [] >>> test.t >>> 

Of course, still follow the information in the other answers about using mutable vs immutable types as the default value in __init__ .

0
May 28 '15 at 19:07
source share



All Articles