{"id":17315,"date":"2017-06-05T12:15:08","date_gmt":"2017-06-05T09:15:08","guid":{"rendered":"https:\/\/www.webcodegeeks.com\/?p=17315"},"modified":"2017-06-05T11:45:18","modified_gmt":"2017-06-05T08:45:18","slug":"another-look-instance-level-properties-python","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/","title":{"rendered":"Another Look at Instance-Level Properties in Python"},"content":{"rendered":"<p>A while back, I did a post on <a href=\"https:\/\/www.webcodegeeks.com\/python\/instance-level-properties-python\/\">making instance-level properties in Python<\/a> where the implementation of it required inheritance as well as messing with <code>__getattribute__()<\/code> and <code>__setattr__()<\/code>, which are a little dangerous to mess with. Then I had another idea last night (as of the time of writing this): Use normal descriptors to delegate to \u201cDelegated Properties\u201d (name taken from Kotlin, the original inspiration). These Delegated Properties can be designed very simply in a way that they only have to worry about the value on one instance, instead of figuring out how to store the value per instance.<\/p>\n<p>A note before we begin: This was going to be my first article where I put type annotations on all of my Python code in order to help make it more readable. While typing up all the code to make sure this idea was viable, I <i>did<\/i> actually add type annotations everywhere, but seeing that this idea is super generic with very few actually helpful type annotations, I decided to forgo them in this article. You can be sure that the next time I write a Python article, the code will be annotated.<\/p>\n<p>Also, a disclaimer: this article assumes that you have a basic understanding of descriptors in Python. If you need to learn about them first, you can start with <a href=\"https:&lt;code&gt;docs.python.org\/3.6\/howto\/descriptor.html\">Raymond Hettinger\u2019s official guide<\/a> or you can get <a href=\"https:&lt;code&gt;www.amazon.com\/Python-Descriptors-Jacob-Zimmerman\/dp\/148422504X\/ref=as_li_ss_tl?ie=UTF8&amp;qid=1496088318&amp;sr=8-1&amp;keywords=Python+Descriptors&amp;linkCode=ll1&amp;tag=proidewitjak-20&amp;linkId=394f9d64a031c69ab44f73e6b2ad17b3\">my book<\/a> if you really want to learn about them.<\/p>\n<h2>The Delegated Property Interface<\/h2>\n<p>I\u2019d first like to go over the interface of a Delegated Property, and I\u2019ll do that by giving you the code for the Abstract Base Class:<\/p>\n<pre class=\"brush:php\">from abc import ABCMeta, abstractmethod\r\n \r\n\u00a0\r\nclass DelegatedProperty(metaclass=ABCMeta): \r\n    @abstractmethod\r\n    def get(self, instance, name): ...\r\n \r\n    def set(self, value, instance, name):\r\n        raise AttributeError<\/pre>\n<p>Now let\u2019s discuss why I did it the way I did. First off, we\u2019ll look at the common parameters between the two methods. Technically, <code>self<\/code> will almost always be the only one you need, but <code>instance<\/code> is there in case the property requires something else that\u2019s on the instance. Please don\u2019t use this to store the value on the instance; store the value on the Delegated Property, since storing it on the instance may interfere with how the descriptor is storing the Delegated Property. <code>name<\/code> is the name that the descriptor has on the class. This will usually be used for a possible exception that needs to be raised so the message can refer to the attribute being accessed and therefore be more informative. These \u201cmetadata\u201d parameters were also inspired by Kotlin\u2019s Delegated Properties.<\/p>\n<p>Then there\u2019s the <code>value<\/code> parameter in <code>set()<\/code>. This, if it\u2019s not obvious, is what you\u2019re setting the property value to.<\/p>\n<p>You probably noticed that <code>get()<\/code> is an <code>abstractmethod<\/code> while <code>set()<\/code> is not. The reason for this is that <code>set()<\/code> is optional. You only need to define <code>set()<\/code> when you want the property to be mutable. And, unlike with descriptors, Delegated Properties are initialized with their starting value in <code>__init__()<\/code>, so <code>set()<\/code> isn\u2019t needed in order to get that. That removes all the difficulty of implementing a \u201cread-only\u201d descriptor, which I spent an entire chapter on in <a href=\"https:&lt;code&gt;www.amazon.com\/Python-Descriptors-Jacob-Zimmerman\/dp\/148422504X\/ref=as_li_ss_tl?ie=UTF8&amp;qid=1496088318&amp;sr=8-1&amp;keywords=Python+Descriptors&amp;linkCode=ll1&amp;tag=proidewitjak-20&amp;linkId=57e740f8ef1c63a7d05052fbdafd619f\">my book<\/a>.<\/p>\n<p>Happily, whether or not you decide to create a Delegated Property without inheriting from <code>DelegatedProperty<\/code> (inheriting from it means that you\u2019re also inheriting the metaclass which can get in the way of multiple inheritance), making a read-only one is as simple as not implementing it. In either case, when the descriptor attempts to call <code>set()<\/code>, it\u2019ll receive an <code>AttributeError<\/code>, which it will interpret to mean that the property is read-only, and it will raise its own appropriate <code>AttributeError<\/code>.<\/p>\n<p>You may be wondering why there isn\u2019t a <code>delete()<\/code> method. I started off having it, but later decided to oust it; I don\u2019t think there\u2019s a single good reason to delete an instance attribute. Any time that seems appropriate could either be replaced by setting the attribute to None (or some other type of <a href=\"https:&lt;code&gt;sourcemaking.com\/design_patterns\/null_object\">Null Object<\/a>) or refactoring to a more stable design overall. The reason that setting to None is preferable is that it works better with Python\u2019s new compact, key-sharing dictionary used for instance attributes.<\/p>\n<h2>Basic Property Example<\/h2>\n<p>To demonstrate how to make a Delegated Property, I\u2019ll make a basic one here:<\/p>\n<pre class=\"brush:php\">class BasicProperty(DelegatedProperty):\r\n    def __init__(self, value):\r\n        self.value = value\r\n \r\n    def get(self, *args):\r\n        return self.value\r\n \r\n    def set(self, value, *args):\r\n        self.value = value<\/pre>\n<p>Besides showing the basic flow of how to write a Delegated Property, it also shows a little shortcut you can use if you don\u2019t plan to use <code>instance<\/code> or <code>name<\/code>; you can replace them with <code>*args<\/code>.<\/p>\n<p>Let\u2019s say you want to redesign it so it can optionally be read-only. It would look more like this:<\/p>\n<pre class=\"brush:php\">class BasicProperty(DelegatedProperty):\r\n    def __init__(self, value, *, readonly=False):\r\n        self.value = value\r\n        self._readonly = readonly\r\n \r\n    @classmethod\r\n    def readonly(cls, value):\r\n \r\n    def get(self, *args):\r\n        return self.value\r\n \r\n    def set(self, value, *args):\r\n        if self._readonly:\r\n            raise AttributeError\r\n        else:\r\n            self.value = value<\/pre>\n<p>There\u2019s three changes to pay attention to. First, a <code>readonly<\/code> boolean was added to the constructor arguments. It was added as keyword-argument-only with a default value so instantiation of a <code>BasicProperty<\/code> is more obvious. The second thing, the <code>readonly()<\/code> class method makes typical instantiation even more obvious, but that\u2019s not quite why it\u2019s there. We\u2019ll get there in a later part of the article when we\u2019re looking at using the whole instance property \u201cframework\u201d. Thirdly, in the <code>set()<\/code> method, you can see that it decides to raise an <code>AttributeError<\/code> when <code>self._readonly<\/code> is <code>True<\/code>, instead of the alternative of setting the value.<\/p>\n<h2>The <code>InstanceProperty<\/code> Descriptor<\/h2>\n<p>Now that we know what a Delegated Property looks like and have a general understanding of how to make one, let\u2019s look into the descriptor that makes using them super easy. What\u2019s really interesting about this is that you could actually redesign the descriptor to tweak how it all works, but I\u2019m just going to show you the default case and explain my reasons for certain choices.<\/p>\n<p>To give you an idea of how I want to create and use them, I\u2019ll give an example:<\/p>\n<pre class=\"brush:php\">class Foo:\r\n    bar = InstanceProperty(BasicProperty)\r\n \r\n    def __init__(self, bar):\r\n        self.bar.initialize(bar)<\/pre>\n<p>So, creating an <code>InstanceProperty<\/code> requires a callable that can be used to initialize a new Delegated Property. Nicely, simply passing the class name usually works great.<\/p>\n<p>Next, you\u2019ll see the use of <code>initialize()<\/code> to set the initial value. While it would be nice to simply write <code>self.bar = bar<\/code> there, <code>initialize()<\/code> is used to call the callable that was passed into <code>InstanceProperty<\/code>, and that callable could easily ask for more than just the starting value, such as passing in <code>readonly=True<\/code>. In this case, it can circumvented by using <code>bar = InstanceProperty(BasicProperty<b>.readonly<\/b>)<\/code> instead, but there are actually cases will require 0 or many arguments, so we can\u2019t just set the value. It\u2019s possible to set up <code>__set__()<\/code> to work that way when there <i>is<\/i> just the initial value, but we already have <code>initialize()<\/code> and putting in an alternative could end up with code that mixes both in one class and becomes confusing. It also makes <code>__set__()<\/code> that much more complicated to implement.<\/p>\n<p>Let\u2019s implement what we need so far:<\/p>\n<pre class=\"brush:php\">class InstanceProperty:\r\n    def __init__(self, instantiator):\r\n        self._create = instantiator\r\n \r\n    def initialize(self, *args, **kwargs):\r\n        delprop = self._create(*args, **kwargs)\r\n        # here we assign\/associate delprop with its instance\r\n \r\n    def __get__(self, instance, owner=None):\r\n        return self<\/pre>\n<p>So, we\u2019ve run into a problem. We currently have what we need here to make the calls in the <code>Foo<\/code> example, but it\u2019s not even enough to make that little bit work. As the comment in <code>initialize()<\/code> says, we need to assign the Delegated Property to the instance of <code>Foo<\/code> somehow. To do that, <code>initialize()<\/code> needs the instance, so it\u2019s rewritten as (with new code in bold)<\/p>\n<pre class=\"brush:php\">def initialize(self, instance, *args, **kwargs):\r\n    delprop = self._create(*args, **kwargs)\r\n    setattr(instance, !!THE NAME!!, delprop)<\/pre>\n<p>That looks okay, but other than lacking the name to assign the property to (we\u2019ll get to that in a moment), we now have a new problem. With the inclusion of the instance in the parameter list, initializing <code>bar<\/code> now looks like this: <code>self.bar.initialize(self, bar)<\/code>. The extra use of <code>self<\/code> is annoying, especially since we already gave the descriptor <code>self<\/code> when we indirectly called <code>__get__()<\/code>. So, what if we returned something else from <code>__get__()<\/code> with an <code>initialize()<\/code> method that already knows the instance? Something like this?<\/p>\n<pre class=\"brush:php\">class InstancePropertyInitializer:\r\n    def __init__(self, instanceprop, instance):\r\n        self.instanceprop = instanceprop\r\n        self.instance = instance\r\n \r\n    def initialize(self, *args, **kwargs):\r\n        self.instanceprop.initialize(self.instance, *args, **kwargs)<\/pre>\n<p>Now, <code>InstanceProperty<\/code>\u2018s <code>__get__()<\/code> method looks like this:<\/p>\n<pre class=\"brush:php\">def __get__(self, instance, owner=None):\r\n    return InstancePropertyInitializer(self, instance)<\/pre>\n<p>Next, let\u2019s look into getting that name we want. Well, the <a href=\"https:&lt;code&gt;github.com\/sad2project\/descriptor-tools\">library I wrote to go along with my book<\/a> includes a function called <code>name_of()<\/code> that takes a descriptor and a class that has the descriptor as an attribute (the class can be a subclass of the one that actually has it, if need be). And since we\u2019ll need the name elsewhere, we\u2019ll set it in <code>__get__()<\/code>. And there\u2019s actually two different names we\u2019ll need. We\u2019ll need the name of the attribute the descriptor is stored under on the class, and we\u2019ll need the name we\u2019ll be using to store the Delegated Property on the instance. The changes look like this:<\/p>\n<pre class=\"brush:php\">class InstanceProperty:\r\n    def __init__(self, instantiator):\r\n        self._create = instantiator\r\n        self._name = None\r\n        self._on_instance_name = None\r\n \r\n    def initialize(self, instance, *args, **kwargs):\r\n        delprop = self._create(*args, **kwargs)\r\n        setattr(instance, self._on_instance_name, delprop)\r\n \r\n    def __get__(self, instance, owner=None):\r\n        owner = owner if owner is not None else type(instance)\r\n        self._set_names(owner)\r\n        return InstancePropertyInitializer(self, instance)\r\n \r\n    def _set_names(self, owner):\r\n        if self._name is None:\r\n            self._name = name_of(self, owner)\r\n            self._on_instance_name = '_' + self._name<\/pre>\n<p>We can set the names in <code>__get__()<\/code> because it has the owner, and it will be the first method called if everything is used correctly. I don\u2019t like being that flaky with it, but I like it better than the other alternatives I came up with.<\/p>\n<p>Let\u2019s finish this up:<\/p>\n<pre class=\"brush:php\">class InstanceProperty:\r\n    def __init__(self, instantiator):\r\n        self._create = instantiator\r\n        self._name = None\r\n        self._on_instance_name = None\r\n \r\n    def initialize(self, instance, *args, **kwargs):\r\n        delprop = self._create(*args, **kwargs)\r\n        setattr(instance, self._on_instance_name, delprop)\r\n \r\n    def __get__(self, instance, owner=None):\r\n        if instance is None:\r\n            return self  # also check out my article that mentions unbound attributes.\r\n        owner = owner if owner is not None else type(instance)\r\n        self._set_names(owner)\r\n        try:\r\n            delprop = self._get_deleg_prop(instance)\r\n        except AttributeError:\r\n            # if this happens, then the property has not yet been initialized on\r\n            # the instance yet, which means we need to return an initializer\r\n            return InstancePropertyInitializer(self, instance)\r\n        return delprop.get(instance, self._name)\r\n \r\n    def __set__(self, instance, value):\r\n        delprop = self._get_deleg_prop(instance)\r\n        try:\r\n            delprop.set(value, instance, self._name)\r\n        except AttributeError:\r\n            raise AttributeError(f\"Cannot change value of read-only attribute, '{self._name}'\")\r\n \r\n    def _set_names(self, owner):\r\n        if self._name is None:\r\n            self._name = name_of(self, owner)\r\n            self._on_instance_name = '_' + self._name\r\n \r\n    def _get_deleg_prop(self, instance):\r\n        try:\r\n            return getattr(instance, self._on_instance_name)\r\n        except AttributeError:\r\n            raise AttributeError(f\"Instance property, '{self._name}', not yet initialized\")<\/pre>\n<p>We added a helper method that gets the Delegated Property from the instance, since that has to be done a couple times. If there\u2019s an <code>AttributeError<\/code>, that means that the Delegated Property hasn\u2019t been initialized yet. Hopefully, we\u2019re in <code>__get__()<\/code> and it\u2019ll return an initializer, but we could be in <code>__set__()<\/code>, so we need a good error message to instruct the user on their failure to use the descriptor properly.<\/p>\n<p>In <code>__get__()<\/code> we retrieve the Delegated Property, and if that fails with an <code>AttributeError<\/code>, then we know that the Delegated Property isn\u2019t initialized yet. I could have done a <code>hasattr()<\/code> check instead of a <code>try...except<\/code> block, but since the <code>hasattr()<\/code> will only return <code>False<\/code> once per instance, as opposed to the unknown number of times that it will get accessed after creation, I decided to ask for forgiveness rather than permission and save the time required for the check. I would have liked to have kept <code>return delprop.get(instance, self._name)<\/code> inside the block, but if that raises an <code>AttributeError<\/code>, something bad is actually happening and it should propagate upwards.<\/p>\n<p>The code in <code>__set__()<\/code> is pretty straightforward; it gets the Delegated Property, then delegates to it. But if <code>set()<\/code> raises an <code>AttributeError<\/code>, that means the Delegated Property wants to be a read-only one, and we raise another <code>AttributeError<\/code> with the appropriate error message.<\/p>\n<h2>Outro<\/h2>\n<p>That\u2019s it for this week. Next week, I\u2019ll make a few more Delegated Properties, show some other little bits to make using all this a little nicer and even look more like it does in Kotlin. See you then!<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/programmingideaswithjake.wordpress.com\/2017\/06\/03\/another-look-at-instance-level-properties-in-python\/\">Another Look at Instance-Level Properties in Python<\/a> from our <a href=\"http:\/\/www.webcodegeeks.com\/join-us\/wcg\/\">WCG partner<\/a> Jacob Zimmerman at the <a href=\"http:\/\/programmingideaswithjake.wordpress.com\/\">Programming Ideas With Jake<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with __getattribute__() and __setattr__(), which are a little dangerous to mess with. Then I had another idea last night (as of the time of writing this): Use normal descriptors to delegate &hellip;<\/p>\n","protected":false},"author":51,"featured_media":1651,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[],"class_list":["post-17315","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2017-06-05T09:15:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jacob Zimmerman\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/jacobz_20\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jacob Zimmerman\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\"},\"author\":{\"name\":\"Jacob Zimmerman\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/f54a53cfb8523f4ef6012aa63f075c39\"},\"headline\":\"Another Look at Instance-Level Properties in Python\",\"datePublished\":\"2017-06-05T09:15:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\"},\"wordCount\":1681,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"articleSection\":[\"Python\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\",\"name\":\"Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"datePublished\":\"2017-06-05T09:15:08+00:00\",\"description\":\"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/python\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Another Look at Instance-Level Properties in Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/f54a53cfb8523f4ef6012aa63f075c39\",\"name\":\"Jacob Zimmerman\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2dfdd9e2d35ed2224faf73968f8c597b5489fc345287e06e2571d3935a6bcc86?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2dfdd9e2d35ed2224faf73968f8c597b5489fc345287e06e2571d3935a6bcc86?s=96&d=mm&r=g\",\"caption\":\"Jacob Zimmerman\"},\"description\":\"Jacob is a certified Java programmer (level 1) and Python enthusiast. He loves to solve large problems with programming and considers himself pretty good at design.\",\"sameAs\":[\"https:\/\/programmingideaswithjake.wordpress.com\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/jacobz_20\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/jacob-zimmerman\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026","description":"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/","og_locale":"en_US","og_type":"article","og_title":"Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026","og_description":"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with","og_url":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2017-06-05T09:15:08+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","type":"image\/jpeg"}],"author":"Jacob Zimmerman","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/jacobz_20","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Jacob Zimmerman","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/"},"author":{"name":"Jacob Zimmerman","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/f54a53cfb8523f4ef6012aa63f075c39"},"headline":"Another Look at Instance-Level Properties in Python","datePublished":"2017-06-05T09:15:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/"},"wordCount":1681,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","articleSection":["Python"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/","url":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/","name":"Another Look at Instance-Level Properties in Python - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","datePublished":"2017-06-05T09:15:08+00:00","description":"A while back, I did a post on making instance-level properties in Python where the implementation of it required inheritance as well as messing with","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/python\/another-look-instance-level-properties-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Python","item":"https:\/\/www.webcodegeeks.com\/category\/python\/"},{"@type":"ListItem","position":3,"name":"Another Look at Instance-Level Properties in Python"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/f54a53cfb8523f4ef6012aa63f075c39","name":"Jacob Zimmerman","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/2dfdd9e2d35ed2224faf73968f8c597b5489fc345287e06e2571d3935a6bcc86?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2dfdd9e2d35ed2224faf73968f8c597b5489fc345287e06e2571d3935a6bcc86?s=96&d=mm&r=g","caption":"Jacob Zimmerman"},"description":"Jacob is a certified Java programmer (level 1) and Python enthusiast. He loves to solve large problems with programming and considers himself pretty good at design.","sameAs":["https:\/\/programmingideaswithjake.wordpress.com\/","https:\/\/x.com\/https:\/\/twitter.com\/jacobz_20"],"url":"https:\/\/www.webcodegeeks.com\/author\/jacob-zimmerman\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/17315","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/51"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=17315"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/17315\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/1651"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=17315"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=17315"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=17315"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}