montecarl 373 days ago [-]
This part is a little dated (it is a 2012 post after all):

In Python 3 __cmp__ is ignored and you have to use the other methods. To make this easier, you can use

gvx 373 days ago [-]
Yeah. In Python 3, __div__ is gone, and only __floordiv__ and __truediv__ exist.
opencl 373 days ago [-]
It's amazing that Python 3 was 4 years old when this post was made and yet saying "Python" was still implicitly assumed by basically everyone to mean 2.x.
kjeetgill 373 days ago [-]
Is it that amazing? I don't think I've had use 3 until this year and I still have to flip-flop.

AND I say this as someone who was reading peps going into 3's release.

Do Ubuntu or Fedora default to python 3 yet? Arch? My RHEL experience isn't as representative.

bhrgunatha 373 days ago [-]
Arch's default is Python 3, but there are still many official Python 2 packages, mostly in community i.e. adopted from the AUR:

Core: 1

Extra: 96

Community: 822

AUR: Over 2300 depending on how you search

lathiat 373 days ago [-]
The official python recommendation is not to "default" the 'python' command as python3, and they should just explicitly be 'python' and 'python3'

This is what every distro except arch does (for whatever reason)

mkesper 373 days ago [-]
But that should turn around NOW, comsidering 2020 will be EOL for Python2 (except for Redhat which will have to ride that dead horse for years to come).
cferr 372 days ago [-]
RHEL 8 will ship with Python 3 as the default.

opencl 372 days ago [-]
What I was saying is that it's amazing Python 3 failed to gain any significant traction in 4 years. I personally have been using Python 3 since ~2010 but am apparently in a tiny minority on that.
sethgecko 373 days ago [-]
Ubuntu 18.04 ships with Python 3.6 and no python2
kqr 373 days ago [-]
This is a great explanation and a must-read for Python developers. Once you know this stuff, you'll be a much stronger debugger.

But it's also worth throwing a warning out there: when you first learn about a new type of magic, you'll be tempted to use it everywhere. Be careful!

I can recognise a clear specific period in my Python work which was just after I had read this, and a bunch of things suddenly became implicit.

nomel 373 days ago [-]
> Once you know this stuff, you'll be a much stronger debugger.

As you suggest, more accurately, you'll require the next person who debugs your code to read this, making them much better at debugging your code.

I no longer use magic and completely avoid meta programming in python. It confuses everyone, is not needed (just use a boring factory function), and severely limits who can help you work on your code, for what? A few lines of less boilerplate here and there? "Succinctness"? Some sort of "elegance"? More likely, a DSL that nobody understands but you!

The more I write, and mostly the more I interact with other people, the more I realize that code needs to be boring. No magic. I think this is why go is succeeding: no magic.

rootusrootus 373 days ago [-]
100% agree. I figure this is a big part of what turns normal developers into senior developers, and lead developers. It's easy to code. What takes wisdom is 1) knowing what not to write, and 2) self control on how you write it. As a mentor I try to convey this to the fresh new supercoders joining our team.
florabuzzword 373 days ago [-]
My reaction to this, as someone who doesn’t use many of these on a regular basis (probably guilty of overusing __new__ though) is actually that I can imagine these causing some real problems. The operator ones seem particularly tempting and dangerous at the same time.
ubernostrum 373 days ago [-]
Operator overloading, in any language that supports it, has always been controversial, so Python doesn't really add anything new there.

The thing is, it's also incredibly useful at times. Language features that are "useful when you have the use case for it, confusing when you don't" tend to provoke that reaction.

int_19h 373 days ago [-]
In Python, though, operator overloading is not merely "supported". It's how all operators are defined, including built-in ones.

   >>> dir(123)
   ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', 
   '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__',
   '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__',
   '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', 
   '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', 
   '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', 
   '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', 
   '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', 
   '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 
   'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

   >>> (1).__add__
   <method-wrapper '__add__' of int object at 0x678C40A0>

   >>> (123).__add__.__doc__
   'Return self+value.'

   >>> (1).__add__(2)
