Trying to get into good code habbits

Trying to get into good code habbits

Author
Discussion

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 17th March 2015
quotequote all
Hey guys,

Im currently filling my spare time messing around with python and learning how to use it blah blah blah.

Ive created a couple quick a dirty programs to get me used to the new syntax im learning and when best to use it.

ill paste my code below.

Its a simple program to calculate the area of a triangle. with pretty basic error checking.

if any of you have suggestions on making it more elegant or "pythonic" as they say; i'd love to hear it smile

I appreciate that im probably on completely the wrong website for receiving feedback on this sort of thing, but signing up for new webforums all the time is alot of effort!



#! /usr/bin/env python

#
#
#========= ( EXPLANATION OF FIRST LINE )=========#
#
#

'''
If you have several versions of Python installed, /usr/bin/env will
ensure the interpreter used is the first one on your environment's
$PATH. The alternative would be to hardcode something line
#!/usr/bin/python or the like -- that's OK but less flexible.

In Unix / Linux, an executable file that's meant to be interpreted can
indicate what interpreter to use by having a #! at the start of the
first line, followed by the interpreter (and any flags it may need).

With other platforms like Windows, of course, this rule does not
apply (but that "shebang line" does no harm, and will help if you ever
copy that script to a platform with a Unix base, such as Linux or Mac.
'''

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
#
#========= ( SYSTEMPARANOIAS INTRODUCTION NOTES )=========#
#
#

'''
Program created by SYSTEMPARANOIA 3/2015
Final revision and most robust version of python calculator that not
only works out the area of a triangle using the base x height divided
by 2 method.
It also has an Error Checking function on the user input to make sure
the user is entering a number and not a letter and forces the program
to run again if an error is found.
I have also added a continuation function to allow the programme to exit
cleanly when the user is ready.
This version is set within a (while) loop using multiple
definitions (def) that can be called repeatedly in this and other
programs.
This version gives the workings out for the user and exits cleanly.
'''

#
#
#========= ( DEFINITIONS OF FUNCTIONS )=========#
#
#

'''
This function performs the main calculations for the program and
prints the results on screen including the workings out for the sum.

To explain the first print statement, see sample code below:

name = 'maths'
number = 42
print '%s %d' % (name, number)

will print maths 42.

Note that name is a string (%s) and
number is an integer (%d for decimal)

'''

def triangle(base, height): # Name of the function with arguments
base = float(base) # Convert Variable to decimal
height = float(height) # Convert Variable to decimal
area = base * height / 2 # Perform calculation
print "The working out is, %d x %d / 2" % (base, height)
print "Base x height =", base * height
print "Once divided by 2 the area of your triangle is ",area

'''
This Function performs a check of the user's input to make sure
that it is a number and will not cause the program to crash due to
the user entering a string.
'''

def is_number(n): #Name of the function with argument
try: #Attempt the following action
float(n) #Convert to float with argument
return True #If successful return True
except ValueError: #Check if error message is received
return False #If Error, return False

'''
This function performs a check if the user would like to continue
and run another calculation, or to end the program. it returns a true
or a false value.
'''

def re_run(c): #Name of Function with argument
c.lower() #Force string to Lower case
if c == "y" or c == "yes": #If one of these values are True then..
return True #End function with True value
else: #If both are False then..
print "\nGood Bye\n" #Print String
return False #End function with False value

#
#
#========= ( DEFINITIONS OF VARIABLES )=========#
#
#

'''
This variable is what the while loop checks to see if it should
loop again or not. Once set, a variable can be changed to any other
value at any time
'''

i = True #Set variable to True

#
#
#========= ( DEFINITIONS OF PROGRAM LOOPS )=========#
#
#

# Start of loop, check if 'i' is true, otherwise do not loop
while i == True:
print "\nThis programme calculates the area of a triangle\n"
base = raw_input("Enter Base Value: ")
height = raw_input("Enter Height value: ")
# Call function and check if both results return a True value
if is_number(base) and is_number(height):

# Print contents of triangle function
print triangle(base, height)

#If error or exception
else:
print "\nPlease enter numbers and not letters"

