Python Module: nift

J

J

What are your thoughts on this module I created?

'''
A Python Module created by a High School Student.
Includes rev(), reet(), and leet().

Import nift

Function: nift.rev()
Description: Reverses a string
Usage: nift.rev('string')
Example: nift.rev('Testing function.')
Output: '.noitcnuf gnitseT'

Function: nift.reet()
Description: Reverses a string
and transforms to leet text.
Usage: nift.reet('string')
Example: nift.reet('Hello World!')
Output: 'dlr0W 0ll3H'

Function: nift.leet()
Description: Transforms a string
into leet text.
Usage: nift.leet('string')
Example: nift.leet('Hello there!')
Output: 'H3ll0 7h3r3!'

Setup:
* Save to Python Directory\Lib\ as nift.py
* Now you may import it by:
from nift import function
function()
OR
import nift
nift.function()

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This Module and its functions were created for my own fun, also
*
* contributing to Inter-Society. I don't mind if anyone modifies
*
* this module or adds on to it, as long as you attribute it to
*
* Myself.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
'''

def rev(string):
list = []
final = ''
for letters in string:
list.append(letters)
list.reverse()
for letters in list:
final = final + letters
return final

def reet(string):
list = []
final = ''
for letters in string:
list.append(letters)
list.reverse()
for letters in list:
if letters == 'e' or letters == 'E':
letters = '3'
elif letters == 'a' or letters == 'A':
letters = '4'
elif letters == 'i' or letters == 'I':
letters = '1'
elif letters == 't' or letters == 'T':
letters = '7'
elif letters == 's' or letters == 'S':
letters = '5'
elif letters == 'o' or letters == 'O':
letters = '0'
elif letters == 'b' or letters == 'B':
letters = '8'
final = final + letters
return final

def leet(string):
list = []
final = ''
for letters in string:
if letters == 'e' or letters == 'E':
letters = '3'
elif letters == 'a' or letters == 'A':
letters = '4'
elif letters == 'i' or letters == 'I':
letters = '1'
elif letters == 't' or letters == 'T':
letters = '7'
elif letters == 's' or letters == 'S':
letters = '5'
elif letters == 'o' or letters == 'O':
letters = '0'
elif letters == 'b' or letters == 'B':
letters = '8'
list.append(letters)
for letters in list:
final = final + letters
return final
 
C

Chris Rebert

What are your thoughts on this module I created?

* You should probably use individual docstrings for each function
rather than one giant module docstring
* Don't use 'list' as a variable name; it shadows the name of the
builtin list type
* You can use the .lower() or .upper() method of strings to get rid of
half the 'or'-s in leet() and reet(). Better yet, use a dict rather
than a long if-elif chain.
* To convert a list of strings to a single string, use
''.join(the_list) instead of:
final = ''
for letters in the_list:
final = final + letters #also, += is preferred in cases like this
* To convert a string to a list of characters, use list(string) instead of:
the_list = []
final = ''
for letters in string:
the_list.append(letters)

Cheers,
Chris
 
B

bearophileHUGS

More suggestions for a real-world Python programmer:
- There's code duplication, the original poster may express reet as a
composition of the other functions.
- A Python string/list/array can be inverted with [::-1]
- I suggest to convert the examples of the main doscstring into
doctests.
- The main docstring looks too much heavy.
- To convert many ASCII chars there's the str.translate method.
- Generally I suggest to learn to code in the small, using as little
code as possible.

Bye,
bearophile
 
G

Gabriel Genellina

More suggestions for a real-world Python programmer:
- There's code duplication, the original poster may express reet as a
composition of the other functions.
- A Python string/list/array can be inverted with [::-1]
- I suggest to convert the examples of the main doscstring into
doctests.
- The main docstring looks too much heavy.
- To convert many ASCII chars there's the str.translate method.
- Generally I suggest to learn to code in the small, using as little
code as possible.

I completely agree with all the above suggestions, except this last one.
Ok, I think I know what you mean, but a beginner might understand this
completely wrong. Readability is important, and trying to compress too
much code into one single line should not be the ultimate goal.
 
P

Paul McGuire

What are your thoughts on this module I created?
Here are a few steps to illustrate some good basic Python idioms worth
learning:

Step 1: Replace many-branched if-elif with dict

While translating characters in a string is a special case that
usually warrants using str.translate, a more general-purpose technique
to learn is to define a dict that captures the various branching
options, and then use the selecting value as a key to access the
desired branch.
Here is a dict containing your branches:

LEET_LETTERS = {
"e" : "3",
"E" : "3",
"a" : "4",
"A" : "4",
"i" : "1",
"I" : "1",
"t" : "7",
"T" : "7",
"s" : "5",
"S" : "5",
"o" : "0",
"O" : "0",
"b" : "8",
"B" : "8",
}

