https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_b964594d3d957944241961017b9eb19bf02834de44cce93d8e67dd306852dbe346167181e455e33d5268ea01d973d77bb056848546f31794f31a4c31a9da5aa3.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_23f1ae74c634d7e5e0a067c22b7a8c2d79c3ffd9a3b9395fc82c1b3b99635552b994f1f72f532f28ceaff1ea054ea026cd488cd62fa03a4ad91d212b5f3c5a72.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_e6b7e0bf68aa4a61d5c6a0065ec42e38a0cc53e39a4fbee057b72d4b2297b37c01e716e1e61bac7f240b5a0edbb178d37b62f7ed4ea4ea3d10e46dbe7429f326.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_bfff9e63e857e9ee612e292d4a6edf3ced64d6a756925c953a9d8f77845ff601eca64d73dfa48756b1a9f4a4d6de6127a273bcde16ddeb71a22383460f4e94b0.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f4dd7e1d73ae5eda35ed5ad6aa965b612dbf483ece3ca50c1e8e30ad8dff1c66a160ed75e958e2db399661d229874783e0834ad813a479437035666b8e9e3386.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_4fce0769137d4cd096989b0349bc3c2bbfca79ac311fdf714c41ab24d87551c7b49b756c8a8de090b0714a0ad0560e49fa532ba5a88875ea4afd78efac464df6.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_85cec8b07d60426b11040e471babca0d2f9c8dc87a9b56e06cad39828f7f67179e29609100f282a574872c9a93fb635b25416300eb4c97bc5a653d00cf6f8dbf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_6768e5a27d4d357347338621c0d20bd269b126d30eec796193390f2f530fbaea60af84130c46f9786114be65149e661e87d55c339219c90aa76396d7e5b734ef.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_2acd6bdff3b680341e8c727da5169a647123eb8fd0a90253161b4c3af272c15d293bf9bb217008bb13f84d1910b0e166798001f8603b6c026d5c20a76c41d47c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_9188e7898ddc65a587fa381e4bc60c27b71f8b438218411e924eac7644a9ab2af3fd22bda26ebff479a5575bc2f015114d41e9dbb182550cb4ca1ef4be0ac356.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_268c9bba6ba649318f0da28c37b09a9bbfa371210f9b6b52faa7fd8ae94abf6b3c3bfeb5df5705c93495ce1152ca58aeabc435d6c6c1bd959025165c3f50e086.js
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer
  • Home
  • Featured
    • Advanced Python Topics
    • AWS Learning Roadmap
    • JWT Complete Guide
    • Git CheatSheet
  • Explore
    • Programming
    • Development
      • microservices
      • Front End
    • Database
    • DevOps
    • Productivity
    • Tutorial Series
      • C# LinQ Tutorials
      • PHP Tutorials
  • Dev Tools
    • JSON Formatter
    • Diff Checker
    • JWT Decoder
    • JWT Generator
    • Base64 Converter
    • Data Format Converter
    • QR Code Generator
    • Javascript Minifier
    • CSS Minifier
    • Text Analyzer
  • About
  • Contact
CodeSamplez.com

CodeSamplez.com

Programming And Development Resources

You are here: Home / Programming / Python Descriptors Tutorial: Descriptor Protocol Explained

Python Descriptors Tutorial: Descriptor Protocol Explained

Updated June 12, 2025 by Rana Ahsan Leave a Comment ⏰ 9 minutes

Python Descriptors Tutorial

Ever needed to control how a Python class manages its attributes? Today, in this tutorial, we will explore Python Descriptors, one of Python’s one of most powerful yet underappreciated advanced features. They’re powerful, a bit sneaky, and will totally change how you handle attribute access in classes. Descriptors are absolutely game-changing once you understand them!

What Are Python Descriptors?

Python Descriptors are objects that implement a specific protocol to customize how attribute access works. It lets objects control what happens when attributes are accessed or modified.

Think of them as the ultimate middleman—controlling the flow between your code and the attribute. They’re the magic behind many Python features you already use – from properties and methods to the entire Django ORM system! 🐍✨

You create a descriptor by building a class with at least one of these special methods:

  • __get__(self, instance, owner): Fires when you grab an attribute (like obj.attr).
  • __set__(self, instance, value): Kicks in when you assign a value (like obj.attr = 5).
  • __delete__(self, instance): Handles attribute deletion (like del obj.attr).