Which is a good thing, because it makes the whole arrangement a lot more consistent that languages in which this sort of thing is just magic associated with a specific primitive type (sometimes it's even inconsistent - e.g. in C#, + for ints and strings is magic, but + for decimal is an overloaded operator). In Python, all that magic is confined to the magic methods. Learn them once, and they work the same everywhere.
florabuzzword 373 days ago [-]
Oh yeah, don’t get me wrong. It’s cool as hell! I’m totally gonna use it for a GUI menu-building script interface I’m making right now :).

I have just never done it before, and I think this is the first time I have seen the concept, so the first thing that popped in my mind we’re all the things that can go wrong. But, also all the things that can go right.

Puer 373 days ago [-]
Could you give an example of how you would use these methods to debug versus other methods/approaches? I'd love to hear if you're willing to share--I program mainly in Python these days but Python's magic methods are definitely something I need to understand at a deeper level.
travisjungroth 373 days ago [-]
Fluent Python has a chapter on these methods and I highly recommend it. Also, these are much better described as dunder methods (short for double underscore) than magic methods. There's really no magic to them.
florabuzzword 373 days ago [-]
Wonderful. I’ve never seen this resource before.

A related article I got a lot out of was ‘Understanding Python Metaclasses’, an in-depth breakdown of Python class instantiation. Here’s the link to that:

pypypypypypy 373 days ago [-]
It's awesome that someone has taken the time to write this all up. With reference to this section ( the author mentions that descriptors are "meant to be held by an owner class." which is true, however in their example, they are storing the value as `self.value` on the descriptor object itself meaning that if the user were to have two instances of `Distance` all their values would be the same for meter or foot on all instances of `Distance`. One way to solve this is to store the values in a dictionary-like structure on the descriptor, e.g. `[instance] = your_stored_value`.
devxpy 373 days ago [-]
It is when you get to this part of python, that you achieve true Nirvana.

It's absolutely bonkers the extent to which you can be dynamic in this language.

It's the very reason why Django is so DRY.

Waterluvian 373 days ago [-]
Django's DRY suuuuuuuucks when you're getting started. It's basically all this magic that you can't understand without already knowing Django.

Why does get_attr get called? Oh because it begins with the word "get" and there's an attribute that defines a method field called "attr".

I use Django a lot and generally it's great. But I hate that you can't follow your code paths from start to finish on the surface. You have to know about how it works underneath. Meaning you can't just be a python + web server expert. You have to also be a Django expert. So I get non-Django experts reviewing code and they have no clue why things work or break.

Just an opinion. Not saying this is objectively wrong.

sbjs 373 days ago [-]
People who feel this way usually use Flask instead. Worth checking out.

Waterluvian 373 days ago [-]
Flask is great for smaller things where Django is far too verbose. Like single file webservers for basic stuff.

Its also for more complex stuff but then you have to grab additional libraries to do stuff like db management, migrations, serialization, etc.

Flask also has some, in my opinion, rather uncomfortablly unintuitive global scope stuff. Where responses aren't passed into the view function, they're available on the imported flask object.

sbjs 373 days ago [-]
Good to know. I haven't used Flask recently, I have used Express.js which is Node.js's version of Flask, and I really like how simple it is. Most apps these days seem to have a REST (or GraphQL) backend and dynamic (often React.js) frontend. Flask (and Flask-RESTful) would probably be a better fit for this type of app than Django.
Waterluvian 373 days ago [-]
Yeah don't let me dissuade you. Flask is a prime piece of software.
devxpy 373 days ago [-]
Wierd. Maybe it's just me, but I felt that way for the first 2 days.

I have made some really dynamic stuff (like 100 domains running off a single server with each of their data separate, and to add a new domain is a click away) . I can't imagine doing that with other frameworks

