Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attributes of Python module `this`

Tags:

python

Typing import this returns Tim Peters' Zen of Python. But I noticed that there are 4 properties on the module:

this.i  this.c this.d this.s 

I can see that the statement

print(''.join(this.d.get(el, el) for el in this.s)) 

uses this.d to decode this.s to print the Zen.

But can someone tell me what the attributes this.i and this.c are for?

I assume they are there intentionally - answers to this question seem to suggest there are other jokes to be gleaned from the wording of the Zen. I'm wondering if there is a reference I'm missing with these 2 values.

I noticed that the values differ between Python versions:

# In v3.5: this.c Out[2]: 97 this.i Out[3]: 25  # In v2.6 this.c Out[8]: '!' this.i Out[9]: 25 
like image 378
Noel Evans Avatar asked May 18 '16 13:05

Noel Evans


People also ask

What are Python module attributes?

A module is a Python object with arbitrarily named attributes that you can bind and reference. Simply, a module is a file consisting of Python code. A module can define functions, classes and variables.

How do you show attributes of a module in Python?

You can use dir(module) to see all available methods/attributes.

What is a module attribute?

Module attributes in Elixir serve three purposes: They serve to annotate the module, often with information to be used by the user or the VM . They work as constants. They work as a temporary module storage to be used during compilation.

How do I print all attributes of a module?

After you import the os module, then we pass the os module into the dir() function. This outputs all of the attributes and functions of the os module. This prints out all of the attributes and functions of the os module. You can see there are functions such as listdir, mkdir, makedirs, etc.


1 Answers

i and c are simply loop variables, used to build the d dictionary. From the module source code:

d = {} for c in (65, 97):     for i in range(26):         d[chr(i+c)] = chr((i+13) % 26 + c) 

This builds a ROT-13 mapping; each ASCII letter (codepoints 65 through 90 for uppercase, 97 through 122 for lowercase) is mapped to another ASCII letter 13 spots along the alphabet (looping back to A and onwards). So A (ASCII point 65) is mapped to N and vice versa (as well as a mapped to n):

>>> c, i = 65, 0 >>> chr(i + c) 'A' >>> chr((i + 13) % 26 + c) 'N' 

Note that if you wanted to ROT-13 text yourself, there is a simpler method; just encode or decode with the rot13 codec:

>>> this.s "Gur Mra bs Clguba, ol Gvz Crgref\n\nOrnhgvshy vf orggre guna htyl.\nRkcyvpvg vf orggre guna vzcyvpvg.\nFvzcyr vf orggre guna pbzcyrk.\nPbzcyrk vf orggre guna pbzcyvpngrq.\nSyng vf orggre guna arfgrq.\nFcnefr vf orggre guna qrafr.\nErnqnovyvgl pbhagf.\nFcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.\nNygubhtu cenpgvpnyvgl orngf chevgl.\nReebef fubhyq arire cnff fvyragyl.\nHayrff rkcyvpvgyl fvyraprq.\nVa gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.\nGurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.\nNygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.\nAbj vf orggre guna arire.\nNygubhtu arire vf bsgra orggre guna *evtug* abj.\nVs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.\nVs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.\nAnzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!" >>> import codecs >>> codecs.decode(this.s, 'rot13') "The Zen of Python, by Tim Peters\n\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!" 

As for the difference in Python 2.6 (or Python 2.7 for that matter) versus Python 3.5; the same variable name c is also used in the list comprehension in the str.join() call:

print "".join([d.get(c, c) for c in s]) 

In Python 2, list comprehensions do not get their own scope (unlike generator expressions and dict and set comprehensions). In Python 3 they do, and the c value in the list comprehension is no longer part of the module namespace. So the last value assigned to c at the module scope is 97 in Python 3, and this.s[-1] (so a '!') in Python 2. See Why do list comprehensions write to the loop variable, but generators don't?

There is no joke embedded in these 1-letter variable names. There are jokes in the Zen itself. Like the fact that between the source code for the this module and the text itself you can find violations for just about all the rules!

like image 196
Martijn Pieters Avatar answered Sep 22 '22 23:09

Martijn Pieters