Implementing these methods gives you incredible control over how attributes behave when accessed, modified, or deleted. This is powerful stuff!

Why Use Python Descriptors?

Python Descriptors aren’t just cool but also essential for writing top-notch code. Here’s why they rock:

  1. Reusability: Write it once and use it everywhere. No more copy-pasting getters and setters!
  2. Encapsulation: Keep your attribute logic tidy and tucked away.
  3. Flexibility: From validation to lazy loading, descriptors do it all.
  4. Python Magic: Ever wonder how property works? Descriptors are the secret sauce.

The first time I implemented a custom descriptor in a system, the codebase shrunk significantly while becoming more maintainable. Descriptors are that powerful!

A Simple Descriptor Example

Let’s start with a basic example – a descriptor that validates values:

class Positive:
    def __init__(self, name):
        self.name = name
        
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__[self.name]
    
    def __set__(self, instance, value):
        if value <= 0:
            raise ValueError(f"{self.name} must be positive")
        instance.__dict__[self.name] = value
        
class Product:
    price = Positive("price")
    quantity = Positive("quantity")
    
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def total_cost(self):
        return self.price * self.quantity

# This works fine
product = Product(10, 5)
print(product.total_cost())  # 50

# This raises a ValueError
try:
    product.price = -10
except ValueError as e:
    print(e)  # price must be positiveCode language: HTML, XML (xml)

Now that we saw the example, did you noticed what happened there? Our Positive descriptor enforces that values must be positive, handling the validation logic in one place. I’ve used this pattern countless times to make my code more robust and maintainable.

The Python Descriptors Protocol Deep Dive

Let’s break down how the descriptor protocol actually works:

  • __get__(self, instance, owner): Called when the attribute is accessed
    • self: The descriptor object
    • instance: The instance owning the attribute (or None for class access)
    • owner: The class where the descriptor is defined
  • __set__(self, instance, value): Called when the attribute is assigned
    • self: The descriptor object
    • instance: The instance owning the attribute
    • value: The value being assigned
  • __delete__(self, instance): Called when the attribute is deleted
    • self: The descriptor object
    • instance: The instance owning the attribute

A descriptor that implements __get__ but not __set__ is a non-data descriptor, while one that implements both is a data descriptor. This distinction matters because data descriptors always take precedence over instance dictionary entries.

Here’s a flow chart diagram for showing how accessing obj.attr triggers a descriptor’s methods:

a flowchart showing how accessing obj.attr in python triggers a descriptor’s methods

Data vs Non-Data Descriptors

Data descriptors implement both __get__() and either __set__() or __delete__(). They have higher precedence in attribute lookup and can control both getting and setting of attributes. Examples include properties and most built-in descriptors.

Non-data descriptors implement only __get__(). They have lower precedence and only control attribute retrieval, not assignment. The most common example is functions (which become bound methods when accessed on instances).

The precedence difference is crucial: when looking up an attribute, Python checks data descriptors first, then instance dictionary, then non-data descriptors, then class dictionary. This means data descriptors can override instance attributes, while non-data descriptors can be shadowed by instance attributes.

For example, a property (data descriptor) will always be called even if you try to set an instance attribute with the same name, while a method (non-data descriptor) can be overridden by setting an instance attribute.

Some Use Case Examples For Descriptors in Python

Descriptors can be used in so many situations, but here are some of my favorites:

1. Type-checking and Validation


class TypedAttribute:
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type
        
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name, None)
    
    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError(f"{self.name} must be of type {self.expected_type.__name__}")
        instance.__dict__[self.name] = value
        
class Person:
    name = TypedAttribute("name", str)
    age = TypedAttribute("age", int)
    
    def __init__(self, name, age):
        self.name = name
        self.age = age

2. Lazy Properties (Computed Only When Needed)

class LazyProperty:
    def __init__(self, function):
        self.function = function
        self.name = function.__name__
        
    def __get__(self, instance, owner):
        if instance is None:
            return self
        
        value = self.function(instance)
        instance.__dict__[self.name] = value  # Cache the result
        return value
        
class DataProcessor:
    def __init__(self, data):
        self.data = data
        
    @LazyProperty
    def processed_data(self):
        print("Processing data...")  # Expensive operation
        return [x * 2 for x in self.data]

Using such a pattern in a data processing pipeline could cut processing time significantly due to no longer recomputing values unnecessarily. 🚀

3. Logging Descriptors

class LoggingDescriptor:
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        print(f"Accessing {self.name}")
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        print(f"Setting {self.name} to {value}")
        instance.__dict__[self.name] = value

class MyClass:
    attr = LoggingDescriptor('attr')

obj = MyClass()
obj.attr = 10  # Setting attr to 10
print(obj.attr)  # Accessing attr, then 10

We will explore more real-world use-cases later in the tutorial.

Common Pitfalls and How to Avoid Them

I’ve made my share of mistakes with descriptors! Here are the typically the most common ones:

Using instance attributes with the same name as the descriptor: This leads to infinite recursion! Always store the value under a different name:

# BAD - leads to recursion
def __set__(self, instance, value):
    instance.name = value  # This calls __set__ again!

# GOOD - use different name or __dict__
def __set__(self, instance, value):
    instance.__dict__["_name"] = valueCode language: PHP (php)

Forgetting to handle the class access case: When a descriptor is accessed on the class rather than an instance, instance will be None:

# Don't forget to handle this case
def __get__(self, instance, owner):
    if instance is None:
        return self  # Return the descriptor itself
    # Normal instance access handlingCode language: PHP (php)

Not understanding descriptor priority As mentioned previously once, data descriptors (with __set__) take precedence over instance dictionary entries, while non-data descriptors don’t. This subtle distinction has caused me HOURS of debugging!

Beyond the Basics: Advanced Descriptor Techniques

Besides the fundamentals we have covered so far, there’s more to to it. Once you’re comfortable with basic descriptors, you can use them for some truly powerful patterns:

Method Binding

To begin with, did you know that Python functions are non-data descriptors? That’s how methods work:

class Function:
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return MethodType(self, instance)  # Bind the method to the instance

Metaclass Integration

Combine descriptors with Python metaclasses for even more control:

class ModelMeta(type):
    def __new__(mcs, name, bases, namespace):
        fields = {
            key: value for key, value in namespace.items()
            if isinstance(value, Field)
        }
        
        for name, field in fields.items():
            field.name = name
            
        namespace['_fields'] = fields
        return super().__new__(mcs, name, bases, namespace)
        
class Model(metaclass=ModelMeta):
    pass
    
class Field:
    def __init__(self):
        self.name = None
        
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name)
        
    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

I used this pattern to build a mini-ORM, which worked beautifully to simplify database access. Sometimes I wonder – did I really need to learn SQLAlchemy? 😂

Real-World Applications for Descriptors in Python

To illustrate it’s power, let me share a few real-world examples where descriptors can save the day:

  • Configuration systems: Descriptors provide dynamic default values that change based on the environment
  • Financial applications: Descriptors help enforce business rules about monetary values across hundreds of classes
  • Data processing pipeline: Descriptors can help implement a caching system that prevents redundant calculations

Limitations to Watch Out For

While there are so many benefits, Descriptors aren’t perfect. They’ve got quirks:

  • Complexity: They’re a brain-bender at first. Use them wisely and explain them well.
  • Speed: Extra steps mean a tiny slowdown—nothing major, though.
  • Class Only: Define them in the class, not on instances. That’s just how it rolls.

Also, descriptors trigger on instance access, not class access—unless you handle it. It took me a minute to understand that.

Conclusion: Embracing the Power of Descriptors

As we explained in this tutorial guide, Python descriptors represent one of the language’s most elegant design patterns. They’ve completely changed how I approach attribute management and API design.

Once you understand descriptors, you’ll start seeing opportunities to use them everywhere. They’ll help you write cleaner, more maintainable code while giving you fine-grained control over object behaviour. Read the Official docs as well.

So, are you ready to take your Python skills to the next level? Start experimenting with descriptors today – I promise your future self will thank you! 💯

Share if liked!

  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on X (Opens in new window) X
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pinterest (Opens in new window) Pinterest
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to share on Tumblr (Opens in new window) Tumblr
  • Click to share on Pocket (Opens in new window) Pocket

You may also like


Discover more from CodeSamplez.com

Subscribe to get the latest posts sent to your email.

First Published On: April 8, 2025 Filed Under: Programming Tagged With: python

About Rana Ahsan

