ZenOfPython
所属分类:论文
开发工具:Others
文件大小:0KB
下载次数:0
上传日期:2014-12-12 00:55:51
上 传 者:
sh-1993
说明: CSCI 3155编程语言原理的研究论文和演示文稿,
(Research paper and presentation for CSCI 3155 Principles of Programming Languages,)
文件列表:
ZenOfPythonPaper.md (15386, 2014-12-11)
ZenOfPythonPaper.pdf (197027, 2014-12-11)
ZenOfPythonPresForVideo.pdf (326385, 2014-12-11)
paperProposal.md (2597, 2014-12-11)
#The Zen of Python and Its Application
###Readability Promotes Reusable Code
**CSCI 3155 Principles of Programming Languages**
**Jessica Lynch**
**Noah Dillon**
**Max Harris**
******************************************************************************************************************
Python is highly readable due to its complete set of style guidelines and Pythonic idioms relayed in detail in the
Process Python Enhancement Proposal (PEP) #8, "Style Guide for Python Code" created by GvR, Warsaw and Coghlan
in 2001. On August 19, 2004, "The Zen of Python" by Pythoneer Tim Peters was approved as Informational PEP 20.
While PEP 8 is all about the rules for structuring your code, PEP 20 conveys the inspiration behind how you write
your Python code. You can access The Zen of Python by visiting https://www.python.org/dev/peps/pep-0020 or via the
Python terminal or command prompt by typing >>import this and pressing Enter. The below list of Python Zen points
will print to the screen unnumbered.
1. Beautiful is better than ugly.
2. Explicit is better than implicit.
3. Simple is better than complex.
4. Complex is better than complicated.
5. Flat is better than nested.
6. Sparse is better than dense.
7. Readability counts.
8. Special cases aren't special enough to break the rules.
9. Although practicality beats purity.
10. Errors should never pass silently.
11. Unless explicitly silenced.
12. In the face of ambiguity, refuse the temptation to guess.
13. There should be one-- and preferably only one --obvious way to do it.
14. Although that way may not be obvious at first unless you're Dutch.
15. Now is better than never.
16. Although never is often better than *right* now.
17. If the implementation is hard to explain, it's a bad idea.
18. If the implementation is easy to explain, it may be a good idea.
19. Namespaces are one honking great idea -- let's do more of those!
Python according to its creator Guido van Rossum provides a higher level of readability aimed at the creation of
reusable code. Guido writes in his original Python Style Guide essay, "... code can hardly be considered reusable if
it's not readable." In industry, reusable code is coveted to help achieve time and memory efficiency. Why reinvent
code that has already been written? This is not a hypothetical question. Here are the main reasons programmers opt
to write their own version of pre-existing code:
(1) The code (despite doing its job) is badly written, or in other words, is a hack job!
(2) The code is hard to understand (perhaps, just too complex and/or missing comments) even though it is
doing its job.
(3) The programmer is in too big of a hurry and can code up quickly what s/he needs.
Let's focus on statements (1) and (2) because they often bring about statement (3). Statements (1) and (2) in the
case of Python are the result of one or more violations of the Python style guidelines (PEP 8) which are summarized
in the Zen of Python (PEP 20).
The first seven Zen points of PEP 20 address the beautiful nature of Python code if written well, that is, according
to the Zen of Python. Beautiful code is achieved through a combination of explicit, simple, sparse and flat attributes
to ensure readability and therefore the potential for reusability! To illustrate, we will analyze the below code examples
based on the task of walking a directory tree containing multiple directories to generate a list of all file paths of
files contained within. Our first example violates several of the Zen points 1 - 7 and we progressively improve upon
this example with our second (better) and third (best) examples.
````python
#Example 1:
import os.path as op
def generate_file_list( filepath ):
pathList = []
path0 = filepath
dirList0 = os.listdir( path0 )
for p0 in dirList0:
path1 = op.join( path0, p0 )
if op.isdir( path1 ):
dirList1 = os.listdir( path1 )
for p1 in dirList1:
path2 = op.join( path1, p1 )
if op.isdir( path2 )
dirList2 = os.listdir( path2 )
for p2 in dirList2:
path3 = op.join( path2, p2 )
if op.isdir( path3 ):
dirList3 = os.listdir( path3 )
for p3 in dirList3:
path4 = op.join( path3, p3 )
if op.isdir( path4 ):
dirList4 = os.listdir( path4 )
for p4 in dirList4:
pathList.append( op.join( path4, p4 ) )
else:
pathList.append( op.join( path3, p3 ) )
else:
pathList.append( op.join( path2, p2 ) )
else:
pathList.append( op.join( path1, p1 ) )
else:
pathList.append( op.join( path0, p0 ) )
return pathList
````
Example 1, although it may save memory by avoiding recursion, fails to adhere to Zen points 1, 3, 5 and 6, which
furthermore, hinders readability and fails to adhere to Zen point 7.
````python
#Example 2:
import os.path as op
def generate_file_list( filepath ):
pathList = []
for root, dirs, files in os.walk( filepath ):
for filename in files:
pathList.append( op.join(root, filename) )
for dir in dirs:
generate_file_list( dir )
return pathList
````
Example 2 is a lot more readable due to its simplicity achieved through less lines of code. However, it does a lot of
unnecessary work behind the scenes. Python's os.walk module is useful to lessen lines of code, but when dealing with
big data i.e. millions of lines of code to traverse and analyze, the implementation of this module which uses
recursion can be expensive and time consuming.
````python
#Example 3:
import os.path as op
def generate_file_list( filepath ):
pathList = []
if op.isdir( filepath ):
for p0 in os.listdir( filepath ):
path1 = op.join( filepath, p0 )
if op.isdir( path1 ):
pathList += generate_file_list( path1 )
else:
pathList.append( path1 )
return pathList
````
Example 3 is in one way or another beautiful, explicit, simple, flat and sparse, and is therefore readable making it
reusable code which adheres to the Zen of Python points 1 through 7.
Zen point 8: "Special cases are not special enough to break the rules" tells us to find another way despite the
temptation of hacking together a solution. The rules are there to provide structure and organization and therefore
help to secure efficiency. Breaking them therefore, as we know, can result in hard-to-read code that cannot be
reused. For example, the rejected PEP 315 tried to add the functionality of do while loops to Python. However,
the implementation is more complicated and less readable.
````python
#Conventional way
while(True):
if():
break
````
````python
#Proposed way
do:
while():
````
One can also argue that if there is already a good way to do something, why implement another way. This goes against
another PEP 20 Zen point that "there should be one -- and preferably only one -- obvious way to do it." Zen point 9:
"Although practicality beats purity", on the other hand, addresses the rare case where the rules can be ignored to
ensure a more straight-forward answer. As is written in PEP 8, “A Foolish Consistency is the Hobgoblin of Little Minds.”
Know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment.
Look at other examples and decide what looks best. And don't hesitate to ask!
Zen point 10: "Errors should never pass silently" and zen point 11: "Unless explicitly silenced" address the significance
of implementing error-checking and error-handling in our code.
````python
#Bad example:
try:
except:
pass
````
````python
#Good example:
try:
except:
try:
except:
print
raise
````
Zen point 12: "In the face of ambiguity, refuse the temptation to guess" means that when something is not clear, look it
up and figure it out. Make sure you know and fully comprehend before coming to a conclusion. In the example below, we
illustrate how easily a guess about a try except method can have negative results. When we make assumptions, we risk
producing erroneous code.
````python
#Bad example where the variable err leaks
try:
with open(fn, 'r') as f:
lines = list(f)
except( IOError, OSError), err:
log_error( err )
````
````python
#Good example where the variable err no longer leaks
try:
with open(fn, 'r') as f:
lines = list(f)
except( IOError, OSError) as err:
log_error( err )
````
Zen point 13 says "There should be one -- and preferably only one -- obvious way to do it." The below examples illustrate
both impractical and practical approaches.
````python
#Bad (impractical) example
i = 0
while i < len(array):
print array[i]
i+=1
````
````python
#Good (practical and obvious) example
for element in array:
print element
````
This is a counter to Perl's motto: In your Python code, there should be one "best" way of doing something. However, this
one best approach may not be obvious at first unless you are Guido van Rossum to which Zen point 14 eludes,
"Although, that way may not be obvious at first unless you're Dutch." "May not be obvious at first" means that you can
always find a way to do something but the first thing you think of probably won't be the most efficient.
Zen point 15: "Now is better than never" and 16: "Although never is often better than *right* now" remind us that
sometimes a working but less than eloquent solution needs implemented immediately with plans to update and refactor it
later. However, when this is done, precautions need taken to ensure the robustness of the code being implemented.
Adequate testing needs applied and so forth to catch any and all bugs. Follow through with updating and refactoring
must be carried out to comply with the principles of code design.
Zen points 16: "If the implementation is hard to explain, it's a bad idea" and 17: "If the implementation is easy to explain,
it may be a good idea" address the importance of writing readable code. The below examples help illustrate both code
that is hard to explain and code that is easy to explain. The former hinders readability and therefore potential for
reusability. However, just because code is easy to explain does not mean it is the obvious solution or even correct. Zen
point 17 stresses the importance of checking our work and not settling on the first simple solution before we fully know
and comprehend the problem.
````python
#Code that is hard to explain
def hard():
import xml.dom.minidom
document = xml.dom.minidom.parseString(
'''FluffersCisco''')
menagerie = document.childNodes[0]
for node in menagerie.childNodes:
if node.childNodes[0].nodeValue== 'Cisco' and node.tagName == 'cat':
return node
````
````python
#Code that is easy to explain
def easy(maybe):
import lxml
menagerie = lxml.etree.fromstring(
'''FluffersCisco''')
for pet in menagerie.find('./cat'):
if pet.text == 'Cisco':
return pet
````
The last Zen point 19: "Namespaces are one honking great idea -- let's do more of those!" encourages us to optimize use
of namespaces in our Python code. A namespace is a mapping from names to objects, with the property that there is
zero relation between names in different namespaces. In Python, namespaces are defined by the individual modules,
and since modules can be contained in hierarchical packages, then name spaces are hierarchical too. They are usually
implemented as Python dictionaries, although this is abstracted away. Namespaces are typically employed for the
purpose of grouping symbols and identifiers around a particular functionality helping to create a higher level of
organization while promoting readability and the potential for reusability.
In general when a module is imported then the names defined in the module are defined via that module's name space,
and are accessed in from the calling modules by using the fully qualified name.
````python
# Example 1: Assume moduleA defines two functions : func1() and func2() and one class : class1
import moduleA
moduleA.func1()
moduleA.func2()
a = moduleA.class1()
````
The "from ... import ..." can be used to insert the relevant names directly into the calling module's namespace, and
those names can be accessed from the calling module without the qualified name as shown below. However, you risk
overwriting any pre-existing names with no warning. In order to avoid this, apply an alias by using from module
import name as nickname as shown below.
````python
# Example 2: Assume moduleA defines two functions : func1() and func2() and one class : class1
from moduleA import func1 as f1
func1()
func2() # this will fail as an undefined name, as will the full name moduleA.func2()
a = class1() # this will fail as an undefined name, as will the full name moduleA.class1()
````
In conclusion, the hallmark of Python design guidelines addressed in detail in PEP 8 and in a summarized version
in PEP 20 is the promotion of reusable code by ensuring readability. We can combine various attributes of beautiful
code and good coding practices to achieve readability which facilitates the developer's understanding of the code
being reused. The promotion of code reuse can decrease resource constrain, strengthen communication among
engineering teams, and increase productivity. Such benefits should inspire all programmers to write beautiful code.
******************************************************************************************************************
Resources:
http://docs.python-guide.org/en/latest/writing/style/
http://ruben.verborgh.org/blog/2013/02/21/programming-is-an-art/
https://www.python.org/doc/essays/foreword/ (Guido van Rossum's original Python Style Guide essay)
http://neopythonic.blogspot.com/ (Guido's blog)
http://www.stat.washington.edu/~hoytak/blog/whypython.html
http://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide
http://artifex.org/~hblanks/talks/2011/pep20_by_example.html (Blanks, Hunter)
近期下载者:
相关文件:
收藏者: