To answer the question directly:
The best code is simple - it should be self explanatory, but that doesn't mean there should be no comments. Function names should define exactly what they do... But its hard to be perfect.. And, if you ever intend others to read your code and / or learn from it or maintain it ( such as in a business environment ) then you will need a coding standard and it must be adhered to, and comments will help the next person who comes along.
No comments means more wasted time to remember what something does if you come back to it years later... I have code still in use I wrote decades ago because I simplify logic into building blocks - porting code from one language to another is much easier when doing this ( see below regarding repetition, etc.. )..
If you want to make yourself think that your company won't fire you if you don't include comments - you are likely mistaken unless you are the best at your job ( but then you'd also include comments ) and underpaid.. Then, the employer won't give you a positive review when you apply elsewhere because you purposely made it difficult to go through all of the code to determine functionality for the next person for them to comment.
Even if the code is only for you - as I mentioned I am still using code I wrote decades ago ( and Intel is using a 40+ year old command architecture in their processors with additions if I recall correclty [ 8086? ] ) - it's best to include comments, especially if you do not have perfect recall.
If space was the problem, then everyone would use tabs instead of spaces to indent Python code.
For instance: A 1MB Python file indented using spaces is typically around 200KB when using tabs. A HUGE Difference.
Less chars means less to process as well.
I teach, so I always comment my code quite well - what pains me is when reviewing student code from a file named example.py and its so densely packed ( I prefer airy, ie x[ 'abc' ] instead of x['abc'] and when you have hundreds or thousands of lines which read like a book rather than code, it can be tiresome as we humans are good at pattern recognition - ie looking through indents, spacing, etc.. can help us interpret code more efficiently, but no spaces makes it harder to spot errors.
It's why we are albe to raed tihs and smeoihtng legnor eilsay - it's why we are able to read this and something longer easily... Our brain fixes the errors for us in order to make sense of it... So if you come across something close together without spaces and it starts and ends with the proper character, it's super easy to skip over.. For instance, def name( ):: can easily be overlooked with thousands of lines... Just as easily as def name( ) if you code with other languages... ), no comments, etc...
A few other things - when using tabs to indent code, you can easily, with most editors, change the size of spaces each tab character represents meaning if you prefer using 2 spaces, 4 spaces, 8, etc... you can easily set it... It may not be about preference either... Someone with visual deficits may find it a lot easier to code with a larger or smaller indentation and that can be done with a simple menu option or command.. Similarly for airy style of coding, it can help those with visual deficits, and make interpreting code that much more efficient for those without serious visual deficits.
All of this is related... Here are some more tips aside from using Tabs, the size-cost for not, etc..:
I urge you to develop or use a coding standard to ensure your code is written a specific way to help spot errors and to take advantage of how to brain processes text. Here's some of what can be defined... But, it revolves around the entire feel of the code - how it looks, variable naming techniques, commenting styles, and so much more...
In Python underscores have specific meaning, but my coding standard actually works with what I use... no underscores = global / file scope, 1 underscore is local / argument local / etc.., 2 underscores means an internal / private variable. CONSTants and ENUMs are always uppercase. I also use MAP_ and MAPR_ prefixes for CONSTant maps for ENUMs ( map and reverse map ) to lookup data and reverse it...
Using underscores means if there is an error, I know IMMEDIATELY know the scope the variable should be so if I see error _blah global is undefined or something, then I can clearly see _ means it should be a local so something is bleeding through, overwriting or some other issue which needs to be looked into - saving valuable time for debugging.
I have my own set of reserved variable names which are only used in certain scenarios - for instance in Garry's Mod Lua I use _p for Player Entity, _w for Weapon Ent, _ent for General Entity, _npc for NPC Ent, _vm for View Model Ent, _pos for Position ( uses Vector object ), _ang for Angle, and more... This means if I encounter an error with any of these, I know exactly what data-type is used without exception. There are a lot more.
For commenting, I use 2 blank spaces, then 3 lines of //s for each function with the center // having a description of the function. If the language doesn't use //s for comments, then I use 2 characters - for instance in Batch you can use ; so I use ;;s, Python uses # so I use ##s, and so on..
I am porting my function / class comment headers over using this system to include Java style @arg:, @return:, and so on style additions by adding a 4th and 5th line, with the 4th having @..: ... ( and if I add more than 1, then I always keep an empty comment line below the last one above the function / class line... I am adding this because I love automation and because of my reserved variables, etc.. I can combine all of the data from my coding standard and automatically create WIKI pages for everything I code and have them be incredibly accurate with no input, or very little input, from me.
So there are other benefits from using a coding standard and sticking with it aside from clarity, efficiency, automation, etc..
I usually format my coding standard layout using a few pages describing certain aspects and providing examples - it's a very quick way to show exactly what you mean.
Here's a very old version of it I have on Dropbox: https://www.dropbox.com/s/yjfrw9bqih...dards.lua?dl=0
-- This one has some of the differences between GMod Lua and Vanilla Lua
A few other notes - any time I repeat anything in code, I turn it into a helper function thus turning 2 or more lines into 1 each time...
I also change default functions which are ridiculous - for instance DrawRect( x, y, x2, y2 ) is much easier to code with ( and shorter math when overlapping to make a bordered rectangle ) DrawRect( x, y, w, h )... I don't overwrite the default functions, but I create new functions with those easier / more straight-forward logic..
Basically, instead of having to call DrawRect( x, y, w + x, y + x ) I can just call DrawRectEx( x, y, w, h ) and the rest is taken care of... In some cases the replaced functions need to be shifted by 1 so thats 1 less thing needed to be done done each time you call that function, etc..