Rana Ahsan is a seasoned software engineer and technology leader specialized in distributed systems and software architecture. With a Master’s in Software Engineering from Concordia University, his experience spans leading scalable architecture at Coursera and TopHat, contributing to open-source projects. This blog, CodeSamplez.com, showcases his passion for sharing practical insights on programming and distributed systems concepts and help educate others.
Github | X | LinkedIn

Reader Interactions

Leave a ReplyCancel reply

Primary Sidebar

  • Facebook
  • X
  • Pinterest
  • Tumblr

Subscribe via Email

Top Picks

python local environment setup

Python Local Development Environment: Complete Setup Guide

In-Depth JWT Tutorial Guide For Beginners

JSON Web Tokens (JWT): A Complete In-Depth Beginners Tutorial

The Ultimate Git Commands CheatSheet

Git Commands Cheatsheet: The Ultimate Git Reference

web development architecture case studies

Web Development Architecture Case Studies: Lessons From Titans

static website deployment s3 cloudfront

Host Static Website With AWS S3 And CloudFront – Step By Step

Featured Dev Tools

  • JSON Formatter
  • JWT Decoder

Recently Published

advanced service worker features

Advanced Service Worker Features: Push Beyond the Basics

service worker framework integration

Service Workers in React: Framework Integration Guide

service worker caching strategies

Service Worker Caching Strategies: Performance & Offline Apps

service worker lifecycle

Service Worker Lifecycle: Complete Guide for FE Developers

what is service worker

What Is a Service Worker? A Beginner’s Guide

Footer

Subscribe via Email

Follow Us

  • Facebook
  • X
  • Pinterest
  • Tumblr

Other Sites

  • Demo.CodeSamplez.com

Explore By Topics

Python | AWS | PHP | C# | Javascript

Copyright © 2025