> get_attr

What the fuck is that?

Also, you might be interested in webpy

> “Django lets you write web apps in Django. TurboGears lets you write web apps in TurboGears. lets you write web apps in Python.” — Adam Atlas

nikofeyn 373 days ago [-]
why is this so bonkers? it seems like it's just basic patterns of method overriding and operator overloading.

if people think this is so magic, it's almost as if lisps, schemes, and prologs never existed.

jlarocco 373 days ago [-]
> if people think this is so magic, it's almost as if lisps, schemes, and prologs never existed.

I write quite a bit of Lisp, and the conclusion I've come to is that for 95% of software developers, Lisp, Scheme, and Prolog might as well not exist. Even here on HN, where I'd expect the bar to be a little higher, the amount of incorrect info posted about Lisp is pretty crazy.

I'm almost certain most people's only experience with Lisp(s) and Prolog was a week or two using it in their programming languages class at university.

matheusmoreira 372 days ago [-]
I felt the same way as I learned Python. People told me Python had this magical framework built into the language and that I'd understand everything once I learned it. Turns out the built-in language features are syntax sugar for some __special_method__ calls. Simple and functional, but underwhelming...
sbjs 373 days ago [-]
But this article is just explaining operator overloading, right? Doesn't everyone learn that halfway through semester in C++ 101?

And operator overloading has nothing to do with DRY, in fact it's generally better to avoid it except for in very niche situations, like adding __add__ to a matrix type.

misiti3780 373 days ago [-]
can you explain what you mean about django ?
lalos 373 days ago [-]
olooney 373 days ago [-]
Be sure to read "Appendix 2: Changes in Python 3" at the very end of the document! I was preparing a long "Actually..." rant before I saw that.
saagarjha 373 days ago [-]
> Be careful, however, as there is no guarantee that __del__ will be executed if the object is still alive when the interpreter exits, so __del__ can't serve as a replacement for good coding practices (like always closing a connection when you're done with it.

When the interpreter exits, your program's resources should be reclaimed by the operating system, right? So why not just use __del__?

gvx 373 days ago [-]
You almost always only want to implement __del__ if you're writing an extension in C. Otherwise, the GC generally takes care of cleanup perfectly fine.

And in cases like the one cjhanks describes, __del__ doesn't get called reliably enough. In those cases, using a contextmanager is better.

cjhanks 373 days ago [-]
Say it's a socket and you want to send some sort of "END_OF_STREAM" message before closing.
pfranz 373 days ago [-]
That wouldn't work if you expected __del__ to cleanup lock files or temp files or to manage other external resources.
lstyls 373 days ago [-]
If this were the case, there would be no need for SIGTERM. The OS doesn't know the application logic and can't guarantee clean termination from the application's perspective.

As others have said, there's rarely reason to override `__del__`, and when you do you know exactly why you need it.

falsedan 373 days ago [-]
The python interpreter can choose not to call it. I've had to register essential cleanup with `atexit` instead.
jl2718 373 days ago [-]
This is a godsend. Thank you. Without this, I’d nearly given up on python already, but, wow, thank you.
deathanatos 373 days ago [-]
While there's no harm in having a second guide, I just want to make sure folks do know this is in the official documentation:

(The article will perhaps be a better guide to those newer; the data model page is … pretty dense.)

Also, I find is exceptionally handy to have a Chrome "search engine" for the Python docs while I work. That is, on chrome://settings/searchEngines I have added a custom search engine with this setup:

  Search Engine: Python Docs
  Keyword: py
(The URL is an "I'm feeling lucky" search on Google, limited to the Python 3 docs. Note that it is set to search Python 3.)

This allows me to type, e.g.,

  py data model
in the URL and get the above page. Want the asyncio module docs?

  py asyncio

(I similarly have "mdn" for the docs, which are also excellent.)
meowface 373 days ago [-]
Good guide, but missing Python 3's __next__.