Now you can implement leet() using access to the LEET_LETTERS
mapping. Here are 3 different versions, that illustrate the usual
options when accessing entries from a map:
1. Look before you leet, uh, I mean "leap" (check for key existence
before using)
2. Better to ask forgiveness than permission (just use the key and
handle the exception that gets raised if the key is not found - an
homage to Grace Hopper)
3. Slightly different strategy, using dict.get() method instead of key/
indexing into the dict

def leet1(string):
outlist = []
for letter in string:
if letter in LEET_LETTERS:
letter = LEET_LETTERS[letter]
outlist.append(letter)
return "".join(outlist)

def leet2(string):
outlist = []
for letter in string:
try:
letter = LEET_LETTERS[letter]
except KeyError:
pass
outlist.append(letter)
return "".join(outlist)

def leet3(string):
outlist = []
for letter in string:
outlist.append( LEET_LETTERS.get(letter,letter) )
return "".join(outlist)

You can test each in turn without changing your test code, just assign
leet to each of these variants in turn:

leet = leet1
print leet("Hello You Beautiful Sweet World!")

I'm partial to option number 3, so let me show you a few other helpful
tips.

By the way, you can do this if you are doing any kind if if-elif, such
as:

if a=="0":
fn_1()
elif a=="1":
fn_100()
elif a=="7":
fn_greater_than_five()
....

Instead you would write:

# note: values are the methods only, no ()'s
fns = { "0" : fn_1, "1" : fn_100, "7" : fn_greater_than_five }
if a in fns:
# get desired function from fns map, and call it
fns[a]()


Step 2: dict construction instead of {} syntax

LEET_LETTERS is so space-consuming, sometimes it is easier to use the
dict constructor with a list expression of list comprehension. That
is, instead of the built-in syntax P{}'s to define a dict, you can use
the dict constructor and pass a list of (key,value) tuples.

LEET_LETTERS = dict( [("E","3"), ("e","3"), ("A","4"),
("a","4"), ...] )

Well, my fingers are tired and I'm bored already, how about if we
could just list the two strings of key and value characters, and some
how build the tuples by pulling an item from each list one at a time.
Fortunately, that is what Python's zip() function does:

LEET_LETTERS = dict( zip("eEaAiItTsSoObB",
"33441177550088") )