https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_bb74b679b69e9ad172c2fc6cf58c33585c80cef65606684f856d571669ebbbf2917ad0abe95ab4b29cf9ee60aac061b3e12cce81f09539ff3b623fc0e1bc725b.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_c402e38f1879c18090377fb6b73b15ac158be453ecda3a54456494fe8aba42b990c293bae5424e5643d52515ffc2067e0819995be8d07d5bba9107a96780775c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_ffc3511227531cc335353c54c3cbbaa11d0b80e5cb117478e144436c13cd05495b67af2e8950480ed54dbdabcdcef497c90fdb9814e88fe5978e1d56ce09f2cf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_d57da9abfef16337e5bc44c4fc6488de258896ce8a4d42e1b53467f701a60ad499eb48d8ae790779e6b4b29bd016713138cd7ba352bce5724e2d3fe05d638b27.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_edc0e9ef106cc9ef7edd8033c5c6fcff6dc09ee901fd07f4b90a16d9345b35a06534f639e018a64baaf9384eee1df305570c1ecad747f41b787b89f53839962b.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_5a3aa28cd4eb24db3e3e2acd58230ff5cdc78120b94c2b118227d4c7806ecac03978e1a10404240314f66a3b82af8823768abb8b9eccc5003d198eb077ea12b8.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_dccc492dbbfdac33d1411f9df909e849c7268fcf99b43007f278cde3a0adc0ae00e8cae5ec81cf255b9a6eae74e239ba1fa935572af77173219cb081f7d2327d.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_00bacf9e36181aac2b666d110cd9d82257f846766e7041b2d7b3c909b458982931ccc9b203e37098fbdfcf43ca359cf04e3824a724a6789fc204196d3a72ad29.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_a29cfc168828e2841b7b09805471da35a35a7113f8a66df6a76e03f2d847fe02e4ae51017d742de1ce5509d0f01eb9b6046e6a2cae50e236809d8b804a8ce0f3.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_aa5a5d229b421633f4247380e1e8c0a4854f82efb35d13a5b07b7b8fbe22e98842a580f063e5965345a51c477a7f5c2585edf8dd7d896b2438dc61f91d8d970c.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_bb8058a9e234a7ffaa98891b1df7f6b8e67410e6984568b151daa05113b8c7f89d7b5918ae73f020998a16f7f5a087a13d6a9a5e5d7c301e2ca12fd9d1f8d177.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_647fb67570c6108fb10ae6785a1abdbecac99ffcf80351d0bef17c3cf783dce497b1895fcdaae997dacc72c359fbfb128cc1540dd7df56deb4961e1cd4b22636.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f7a298a0f1f754623fe3b30f6910ce2c1373f715450750bd7a391571812b00df1917e2be90df6c4efc54dbdfda8616278a574dea02ba2c7a31992768df8db334.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_df30604d5842ef29888c3c1881220dc6d3f8854666d94f0680c5f38aa643c5fb79b10eb9f10998d8856eb24ca265783195937434fd6c2bb8e4846df0277a7fb7.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f17fe6fb0993f1703181d7ae9e9ea570f3d33a43afd6f2a4567daa1a6745698c7b8193dc72d50991d2dd87cd3dcf663959206607d193a9b57926d061a1f50aef.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_945dcbab2c2a131f3c90f4fb91776b76066d589f84fb55bff25cd5d79a56218000616bfca1f0af9a74f32348693707af49e8fe624de8aa34f1e1c5b6a25709cf.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_65820d252e1b93596de6697fd5f02483f3e2524a0696c7d698b64745edb32bf5831a90e556842f5f88c8209766cc78ca3a41cf783d20236a9f90d4a7ea7b3e72.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_7286884797a1210857e2a36f8ab46604b0034b6abf512380447a5763c873db6a72b8547f660053de0ea69faef1eb64878f39ff4b0ea86c963efab95764a3bf5b.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_cbcf6c279ac6c6a25ae138bf964e64a5fd90d22dcdf8a53b6fe7b72cefa51063bfb0181a6e50dd2acdcae2795619887d1d83b10461e44e5103be756f2588d837.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_47965bc586b95810c925b9df3314e0c9a5cd121e70ca0831f87df0bc034695de4f83ecf2def86f737e14614ee138794473cf32cd3082a5d38db9dec0c1f266fa.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_12aa201cea075846d266536aa222d64d4088b851d87f55dac5e611b77add6826c8ebc6e82650fcd1a9e88a05a0072dedd195719c5f64cd4580a0acd8aee05d92.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_7859317dea28a85c983d7b2a933704b193600b52929d2d894deae21a5d78f1f9715214d4c2ed1b925e9183146806725621d586779705dea3b651260eb53a2f8a.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_adba9c4ca5ff387322ba7300ca9d52b9dcfdcdbdef02c258f31185a6bf4d9a2d6b12724c7fe2ffa8e48c302bffc9ab90628f579653467b0380e6574773cfe0aa.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_d87ea86dd0e7ecdd5fe7a5bb67becf943e57c3add866b456034d51663d099031bd563e12f61fdccc044969adf938a8584ed22ccd401ab8b669e20e4f92fb54e8.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_35311c3d71a3605fad4e1d6b50f3911311cdcc46418bdf56d6d0308a75a69585269ee7582a335e29989adf308fa1a81a10a2c2d4e257e9d680447a4996f6269e.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_f4fc182ef03c12e9dcadd6febc3dbaa4a29134469057ca9e8ec0be2f2de29a494514ff4b59798e74debf26f78b2df2b3e2665c69b77035761fb463b783202915.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_85c0f2769456e60153b0fd8364b82a035da53384f62de342d9bdca806f3f1ea56486919a00497a18d457949c82bf8bfacc4423fc332074ddf71a49a8fe628fff.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_67f99bef3678c549a14b5f2ff790cce6aba338dca29020755444231b45fa0f980f795e3658496ba70739a099b47b22bc2eab564343ac6132309de3adbbae3455.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_09eecfdd96206ed13830b4b93cfb2cc75cd38083671a34194437b5734b5bb38712209dc335b07e3266ceb3c3a44a155b9bbe5f3e0e1105b19dd45d3def76f020.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_4c089fbdb88e3b624a6f884d3ba1bf606f003bfcd3742376d0d353cd62181dc663aa3811a56361c3100de488fc4d6595a50de2b26f058921ba74f5f2c1b5be00.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_897ff6ac314c5f5e0f496c6af624bd9abf296a02cb5aeb850b9220b6dc3ce2fc4004cb02ed8b59d59d4b9c9d90f050d6eebc1d08ecaebab2f671f7d9367e6410.js
https://codesamplez.com/wp-content/cache/breeze-minification/js/breeze_67d1e619e71d36ae00ddcf85ee18628bb4eb64fcb3d6119b463e75cb987013420a21136d19cd03e6634ccc01cfa9af4a357930e4cf6900953b7812efb4f249fb.js