# Call continue function to change variable to true or false
# This will change the value of the variable 'i' above to either True
# or False.

i = re_run(raw_input("\nDo you wish to continue? Y/N "))



'''
This version that will work with decimals, and wont break with letters
it will also loop over and over to allow for repeated use until
the user decides to quit.

This version has Error Checking and is very robust.
These definitions can be taken and used in other programmes the user
may create

Notice that the main programme is only 10 lines of code. if you want to
change how it works, you do not have to change much. The previous
versions of the program would need a complete re-write.
'''



SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 17th March 2015
quotequote all
Brilliant.. Thanks for the feedback.

I guess I have gone way way overboard on the comments just a little smile

I've chosen python as I couldnt make a choice of the many languages out there, and instead of procrastinate over choosing. I just picked one and got on with trying to learn one.

Not sure what I'll try to learn next. Maybe java or c. Regardless that's a looking way off at the mo smile

I shall take onboard the comment about using more meaningful variable names, and get reading about grep and piping commands in shell. I don't think I have to worry about windows cross compatibility as I haven't used the os since XP lol

Edited by SystemParanoia on Tuesday 17th March 13:30

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 17th March 2015
quotequote all
CountZero23 said:
Just out of interest are you coding just for fun or did you have a view to change careers?
Short term, its for fun and to allow me to know enough teach the kids how to code ( they're currently 9 )

Long term, I am very focused on this and once I become a code ninja, I will definitely be trying to change career. once i've learnt vanilla python inside and out maybe even go for an OU computer science degree if it will help.

Tonsko said:
if name__=="__main":
I will look into this so that i fully understand what's happening when i use it smile thank you


Thanks for the links above all, ill try and digest as much of that as i can.
im currently using various free online resources to learn, and a couple of books.

codecademy
codecombat <--- coding game
checkio <--- really hard coding game / challenge
and learnpythonthehardway

I try to do each new thing in both python 2.xx and 3.xx so that I can keep aware of the differences between the 2.

SystemParanoia

Original Poster:

14,343 posts

199 months

Wednesday 18th March 2015
quotequote all
This thread has turned out to be an absolute gold mine!! Thanks guys.

Today I have mostly been writing task automation scripts to use on the works computer using sikuli.

Group policy on the active directory works machines is pretty tightly locked down. No bat/exe/MSI executions allowed without admin.. Java is completely unrestricted however. Meaning I could install the sikuli java/python environment

SystemParanoia

Original Poster:

14,343 posts

199 months

Thursday 19th March 2015
quotequote all
cornet said:
This appears to have gone off topic somewhat. So bringing this back on track and playing some code golf to try and help the OP.

I've done very little python so their might not be some common idioms I'm using but here goes.

The goals when writing this were:

  • Make sure functions have a clear purpose and are reusable
  • Catch errors as early as possible in the program
  • Keep logic separate from presentation


#!/usr/bin/env python

def calc_area(base, height):
"""Calculate and return the area of a triangle give the base and height"""
return base * height / 2


def yes_response(resp):
"""Check if string is a yes response and return true if so"""
YES_RESPONSES = ["y", "yes"]

resp = resp.lower()

if resp in YES_RESPONSES:
return True
else:
return False


def main():
while True:
print "\nThis programme calculates the area of a triangle\n"

try:
base = float(raw_input("Enter Base Value: "))
height = float(raw_input("Enter Height value: "))
except ValueError:
print "\nPlease enter numbers and not letters"
continue # Skips to next iteration of the loop

area = calc_area(base, height)

print "The working out is, %d x %d / 2" % (base, height)
print "Base x height =", base * height
print "Once divided by 2 the area of your triangle is", area

if not yes_response(raw_input("\nDo you wish to continue? Y/N ")):
break # Exits the loop

print "\nGood Bye\n"


if __name__=="__main__":
main()
that is exactly what i meant to write!!

Thank you for this, it didn't even occur to me even consider having the calculation within the return statement and catching the exception of the float immediately at input instead of taking a raw string and converting it later et al, and all the other stuff you did to minimise the lines of code required.

elegant smile


Edited by SystemParanoia on Thursday 19th March 15:14

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
I noticed that I could not ssh into my server using the works wifi today, looks like the I.T boys have been making some firewall changes frown

I decided this is another excuse to spend far longer writing an automated solution, than it would take to just do it manually lol.

so I've spent the last two evenings working on this outbound port-scanner. I've managed to get it working, and so I've decided to show you guys.

you may notice that ive grabbed a few snippets of code from this very thread smile thanks for that guys smile


#! /usr/bin/env python3

import subprocess
import os
import time
successful_results = [] <-- curly braces

def port_scan(low_port, high_port):
website = "portquiz.net:"
for port_num in range(low_port, high_port):
port_to_scan = website + "%d" % port_num
successful_results[port_to_scan] = subprocess.Popen(["wget", "-qO ",
port_to_scan])
output()

def output():
while successful_results:
for result1, result2 in successful_results.items():
if result2.poll() is not None:
del successful_results[result1]
if result2.returncode == 0:
# Print string from the 13th index to omit un-needed url text
print("Port %s is open" % result1[13:])
elif result2.returncode == 1:
print("Port %s is blocked" % result1[13:])
else:
print("Port %s returns an error" % result1[13:])
break

def yes_response(resp):
# Check if string is a yes response and return true if so
YES_RESPONSES = ["y", "yes"]

resp = resp.lower()

if resp in YES_RESPONSES:
return True
else:
return False

def main():
while True:
try:
print("\nThis Programme will scan a range of outbound ports")
low_port = int(input("\nEnter start port: "))
high_port = int(input("Enter end port: "))
start_time = time.clock()
port_scan(low_port, high_port)
end_time = time.clock()
print("\nScan completed in ", end_time - start_time, " seconds")
except ValueError:
print ("\nPlease enter numbers and not letters")
main()
if not yes_response(input("\nDo you wish to perform another scan? Y/N : ")):
break

if __name__=="__main__":
try:
main()
# Attempt to make programme exit cleanly
except KeyboardInterrupt:
print("\n\nShutdown requested... exiting\n\n")
try:
exit()
except SystemExit:
os._exit(0)




I appear to be having an issue with my successful_results dictionary. it will only work where it is; everywhere else I put it, it throws error messages at me.

Edited by SystemParanoia on Tuesday 24th March 19:57 - To edit a comment in the code


Edited by SystemParanoia on Tuesday 24th March - To Neaten up the timing code 20:41


Edited by SystemParanoia on Tuesday 24th March 21:14

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
good point.

Im printing from index 13 as all previous indexes ( indecies? ) contain the the url that's being scanned.

its a little sloppy in its current form, and im working on correctly segmenting my data to prevent the need to do this smile

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
I have taken this onboard.
I thought I was being clever getting it on one line. but your points are clear and concise. sometimes the extra line is worth it as it makes things so much clearer.

Tonsko,

I used wget as I have marginally more experience with it than netcat or curl having recently performed my first arch install.

I'll read up on that scappy module, but I feel ill be needing to get rather intimate with curl, and the requests python module in the not-to-distant future hehe


SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
yeah, I cant seem to get the indents to behave on this forum.

I do my editing in geany and just cut/paste, and the forum makes it rather "wonky"


SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
*clicks furiously*


hehe

SystemParanoia

Original Poster:

14,343 posts

199 months

Tuesday 24th March 2015
quotequote all
ive created an account

https://github.com/systemparanoia/dried-fruit

but, it looks like im going to need time to figure this out lol.

ive only ever git-cloned stuff before, and not always successfully haha smile

SystemParanoia

Original Poster:

14,343 posts

199 months

Wednesday 25th March 2015
quotequote all
That above re-interpretation is alot clearer.
thank you smile

Im endlessly thinking of stuff to try and attempt.
really enjoying the programming experience so-far, I absolutely wish I had started sooner smile

turns out almost all outbound ports are blocked on the works wifi. The only open ports i found were 25, 80, 443, and 1723
so I just adjusted the port forwarding on my home firewall to reflect this and now ssh is working again. hurrah for python! smile

just hope I dont fall into this XKCD trap though