(I've listed the key-value pairs one above the other to illustrate how
the mapping will work, but of course, that isn't required.)

Now if I want to add another leet-speak letter (like "6" for "G"), I
just add the two characters on the end of the two strings.


Step 3: Use list comprehension instead of explicit list.appends using
for loop

As was already mentioned in another post, ''.join
(list_of_characters_to_join_together) is preferred to final +=
next_letter_to_add_to_final. But there is also a nice short and clean
way to build up the list besides explicitly calling append in a loop.
Instead, use a list comprehension. To do this, you convert:

outlist = []
for letter in string:
outlist.append( LEET_LETTERS.get(letter,letter) )

to:
outlist = [ LEET_LETTERS.get(letter,letter) for letter in string ]


In fact, Python is so smart, you can skip the list entirely, and just
pass that expression inside the brackets (called a generator
expression) directly to ''.join:

final = ''.join( LEET_LETTERS.get(letter,letter) for letter in
string )

Just a "list" is not desired variable name since it masks the built-in
list type, I avoid "string" as a name since there is a commonly-used
string module. How about just plain "s"?

Here is the final version of leet - we even got rid of the variable
final, and just return the value that would have been assigned to it:

LEET_LETTERS = dict( zip("eEaAiItTsSoObB", "33441177550088") )
def leet(s):
return ''.join( LEET_LETTERS.get(c,c) for c in s )

Soon you'll be writing Python just like all the cool kids!

-- Paul
 
B

bearophileHUGS

Paul McGuire:
LEET_LETTERS = dict( zip("eEaAiItTsSoObB", "33441177550088") )
def leet(s):
    return ''.join( LEET_LETTERS.get(c,c) for c in s )

This may be better:

from string import maketrans

def leet(txt):
leet_chars = maketrans("eEaAiItTsSoObB", "33441177550088")
return txt.translate(leet_chars)

Moving leet_chars outside the function increases speed a bit.

Or for more expert Python programmers, you can add an attribute the
object function, I don't know if you like this:

from string import maketrans

def leet(txt):
return txt.translate(leet.chars)
leet.chars = maketrans("eEaAiItTsSoObB", "33441177550088")

It's executes maketrans once only and keeps the namespace tidy. So
it's a bit like a static variable in other languages.

Bye,
bearophile
 
C

Chris Rebert

Here are a few steps to illustrate some good basic Python idioms worth
learning:

Step 1: Replace many-branched if-elif with dict

While translating characters in a string is a special case that
usually warrants using str.translate, a more general-purpose technique
to learn is to define a dict that captures the various branching
options, and then use the selecting value as a key to access the
desired branch.
Here is a dict containing your branches:

LEET_LETTERS = {
"e" : "3",
"E" : "3",
"a" : "4",
"A" : "4",
"i" : "1",
"I" : "1",
"t" : "7",
"T" : "7",
"s" : "5",
"S" : "5",
"o" : "0",
"O" : "0",
"b" : "8",
"B" : "8",
}
LEET_LETTERS is so space-consuming, sometimes it is easier to use the
dict constructor with a list expression of list comprehension. That
is, instead of the built-in syntax P{}'s to define a dict, you can use
the dict constructor and pass a list of (key,value) tuples.

LEET_LETTERS = dict( [("E","3"), ("e","3"), ("A","4"),
("a","4"), ...] )

Well, my fingers are tired and I'm bored already, how about if we
could just list the two strings of key and value characters, and some
how build the tuples by pulling an item from each list one at a time.
Fortunately, that is what Python's zip() function does:

LEET_LETTERS = dict( zip("eEaAiItTsSoObB",
"33441177550088") )

(I've listed the key-value pairs one above the other to illustrate how
the mapping will work, but of course, that isn't required.)

Now if I want to add another leet-speak letter (like "6" for "G"), I
just add the two characters on the end of the two strings.

This I disagree with as being unnecessarily clever; the dict literal
is just fine as-is and the zip() makes it less clear. However, I would
definitely rewrite the dict to use less lines, which, after removing
the capital dupes (as I mentioned in my post, just use .lower()),
looks like:

LEET_LETTERS = {"e" : "3", "a" : "4", "i" : "1", "t" : "7", "s" : "5",
"o" : "0", "b" : "8"}

which is better, IMHO.

Cheers,
Chris
 
B

bearophileHUGS

Gabriel Genellina:
bearophile:

I completely agree with all the above suggestions, except this last one.  
Ok, I think I know what you mean, but a beginner might understand this  
completely wrong. Readability is important, and trying to compress too  
much code into one single line should not be the ultimate goal.

What I meant is to use less code as possible, keeping readability and
the original flexibility.

I can't stress enough the importance of writing less code. Every new
programmer has to learn how much important it is. Less code means less
bugs, less lines to edit and debug, etc. Less code is usually more
elegant, and often more readable (even if you take 3 times to read
each line it may be good anyway if you have 1/10 of the lines of code.
Recently in the "Java to Python" thread someone has posted some Java
class that is scary, you can probably write the same thing in
1/10-1/20 of the lines of code).

The sense for "elegance" in coding is of course (as in every other
human activity) something you learn after many years of exercise, it's
a matter of balance among many opposite things, a matter of
compromises, and it's also tight related with your personal style of
coding. Every programmer develops tastes and and one or more styles,
that other people may not appreciate much.

Bye,
bearophile
 
J

J

Thanks for your answers, especially Chris Rebert and Paul McGuire's. I
have a question:
How far does Python go in the Game Development field? (Using Python
only, no extensions)
 
C

Chris Rebert

Thanks for your answers, especially Chris Rebert and Paul McGuire's. I
have a question:
How far does Python go in the Game Development field? (Using Python
only, no extensions)

You pretty much need to integrate with some C(++) libraries in order
to write fancier games. However, you yourself don't need to write any
non-Python in order to utilize these libraries.
Pygame (http://www.pygame.org/) is a popular collection of multimedia
library bindings for Python.

Cheers,
Chris
 
P

Paul McGuire

This I disagree with as being unnecessarily clever; the dict literal
is just fine as-is and the zip() makes it less clear. However, I would
definitely rewrite the dict to use less lines, which, after removing
the capital dupes (as I mentioned in my post, just use .lower()),
looks like:

LEET_LETTERS = {"e" : "3", "a" : "4", "i" : "1", "t" : "7", "s" : "5",
    "o" : "0", "b" : "8"}

Maybe so, I was trying to illustrate zip() and maybe this was getting
too far ahead for a new Python user.

I *do* find that when initializing a list of characters (and for some
reason a string wont do), then instead of this:

vowels = ["A", "E", "I", "O", "U"]


using the list constructor is much easier:

vowels = list("AEIOU")


Or more non-deterministically,

sometimes = lambda s : if random.random() > 0.5 else []
vowels = list("AEIOU") + sometimes("Y")


-- Paul
 
T

Terry Reedy

J said:
What are your thoughts on this module I created?

'''
A Python Module created by a High School Student.
Includes rev(), reet(), and leet().

Gutsy of you to post this.
Setup:
* Save to Python Directory\Lib\ as nift.py

Add-in modules and packages like this should better go in
pythonxy/Lib/site-packages, which is there just for this purpose.
One can then easily see what add-ons ore present or not, or delete them,
or avoid deletion with uninstallation, or move to another version of
Python.

tjr
 
S

Steven D'Aprano

Gabriel Genellina:

What I meant is to use less code as possible, keeping readability and
the original flexibility.

I think a better description is, use as little code as you need, and no
extra, but no less. As Einstein said about physics theories: "As simple
as possible, but no simpler."

I can't stress enough the importance of writing less code. Every new
programmer has to learn how much important it is. Less code means less
bugs, less lines to edit and debug, etc.

[pedant]
There's less code, fewer bugs and lines. Less applies to continuous
quantities, like weight and "amount of code", and fewer applies to
countable quantities.

Don't worry, I frequently get it wrong too, and I'm a native English
speaker :)

Less code is usually more
elegant, and often more readable (even if you take 3 times to read each
line it may be good anyway if you have 1/10 of the lines of code.
Recently in the "Java to Python" thread someone has posted some Java
class that is scary, you can probably write the same thing in 1/10-1/20
of the lines of code).

Within reason, naturally. There's a reason why we write:

for button in buttons:
move(button, delta_x, delta_y)

instead of

for b in bs: mv(b, x, y)

even though the second is significantly shorter. Keyword arguments versus
positional arguments is another example where more verbose code is easier
to read and maintain than shorter code.


Also, I don't think there's much advantage in trying to push new
programmers to reduce the amount of code. Until you're really comfortable
with the language, you need training wheels and scaffolding in the form
of verbose code. Sometimes you really don't appreciate Python's labour
saving features until you've experienced how much labour there is to be
saved.
 
B

bearophileHUGS

Steven D'Aprano:
There's less code, fewer bugs and lines. Less applies to continuous
quantities, like weight and "amount of code", and fewer applies to
countable quantities.

Thank you, I'll try to improve my use of the language.

Within reason, naturally. There's a reason why we write:
for button in buttons:
    move(button, delta_x, delta_y)
instead of
for b in bs: mv(b, x, y)
even though the second is significantly shorter.

Often Shortening names and packing more stuff in single lines that
deserve to be two lines aren't good ways to shorten code.

Also, I don't think there's much advantage in trying to push new
programmers to reduce the amount of code. Until you're really comfortable
with the language, you need training wheels and scaffolding in the form
of verbose code. Sometimes you really don't appreciate Python's labour
saving features until you've experienced how much labour there is to be
saved.

I don't agree. When you learn to code you also have to learn what does
it mean to write "good code", you have to learn that there are several
things that are important beside writing a correct output, like good
comments, well thought out names, good indentation, good idioms, quick
running time, small memory usage, writing clear and readable code, and
later develop elegance, the power of composition, abstraction,
indirection, meta programming, etc. Among such things there's the
importance of writing short programs. All such things are the seeds
that will develop into the personal style of the future programmer.

Such things are also useful for another purpose: to help the student
understand that code is craftsmanship, so she/he/shi can (and is
supposed to) be proud of the code that writes. This helps the student
understand that programming isn't just an ugly way to tell orders to a
moronic CPU, that helps develop appreciation for the act of writing
code, because it becomes something you do also for the sake of it, as
you do art, beside for usefulness. So you have to teach and show such
things from more or less the beginning.

Bye,
bearophile
 
R

r0g

J said:
Thanks for your answers, especially Chris Rebert and Paul McGuire's. I
have a question:
How far does Python go in the Game Development field? (Using Python
only, no extensions)


Hey J,

Python's all about the libraries (extensions), you won't be able to do
much without them but that's no big whoop. AFAIK most python libs are
released under LGPL or BSD style licenses so there's pretty much no
restriction on what you can use them for. A lot of games are written in
C for performance reasons but most python gaming libs are just wrappers
round C gaming libs and share the same names and methods so your
knowledge should travel with you.

As for which libs to use...

There's PyGame which is a a good mature library for 2D stuff.

Pyglet seem to be the most popular OpenGL lib for 3D stuff.

You might also want to look at the "Blender Game Engine" and the free
game "Yo Frankie", they use C for the heavy lifting and Python for
scripting levels and stuff, it might be a good way to test the waters.

Regards,

Roger Heathcote.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top