Python's Class Development Toolkit

By: Next Day Video

1088   12   74126

Uploaded on 03/20/2013

Raymond Hettinger
This is a short, but thorough tutorial on the Python's built-in toolset for creating classes. We look at commonly encountered challenges and how to solve them using Python.

Comments (7):

By anonymous    2017-09-20

Here is a post on static methods. In summary:

  • instance methods: require the instance as the first argument
  • class methods: require the class as the first argument
  • static methods: require neither as the first argument

Regarding your questions:

  1. Yes. While the variable name self is a convention, it pertains to the instance.
  2. Static methods can be used to group similar utility methods under the same class.
  3. For methods within a class, you either need to add self as the first argument or decorate the method it with @staticmethod. "Non-decorated methods" without arguments will raise an error.

It may be more clear to see how these work when called with arguments. A modified example:

class TestClass:

    weight = 200                             # class attr 

    def __init__(self, size):
        self.size = size                     # instance attr

    def instance_mthd(self, val):
        print("Instance method, with 'self':", self.size*val)

    @classmethod
    def class_mthd(cls, val):
        print("Class method, with `cls`:", cls.weight*val)

    @staticmethod
    def static_mthd(val):
        print("Static method, with neither args:", val)

a = TestClass(1000)

a.instance_mthd(2)
# Instance method, with 'self': 2000

TestClass.class_mthd(2)
# Class method, with `cls`: 400

a.static_mthd(2)
# Static method, with neither args: 2

Overall, you can think of each method in terms of access:

  • If you need to access the instance or an instance component (e.g. an instance attribute), use an instance method as it passes self as the first argument.
  • Similarly, if you need to access a class, use a class method.
  • If access to neither an instance nor class is important, you can use a static method.

Notice in the example above, the same argument is passed for each method type, but access to instance and class attributes differ via self and cls respectively.

Note, there is a way to access class components from an instance method by using self.__class__, thereby obviating the need for a class method:

    ...

    def instance_mthd2(self, val):
        print("Instance method, with class access via `self`:", self.__class__.weight*val)
    ...

a.instance_mthd2(2)
# Instance method, with class access via `self`: 400

REF: I recommend watching Raymond Hettinger's talk Python's Class Development Toolkit, which elucidates the purpose for each method type clearly with examples.

Original Thread

By anonymous    2017-09-20

As a followup to the other answer, I highly recommend watching this talk from PyCon 2013, in which the purpose and use of the Python name-mangling paradigm is discussed.

To summarize, using double underscore for your object variables it not a way to keep them "private". In fact, private variables in Python are not "a thing"; when coming from other languages, using Python effectively requires a shift in thinking on this and other topics.

The purpose of name-mangling it to prevent parent and child classes from falling into the trap of namespace wars, in which, for example, some child class is using an attribute name for a different purpose than the parent class.

For further reading, see these other questions and answers:

Underscore vs Double underscore with variables and methods

What is the meaning of a single- and a double-underscore before an object name?

Original Thread

By anonymous    2017-09-20

Most Pythonic would be what the Python standard library already does. Core developer Raymond Hettinger (the collections guy) gave a talk on this, plus general guidelines for how to write classes.

Use separate, class-level functions to initialize instances, like how dict.fromkeys() isn't the class initializer but still returns an instance of dict. This allows you to be flexible toward the arguments you need without changing method signatures as requirements change.

Original Thread

By anonymous    2018-01-01

Is that how you want it to pop out?

Just tweak around the CSS of the navbar to your needs. Here's what I used:

