DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Languages
  4. Sometimes Python is magic

Sometimes Python is magic

Giorgio Sironi user avatar by
Giorgio Sironi
·
Mar. 22, 12 · Interview
Like (0)
Save
Tweet
Share
7.62K Views

Join the DZone community and get the full member experience.

Join For Free

Python's magic methods have probably inspired other languages such as PHP in providing special functionality that ties into method with standard names, with a very low probability of conflicting with existing methods and no need for implementing interfaces (where they exist). All these methods have a name that starts and ends with two underscores, such as __method__, and is reserved for magic usage.

Magic methods are not always clean as they are called automatically in particular situations or due to operator overloading. They act as syntactic sugar, binding < or a field access to some lines of code

The standard ones

The most famous magic method you have for sure called is the constructor of an object. The arguments passed to the class callable during instantiation are passed to __init__ automatically:

class Car:
    def __init__(self, maximumSpeed):
        self.maximumSpeed = maximumSpeed

__str__ and __repr__ instead can be defined to provide a standard string representation of an object. __str__ is a readable representation, while __repr__ is more of a unambiguous dump:

    def __repr__(self):
        return "Car(maximumSpeed=%r)" % (self.maximumSpeed, )
    def __str__(self):
        return "Car%s" % (self.maximumSpeed, )

The mathematical ones

You may call them algebrical operators, as they allow the overloading of operators also in the case of non-numerical classes like those representing Value Objects.
Probably the most famous operators in this category are the equality and comparison ones:

    def __eq__(self, another):
        return self.maximumSpeed == other.maximumSpeed
    def __lt__(self, another):
        return self.maximumSpeed < other.maximumSpeed

There are similar magic methods for comparisons different than <: __le__, __ne__, __gt__, __ge__. __cmp__ is deprecated and won't be supported in Python 3 instead.

Along with __eq__, if only for the Java flavor, we should cite __hash__, a method that should provide the same value for each equal objects. Thus, like in the Java case, returning always 0 is a valid choice; different values will instead improve performance by reducing collision.

The attribute ones

__getattr__ and __setattr__ allow for the interception of object properties access and modification:

    def __getattr__(self, name):
        return self.dict[name]
    def __setattr__(self, name, value):
        self.dict[name] = value

__delattr__ allows also for the removal of an attribute via the del operator.

Note that the default behavior for object attributes is to put and get them from the instance's own dictionary, so the implementation you have just read won't add anything to an object.

The container ones

You can implement a container type in Python by extending a dictionary or a list, but a Plain Old Python Object can conform to the same syntax (and so, to the same interface) by defining a few magic methods. For example, you could wrap a dictionary:

    def __len__(self):
        return len(self.wrappedDictionary)
    def __getitem__(self, key):
        return self.wrappedDictionary[key]
    def __setitem__(self, key, value):
        self.wrappedDictionary[key] = value
    def __contains(self, key):
        return key in self.wrappedDictionary

This set of methods results in the len() function, the object[] notation and the in operator working as on the dictionary while called on the wrapping object.

The numerical ones

While the algebric operators are not stirctly part of the arithmetic domain, you can override all the other operators via numerical magic methods:

    def __add__(self, another):
        return Car(self.maximumSpeed + another.maximumSpeed)

You can now sum Car objects, which is probably more dangerous than beneficial. Stick to types defined in the numerical domains (like complex numbers or vectors) when overriding + and the other operators.

The most generic one

__call__ allows you to handle calls to the object itself, when used like a functions or any other callable:

    def __call__(self, args):
        return "You have just called self(args[0], args[1])

args is a list of parameters, and can be of variable length.

Note that in other languages like PHP, __call specifies an handler for non-defined methods, like Ruby's method_missing; this handling usually forwards the call to a wrapped object, in order to implement the Decorator or Adapter pattern. Python is more similar to JavaScript in this respect as methods are attributes of an object that happen to be callable:

    def __getattr(self, name):
        return getattr(self.wrappedObject, name)

You can know call object.methodX() as an equivalent to object.wrappedObject.methodX(); the method itself is a callable object resolved before the call is performed.

Python (language) Object (computer science) Operator (extension)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Microservices Testing
  • Using Swagger for Creating a PingFederate Admin API Java Wrapper
  • The 5 Books You Absolutely Must Read as an Engineering Manager
  • Top 5 Data Streaming Trends for 2023

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: