title: How to preserve the value of class properties
body: <pre><code>class A:
      p = 1
      def __init__(self, p=None, **kwargs):
          self.p = p
  
  class B(A):
      p = 2
  
  a = A()
  print(a.p)
  b = B()
  print(b.p)
  </code></pre>
  <p>As a more sensible example consider:</p>
  <pre><code>class Mamal:
      can_fly = False
  
  class Bat(Mamal):
      can_fly = True
  </code></pre>
  <p>In the examples above, I would like <code>1</code> and <code>2</code> be printed. However, it prints <code>None</code> for both, though I know why. What is the solution to preserve the default value of classes?</p>
  <p>One solution I can think of is:</p>
  <pre><code>class A:
      p = 1
      def __init__(self, p=None, **kwargs):
          if p: self.p = p
          if q: self.q = q
          ...
  </code></pre>
  <p>and if I have many attributes I should do that for all of them!? another minor problem is that the user can't pass None to the class init.</p>
  <p>Another solution could be like:</p>
  <pre><code>class A:
      p = 1
      def __init__(self, p=1, **kwargs):
          self.p = p
          self.q = q
          ...
  </code></pre>
  <p>However again if one instantiate b like:</p>
  <pre><code>b = B()
  </code></pre>
  <p>the value of <code>b.p</code> would be also <code>1</code>, while I expect it to keep <code>2</code>.</p>
  <p>I use overriding classes attributes much, but I just don't know how to preserve them from being overwritten by default values of the same or parent class.</p>
  <p>Yet, another solution is combination of the above, like:</p>
  <pre><code>class A:
      p = 1
      def __init__(self, p=1, **kwargs):
          if p != 1: self.p = p
          ...
  </code></pre>
  <p>or using <code>dataclass</code></p>
  <pre><code>from dataclasses import dataclass
  @dataclass
  class A:
      p :int = 1
  
  @dataclass
  class B(A):
      p:int = 2
  </code></pre>
  <p>Just would like to know what is usual approach and consequences.</p>