.navbar{
filter: drop-shadow(8px 8px 10px black);
background: linear-gradient(to top left,  #7d7e7d 0%,gray 8%,#0e0e0e 100%);
}

.navbar-toggler{
transition:all 0.5s ease-in-out;
}

.navbar-toggler:hover{
background:#333333;
}

.navbar{
filter: drop-shadow(8px 8px 10px black);
background: linear-gradient(to top left,  #7d7e7d 0%,gray 8%,#0e0e0e 100%);
}

.navbar-toggler{
transition:all 0.5s ease-in-out;
}

.navbar-toggler:hover{
background:#333333;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Wolff Blogg</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="icon" href="http://acwolff.xyz/static/favicon.ico">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">

  <!-- Custom style -->
  <link rel="stylesheet" href="http://acwolff.xyz/static/main.css" type="text/css" />

  <!-- RSS Feed -->
  <link href="http://acwolff.xyz/feeds/atom.xml" type="application/atom+xml" rel="alternate" title="Wolff Blogg Atom Feed" />
</head>

<body>
  <!-- Navbar -->
  <div class="pos-f-t">
    <div class="collapse" id="navbarToggleExternalContent">
      <div class="bg-dark p-4 navdiv">
        <ul class="navbar-nav">
          <h4>
            <a class="navbar-brand" href="http://acwolff.xyz/index.html">Wolff Blogg</a>
          </h4>
          <li class="nav-item">
            <a class="nav-link" href="http://acwolff.xyz/archives.html">
                            Archives</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://acwolff.xyz/categories.html">
                            Categories</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://acwolff.xyz/pages/about.html">
                                    About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://acwolff.xyz/pages/projects.html">
                                    Projects</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://acwolff.xyz/feeds/atom.xml" type="application/atom+xml" rel="alternate" title="Wolff Blogg Atom Feed">
                                Atom Feed</a>
          </li>
        </ul>
      </div>
    </div>
    <nav class="navbar navbar-dark bg-dark">
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
    </nav>
  </div>

  <!-- Begin page content -->
  <div class="container rounded mt-4 mb-4 p-4">
    <header>
      <h2>
        <a href="http://acwolff.xyz/posts/gamedev/2017/understanding-delta-time.html" rel="bookmark" title="Permalink to Understanding Delta Time (in Godot)">
    Understanding Delta Time (in&nbsp;Godot)</a>
      </h2>
      <div class="card border-0">
        <div class="card-body">
          <p class="card-text">
            By: <a href="http://acwolff.xyz/author/alex-c-wolff.html">Alex C. Wolff</a> Published: 27 Jul 2017<br /> Modified: 29 Nov 2017<br /> Category: <a href="http://acwolff.xyz/category/gamedev.html">GameDev</a><br /> Tags:

            <a href="http://acwolff.xyz/tag/programming.html">programming, </a>

            <a href="http://acwolff.xyz/tag/godot.html">godot, </a>
            <a href="http://acwolff.xyz/tag/game-development.html">game development</a>
          </p>
        </div>
      </div>
    </header>
    <article>
      <p>The Godot docs don&#8217;t cover delta in any great detail and maybe they shouldn&#8217;t, but understanding delta time is important in game programming since it helps your game gain framerate independence. If you don&#8217;t already know, tying
        game logic and physics to framerate is easy but gives you undesired behavior like setting hard limits on what frame rate your game can run at, causing collision bugs if you do try to get your game running at higher framerates, or movement/actions
        speeding up and slowing down with framerate. All of these create a terrible user experience, especially on PCs and modern consoles where 60+ fps is the norm. In Godot, you&#8217;ll mostly see delta when passing it in as a parameter to the _process
        overrideable functions, like&nbsp;so: </p>
      <div class="highlight">
        <pre><span></span>func _ready():
        set_process(true)
func _process(delta):
        # do something every frame  
func _fixed_process(delta):
        # do something every physics frame
</pre>
      </div>


      <p>Delta is the time in seconds since the last frame. Since games normally run at at least 30fps and usually 60fps, that means this will be a <code>float</code> type showing milliseconds, and it will <strong><span class="caps">NOT</span></strong> be
        constant since frame latency varies widely. It will look like this: 0.017, 0.020, 0.01,&nbsp;etc. </p>
      <p>To take advantage of delta time, all you have to do is normalize it. If you want an action to happen 60 times per second, it&#8217;s a simples as action_speed * delta! Here&#8217;s an examples pulled straight from the Godot&nbsp;docs:</p>
      <div class="highlight">
        <pre><span></span># Code trimmed by ellipses to just show the key bits
...
# Initial direction of the ball
var direction = Vector2(1.0, 0.0)
# Constant for pad speed (in pixels/second)
const INITIAL_BALL_SPEED = 80
# Speed of the ball (also in pixels/second)
var ball_speed = INITIAL_BALL_SPEED
...
func _process(delta):
    var ball_pos = get_node(&quot;ball&quot;).get_position()
...
ball_pos += direction * ball_speed * delta
</pre>
      </div>


      <p>Assuming our ball is moving in a straight horizontal line from the origin (the top left corner) at it&#8217;s initial speed and with a delta of .20 (50fps), this means our will move at a rate of Vector2(0.0, 0.0) + (Vector2(1.0, 0.0) * 80 * .02)
        = Vector2(1.6, 0.0) or 1.6 pixels to the right every frame. But what if the framerate is higher? Let&#8217;s try 100fps: Vector2(0.0, 0.0) + (Vector2(1.0, 0.0) * 80 * .01) = Vector2(16.0, 0.0) or 0.8 pixels to the right every frame. What about
        25 fps? Vector2(0.0, 0.0) + (Vector2(1.0, 0.0) * 80 * .04) = Vector2(3.2, 0.0) or 3.2 pixels to the right every frame. Pretty simple concept once you lay it&nbsp;out!</p>
      <p>As a note, physics should usually not be tied to delta time since the calculations require much more precise timing. Godot handles this already, so it&#8217;s not something you need to worry about unless you start changing physics speed in the project&nbsp;settings.</p>
      <p><span class="caps">P.S.</span>- If you don&#8217;t remember vectors, they&#8217;re also super important in game programming. Check out MAth for Game Developers on&nbsp;YouTube.</p>
      <h4>References</h4>
      <ul>
        <li><a href="https://www.youtube.com/watch?v=Q9FZllr6-wY&amp;list=PLW3Zl3wyJwWOpdhYedlD-yCB7WQoHf-My&amp;index=1">Math for Game&nbsp;Developers</a></li>
        <li><a href="http://docs.godotengine.org/en/latest/learning/step_by_step/scripting_continued.html?highlight=delta">Godot Docs - Scripting&nbsp;(continued)</a></li>
        <li><a href="http://docs.godotengine.org/en/latest/classes/class_node.html?highlight=delta#class-node-process">Godot Docs - Node&nbsp;Class</a></li>
        <li><a href="https://www.scirra.com/tutorials/67/delta-time-and-framerate-independence">Delta-time and framerate independence in Construct&nbsp;2</a></li>
        <li><a href="https://youtu.be/c4b9lCfSDQM">Math for Game Developers - Jumping and&nbsp;Gravity</a></li>
        <li><a href="https://www.vg247.com/2015/05/08/dark-souls-2-durability-bug-now-fixed/">Dark Souls 2 Durability&nbsp;Bug</a></li>
        <li><a href="https://www.youtube.com/watch?v=33VRCGh2uQM">Lockpicking at&nbsp;600+fps</a></li>
        <li><a href="https://www.youtube.com/watch?v=r4EHjFkVw-s">Fallout 4 Game Speed Tied to&nbsp;Framerate</a></li>
      </ul>
    </article>
    <a href="http://acwolff.xyz/posts/gamedev/2017/understanding-delta-time.html">
      <button class="btn btn-secondary btn-lg btn-block mt-4">
                        Click through to article for comments.
                    </button>
    </a>
  </div>
  <div class="container rounded mt-4 mb-4 p-4">
    <header>
      <h2>
        <a href="http://acwolff.xyz/posts/python/2017/python-class-development-toolkit.html" rel="bookmark" title="Permalink to Python’s Class Development Toolkit">
    Python&#8217;s Class Development&nbsp;Toolkit</a>
      </h2>
      <div class="card border-0">
        <div class="card-body">
          <p class="card-text">
            By: <a href="http://acwolff.xyz/author/alex-c-wolff.html">Alex C. Wolff</a> Published: 26 Mar 2017<br /> Category: <a href="http://acwolff.xyz/category/python.html">Python</a><br /> Tags:

            <a href="http://acwolff.xyz/tag/programming.html">programming, </a>

            <a href="http://acwolff.xyz/tag/python.html">python, </a>

            <a href="http://acwolff.xyz/tag/notes.html">notes, </a>
            <a href="http://acwolff.xyz/tag/code.html">code</a>
          </p>
        </div>
      </div>
    </header>
    <article>
      <p>Based on the <a href="https://www.youtube.com/watch?v=HTLu2DFOdTg">PyCon talk by Raymond Hettinger</a>. These is a good tutorial on building Python&nbsp;classes.</p>
      <p>This is part of my repo for useful python features and ways of improving your code, check it out <a href="https://github.com/AlexCWolff/python_stuff">here</a>.</p>
    </article>
    <a href="http://acwolff.xyz/posts/python/2017/python-class-development-toolkit.html">
      <button class="btn btn-secondary btn-lg btn-block mt-4">
                        Click through to article for comments.
                    </button>
    </a>
  </div>
  <div class="container rounded mt-4 mb-4 p-4">
    <header>
      <h2>
        <a href="http://acwolff.xyz/posts/python/2017/beautiful-idiomatic-python.html" rel="bookmark" title="Permalink to Beautiful, Idiomatic Python">
    Beautiful, Idiomatic&nbsp;Python</a>
      </h2>
      <div class="card border-0">
        <div class="card-body">
          <p class="card-text">
            By: <a href="http://acwolff.xyz/author/alex-c-wolff.html">Alex C. Wolff</a> Published: 26 Mar 2017<br /> Category: <a href="http://acwolff.xyz/category/python.html">Python</a><br /> Tags:

            <a href="http://acwolff.xyz/tag/programming.html">programming, </a>

            <a href="http://acwolff.xyz/tag/python.html">python, </a>

            <a href="http://acwolff.xyz/tag/notes.html">notes, </a>
            <a href="http://acwolff.xyz/tag/code.html">code</a>
          </p>
        </div>
      </div>
    </header>
    <article>
      <p>Based on the <a href="http://www.youtube.com/watch?feature=player_embedded&amp;v=OSGv2VnC0go">PyCon talk by Raymond Hettinger</a>. These are examples of ways to improve your Python code, at all&nbsp;levels.</p>
      <p>This is part of my repo for useful python features and ways of improving your code, check it out <a href="https://github.com/AlexCWolff/python_stuff">here</a>.</p>
    </article>
    <a href="http://acwolff.xyz/posts/python/2017/beautiful-idiomatic-python.html">
      <button class="btn btn-secondary btn-lg btn-block mt-4">
                        Click through to article for comments.
                    </button>
    </a>
  </div>
  <div class="container rounded mt-4 mb-4 p-4">
    <header>
      <h2>
        <a href="http://acwolff.xyz/posts/python/2017/better-looping-in-python.html" rel="bookmark" title="Permalink to Better Looping in Python">
    Better Looping in&nbsp;Python</a>
      </h2>
      <div class="card border-0">
        <div class="card-body">
          <p class="card-text">
            By: <a href="http://acwolff.xyz/author/alex-c-wolff.html">Alex C. Wolff</a> Published: 25 Mar 2017<br /> Category: <a href="http://acwolff.xyz/category/python.html">Python</a><br /> Tags:

            <a href="http://acwolff.xyz/tag/programming.html">programming, </a>

            <a href="http://acwolff.xyz/tag/python.html">python, </a>

            <a href="http://acwolff.xyz/tag/notes.html">notes, </a>
            <a href="http://acwolff.xyz/tag/code.html">code</a>
          </p>
        </div>
      </div>
    </header>
    <article>
      <p>Based on the <a href="https://www.youtube.com/watch?v=EnSu9hHGq5o">PyCon talk by Ned Batchelder</a>. These are examples of better ways to iterate in&nbsp;Python. </p>
      <p>This is part of my repo for useful python features and ways of improving your code, check it out <a href="https://github.com/AlexCWolff/python_stuff">here</a>.</p>
    </article>
    <a href="http://acwolff.xyz/posts/python/2017/better-looping-in-python.html">
      <button class="btn btn-secondary btn-lg btn-block mt-4">
                        Click through to article for comments.
                    </button>
    </a>
  </div>
  <div class="container rounded mt-4 mb-4 p-4">
    <header>
      <h2>
        <a href="http://acwolff.xyz/posts/short-stories/2017/the-question.html" rel="bookmark" title="Permalink to The Question">
    The&nbsp;Question</a>
      </h2>
      <div class="card border-0">
        <div class="card-body">
          <p class="card-text">
            By: <a href="http://acwolff.xyz/author/alex-c-wolff.html">Alex C. Wolff</a> Published: 25 Jan 2017<br /> Category: <a href="http://acwolff.xyz/category/short-stories.html">Short Stories</a><br />
          </p>
        </div>
      </div>
    </header>
    <article>
      <p>This isn&#8217;t a particularly good story, just me trying some things out. Feedback&nbsp;welcome.</p>
      <h4 class="text-center">I</h4>

      <p><em>Today was the day</em> he said to himself, for what felt like the hundredth time. He was grinding his teeth, enough to make his jaw sore. He turned the wheel of the car and pulled on to the street. He briefly considered driving past, thinking
        of any excuse he could give for his absence. Nothing came to mind so he gave up and slowly pulled in the driveway as planned, stopping in front of the house. He killed the engine and collected his thoughts. What was he going to say? He had spent
        days planning it out but now that it was finally time nothing seemed quite right. He opened the door and stepped outside. He didn’t bother locking it. The walk to the front door may as well have been a million miles. He walked slowly and never
        seemed to get any closer. The door opened and a woman came out to greet him. They embraced warmly, and he cheered up at the familiarity of the situation. They sat down in the living room and talked as they usually do. As the night carried on he
        became his usual self again. She asked if he would like a drink. The night grew darker and colder as they shared glass after glass together by the fire. The record player softly played their favorites. After a while he began to grow serious, and
        knew that now was the time. He called her name and let out everything he had been holding in all. When he was done, she too grew serious. As the situation fully dawned on her, she became cold and angry. She replied to him and expressed her shock
        and anger. He too was now shocked and hurt by her response. Both were now deeply offended by the others actions. The conversation was increasing in speed and volume, betraying their emotions. After a few minutes of this the man could take it no
        longer. He grabbed his coat and left, slamming the door behind him. He got back in to his waiting car and drove off quickly. She watched him leave and fumed for a while but as she picked up after them she was began to cry a little. She took a
        long bath and went to&nbsp;bed.</p>
      <h4 class="text-center"><span class="caps">II</span></h4>

      <p>The young woman angrily walked up the stairs. Her mother shouted behind her to not come back down until she had found what had been asked. She groaned at the thought of the task she had been given and how she’d rather be doing almost anything else.
        After a quick search she found the most likely candidate, an old safe deposit box labeled “Karen’s important papers”. It probably hadn’t been opened since it was filled and labeled before being moved who knows how many houses ago. She took half
        the papers out and placed them to the side, then began leafing through them. One piece of paper fell out from the stack, it was much smaller than any others and looked to have a few small water spots on it. When she looked closer she noticed it
        wasn’t one paper but two newspaper articles cut out and glued to a single piece of paper. One was an obituary for a man who had gotten in to a car accident. It was determined to be drunk driving. The second was a classified ad. It read: “One diamond
        engagement ring, never&nbsp;worn.”</p>
    </article>
    <a href="http://acwolff.xyz/posts/short-stories/2017/the-question.html">
      <button class="btn btn-secondary btn-lg btn-block mt-4">
                        Click through to article for comments.
                    </button>
    </a>
  </div>


  <footer class="footer">
    <p class="text-center text-white">
      Copyright 2017 Alexander Wolff.<br /> For legal/licensing info please see the <a href="http://acwolff.xyz/pages/about.html">About</a> page.<br /> This site is powered by <a href="http://docs.getpelican.com/en/stable/">Pelican</a>, <a href="https://pages.github.com/">Github Pages</a>,
      <a href="https://disqus.com/">Disqus</a>, and <a href="http://getbootstrap.com/">Bootstrap</a>.
    </p>
  </footer>

  <!-- Bootstrap core JavaScript
        ================================================== -->
  <!-- Placed at the end of the document so the pages load faster -->
  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>

  <!-- Google Analytics/Disqus scripts -->
  <script type="text/javascript">
    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
  </script>
  <script type="text/javascript">
    try {
      var pageTracker = _gat._getTracker("UA-29261422-6");
      pageTracker._trackPageview();
    } catch (err) {}
  </script>
  <script type="text/javascript">
    var disqus_shortname = 'acwolff-xyz';
    (function() {
      var s = document.createElement('script');
      s.async = true;
      s.type = 'text/javascript';
      s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
      (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
    }());
  </script>
</body>

</html>

Original Thread

Recommended Books

    Submit Your Video

    If you have some great dev videos to share, please fill out this form.