# intercept a wrong data type with a function decorator
def require_numeric (func):
"""decorator to check if function argument is of type int or float"""
def wrapper (arg1, arg2=0):
if type(arg1) == int or type(arg1) == float:
return func(arg1)
else:
print("need a numeric value!")
return wrapper
@require_numeric
def print_num(arg):
print("numeric value = %f" % arg)
# test ...
print_num(7.33) # numeric value = 7.330000
print_num("$3.99") # need a numeric value!
HiHe 174 Junior Poster
TrustyTony commented: Kind of fun func! +12
TrustyTony 888 ex-Moderator Team Colleague Featured Poster
@HIhe
Lets be functional and generate/itertools/lambda the same:
# everyone likes TGIF
# so loop through a whole year day by day and show all the dates that are Fridays
from itertools import takewhile, count
import datetime
# pick a year
year = 2012
one_day = datetime.timedelta(days=1)
start_year = datetime.date(year, 1, 1)
print("These are all the Fridays of %d:" % year)
for day in takewhile(lambda d: d <= datetime.date(year, 12, 31), (start_year + one_day * c for c in count(0))):
if day.weekday() == 4:
print("%s is a Friday" % day)
Edited by TrustyTony
HiHe 174 Junior Poster
Numpy is a high speed numeric module for Python:
# use loadtxt() to load a data file to a numpy array
try:
# Python2
from StringIO import StringIO
except ImportError:
# Python3
from io import StringIO
import numpy as np
data_str = """\
1,2,3
4,5,6
"""
# create a file object
data_file = StringIO(data_str)
# load into a numpy array, default is float datatype
data_array = np.loadtxt(data_file, delimiter=',', dtype=int)
print(data_array)
'''
[[1 2 3]
[4 5 6]]
'''
print('-'*30)
data_str2 = """\
frank,19,167
jean,18,123
"""
# create a file object
data_file2 = StringIO(data_str2)
# load mixed data types into a numpy array
dt = {
'names': ('first','age','weight'),
'formats' : ('S12','i4','i4')
}
data_array2 = np.loadtxt(data_file2, delimiter=',', dtype=dt)
print(data_array2)
'''
python2>>>
[('frank', 19, 167) ('jean', 18, 123)]
python3>>>
[(b'frank', 19, 167) (b'jean', 18, 123)]
'''
HiHe 174 Junior Poster
# sum a bunch of numbers recursively
# works with Python2 and Python3
try:
input = raw_input
except NameError:
pass
def my_sum():
n = input('Next number or blank to finish: ')
return (float(n) + my_sum()) if n else 0
s = my_sum()
print("The sum of numbers is %s" % s)
HiHe 174 Junior Poster
# specifically replace full words only
# will replace red but not change reduce
# like the normal string.replace() function would
# note that replacement is case sensitive
# attached quotes and punctuation marks are neutral
import re
def replacer(match_obj):
# function will be called for each key_word
# in the text during substitution
word = match_obj.group(0)
return replace_dict.get(word, word)
text = """
In this text 'debug' will be changed but not 'debugger'.
Similarly red will be replaced but not reduce.
How about Fred, -red- and red? Red, white and blue
"""
# create a dictionary of key_word:replace_with pairs
replace_dict = {
"red" : "redish",
"debug" : "fix"
}
# a regular expression matching all identifiers
pattern = re.compile(r"[A-Za-z_]\w*")
print(pattern.sub(replacer, text))
"""result -->
In this text 'fix' will be changed but not 'debugger'.
Similarly redish will be replaced but not reduce.
How about Fred, -redish- and redish? Red, white and blue
"""
ZZucker 342 Practically a Master Poster
One way to get your IP:
# get your ip
# Python32
import urllib.request
def get_external_ip():
'''returns a string'''
url = "http://automation.whatismyip.com/n09230945.asp"
ipb = urllib.request.urlopen(url).read()
# decode <class 'bytes'> to string
ip = ipb.decode("utf8")
return ip
print(get_external_ip())
ZZucker 342 Practically a Master Poster
Time a function with a timing decorator:
# time relatively time consuming functions
# with a decorator function
# apply the decorator right above the function
# you want to time, starting with a @
# works with Python27 and Python32
# (use module timeit for faster functions)
import time
def print_timing(func):
"""set up a decorator function for timing"""
def wrapper(*arg):
t1 = time.time()
res = func(*arg)
t2 = time.time()
print('%s took %0.3f ms' % (func.__name__, (t2-t1)*1000.0))
return res
return wrapper
@print_timing
def get_primes(n):
"""
standard optimized sieve algorithm to get a list
of prime numbers from 2 to < n, prime numbers are
only divisible by unity and themselves
(1 is not considered a prime number)
"""
if n < 2: return []
if n == 2: return [2]
# do only odd numbers starting at 3
s = list(range(3, n+1, 2))
# n**0.5 simpler than math.sqr(n)
mroot = n ** 0.5
half = len(s)
i = 0
m = 3
while m <= mroot:
if s[i]:
j = (m*m-3)//2
s[j] = 0
while j < half:
s[j] = 0
j += m
i += 1
m = 2*i+3
# skip all zero items in list s
return [2]+[x for x in s if x]
print( "prime numbers from 2 to <10,000,000 using a sieve algorithm")
prime_list = get_primes(10000000)
'''my result with Python32 -->
prime numbers from 2 to <10,000,000 using a sieve algorithm
get_primes took 2632.000 ms
just a note, result with Python27 -->
get_primes took 2394.000 ms
'''
ZZucker 342 Practically a Master Poster
You can use lambda to set up a function:
# works with Python27 and Python32
# a recursive denary to binary function via lambda
d2b = lambda d: (not isinstance(d,int) or (d==0)) and '0' \
or (d2b(d//2)+str(d%2))
den = 255
print("denary = %d" % den)
binary = d2b(den)
print("binary = %s" % binary)
# check reult with function bin()
print("binary = %s via bin(%d)" % (bin(den), den))
'''result -->
denary = 255
binary = 011111111
binary = 0b11111111 via bin(255)
'''
ZZucker 342 Practically a Master Poster
You can set up a function decorator using a class:
# using a Python class as a decorator
class StripCharacters:
"""
a decorator class to strip given chrs from string text
by default strip common punctuation marks --> ,.?!:;
"""
def __init__(self, func, chrs=",.?!:;"):
self.chrs = chrs
self.func = func
def __call__(self, text):
"""
allows the class instance to be called as a function
"""
# do the stripping
new_text = ''.join(c for c in text if c not in self.chrs)
return self.func(new_text)
@StripCharacters
def print_text(text):
print(text)
text1 = 'If you are here, you are lost!'
print_text(text1)
print('-'*30)
text2 = 'common punctuation marks are ,.?!:;'
print_text(text2)
'''my result -->
If you are here you are lost
------------------------------
common punctuation marks are
'''
ZZucker 342 Practically a Master Poster
You can use Python to check the size of a given directory (folder):
# determine the size of a given folder in MegaBytes
import os
# pick a folder you have ...
folder = r'C:\Python32\DLLs'
folder_size = 0
for (path, dirs, files) in os.walk(folder):
for file in files:
filename = os.path.join(path, file)
folder_size += os.path.getsize(filename)
print("Folder %s = %0.1f MB" % (folder, folder_size/(1024*1024.0)))
'''possible result -->
Folder C:\Python32\DLLs = 5.6 MB
'''
ZZucker 342 Practically a Master Poster
Sometimes you have to flatten a deeply nested list or tuple:
# flatten a nested list
def flatten(seq):
mylist = []
for item in seq:
if isinstance(item, (list, tuple)):
# recursive function
mylist.extend(flatten(item))
else:
mylist.append(item)
return mylist
nested_list = [1, 2, [3, 4, [5, 6, [7, 8]]]]
print(nested_list)
print('nested list flattened:')
print(flatten(nested_list))
'''result-->
[1, 2, [3, 4, [5, 6, [7, 8]]]]
nested list flattened:
[1, 2, 3, 4, 5, 6, 7, 8]
'''
ZZucker 342 Practically a Master Poster
The Python function range() handles only integers. Here is a range generator that handles floats:
# a floating point range generator with roundoff-fix
# works with Python2 and Python3
def frange(start, stop=None, step=1.0, delta=0.0000001):
"""
a range generator that handles floating point numbers
uses delta fuzzy logic to avoid float rep errors
eg. stop=6.4 --> 6.3999999999999986 would slip through
"""
# if start is missing it defaults to zero
if stop == None:
stop = start
start = 0
# allow for decrement
if step <= 0:
while start > (stop + delta):
yield start
start += step
else:
while start < (stop - delta):
yield start
start += step
# testing ...
# expect numbers 6.0 to 6.3
for k in frange(6.0, 6.4, 0.1):
print("%f" % k)
'''my result -->
6.000000
6.100000
6.200000
6.300000 okay!
'''
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague
The Python function format is available for Python27 and Python3 and above ...
# create a 4 row 5 column evenly spaced table using format()
# tested with Python27 and Python32
text = """\
kamikaze pilots did wear helmets
abbreviation is a long word
shoot them in tourist season
a quarterback is a refund
"""
# create a list of the words
w = text.split()
n = 0
for k in range(0, len(w), 5):
# Python27 and higher string formatting
# use a field of 13 char to fit longest word
sf = '{:13s} {:13s} {:13s} {:13s} {:13s}'
print(sf.format(w[n], w[n+1], w[n+2], w[n+3], w[n+4]))
n += 5
"""
kamikaze pilots did wear helmets
abbreviation is a long word
shoot them in tourist season
a quarterback is a refund
"""
sneekula 969 Nearly a Posting Maven
Use the Python module timeit to test the speed of a function. Here is an easy way:
'''get_timing.py
use Python module timeit in a wrapper
modified vegaseat code
works with Python2 and Python3
'''
def get_timing(fs, number=10000, module="__main__"):
"""
this wrapper can be used to time any function
pass full function call in as a string eg. 'func(arg1, arg2)'
number = number of timeit loops
module namespace is autodetected
"""
import timeit
import inspect
# extract function name
q1 = fs.split('(')
f = eval(q1[0])
# extract arguments
q2 = q1[1].strip(')')
if q2:
args = eval(q2)
else:
args = None
name = f.__name__
# get module namespace
module = inspect.getmodule(f).__name__
if args == None:
st1 = "%s()" % (name)
elif type(args) == tuple:
st1 = "%s%s" % (name, args)
elif type(args) == str:
st1 = "%s('%s')" % (name, args)
else:
st1 = "%s(%s)" % (name, args)
st2 = "from %s import %s" % (module, name)
t = timeit.Timer(st1, st2)
# elapsed time is in microseconds
print("Function %s took %.2f microseconds/pass" % \
(st1, 1000000*t.timeit(number=number)/number))
# optional ...
return eval(fs)
def gcd3(x, y):
"""greatest common denominator, non-recursive"""
while y:
x, y = y, x % y
return x
def test():
pass
# testing ...
if __name__=="__main__":
import math
# no arguments
print(get_timing('test()'))
# one argument
print(get_timing("math.log(1000)"))
# two arguments
print(get_timing('gcd3(1251, 3357)'))
vegaseat commented: nice +14
HiHe 174 Junior Poster
Create a multidimensional array (matrix or list of lists):
# create a x by y matrix (list of lists)
import pprint
def zero_matrix(x,y):
'''create a x rows by y columns matrix of zeroes'''
return [[0 for a in range(y)] for b in range(x)]
# test matrix has 10 rows and 12 columns
ma = zero_matrix(10, 12)
pprint.pprint(ma)
print('-'*32)
# to test change row=0 col=0 to a 1
ma[0][0] = 1
pprint.pprint(ma)
''' result -->
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
--------------------------------
[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
'''
HiHe 174 Junior Poster
One way to display text in color:
# display a multi-line text in your browser in color
import webbrowser as wb
def color_text_html(text, color="black"):
# replace any newline with <BR> html code
text = text.replace('\n', '<BR>')
return "<FONT color=%s>%s</FONT>" % (color, text)
# this is your test text
text = """\
one
two
three
"""
# add some color html code
text_html = color_text_html(text, "red")
print(text_html) # test
# write the text out as .htm file
fname = "simple_text.htm"
with open(fname, "w") as fout:
fout.write(text_html)
# now display the text in your web browser
wb.open(fname)
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague
This shows you how to use a helper function when sorting ...
'''sort_by_last_name1.py
sort names in format "first middle last" by the last name
'''
import pprint
def by_last_name(name):
"""
helper function to sort by last name
assume names are "first middle last"
"""
return name.split()[-1]
# some sample names for testing
# format is first middle last
names = """\
Fred M. Ferkel
Carolus D. Arm
Carl S. Gustafson
Ben M. Over
Rosa X. Parker
Larry Marsh
Lola Q. Zumokar
Heinrich S. W. Buzen
"""
# convert to a list
name_list = [name for name in names.split('\n') if name]
print("names unsorted:")
pprint.pprint(name_list)
print('-'*35)
print("names sorted by last name:")
pprint.pprint(sorted(name_list, key=by_last_name))
'''result >>
names unsorted:
['Fred M. Ferkel',
'Carolus D. Arm',
'Carl S. Gustafson',
'Ben M. Over',
'Rosa X. Parker',
'Larry Marsh',
'Lola Q. Zumokar',
'Heinrich S. W. Buzen']
-----------------------------------
names sorted by last name:
['Carolus D. Arm',
'Heinrich S. W. Buzen',
'Fred M. Ferkel',
'Carl S. Gustafson',
'Larry Marsh',
'Ben M. Over',
'Rosa X. Parker',
'Lola Q. Zumokar']
'''
Lardmeister 461 Posting Virtuoso
Windows in its infinite oddity has chosen to us the backslash '\' in its path names. However it will work with the normal slash '/' of the unix systems. in a string things like '\temp' will be interpreted as tab and 'emp'. So why not replace the '\' with '/'? Easier said than done as you will see in this example:
# experiments to convert
# r"a\b\c\d\e.aaa" to "a/b/c/d/e.aaa"
# make sure you make s a raw string
s = r"a\b\c\d\e.aaa"
# gives SyntaxError: EOL while scanning string literal
#s2 = s.replace('\', '/')
# gives SyntaxError: EOL while scanning string literal
#s2 = s.replace(r'\', '/')
# not the desired output
s2 = s.replace('\\', '/')
print(s2) # a\b\c\d\e.aaa
# however this will work
s3 = "%r" % s
# test
print(s3) # 'a\\b\\c\\d\\e.aaa'
# eval() converts repr back to str
s4 = eval(s3.replace(r'\\', '/'))
# success
print(s4) # a/b/c/d/e.aaa
Edited by Lardmeister
Lardmeister 461 Posting Virtuoso
Here is another way to do this:
# experiment to convert back slash to forward slash
# r"a\b\c\d\e.aaa" to "a/b/c/d/e.aaa"
def back2forw(c):
'''helper function for list comprehension'''
return (c, '/')[c == '\\']
# make sure you make s a raw string
s = r"a\b\c\d\e.aaa"
s2 = "".join([back2forw(c) for c in list(s)])
print(s)
print(s2)
'''result >>
a\b\c\d\e.aaa
a/b/c/d/e.aaa
'''
The helper function uses True=1 and False=0
Edited by Lardmeister
vegaseat commented: thanks +0
Lardmeister 461 Posting Virtuoso
This is the exploration of a toggle function using a list element as default argument:
'''toggle_function1.py
explore functions that toggle between 2 states every time they are called
'''
def toggle(x=[0]):
'''
toggles between True and False each time called
'''
x[0] = not x[0]
return x[0]
# test
for k in range(6):
print(toggle())
'''result >>
True
False
True
False
True
False
'''
Edited by Lardmeister
vegaseat commented: clever +14
TrustyTony 888 ex-Moderator Team Colleague Featured Poster
Alternative way to do toggle function without global using attribute of function (which is also an object in Python).
def toggle():
'''
toggles between True and False each time called
'''
try:
toggle.state = not toggle.state
except AttributeError:
toggle.state = True
return toggle.state
# test
for k in range(6):
print(toggle())
print('Toggle state is %s.' % toggle.state)
'''result >>
True
False
True
False
True
False
Toggle state is False.
'''
Even simpler is to use itertools module, now we keep state in variable in loop location:
from itertools import cycle
limit = 6
for counter, state in enumerate(cycle((True, False))):
if counter >= limit:
break
print counter, state
print('Toggle state is %s.' % state)
"""Output:
0 True
1 False
2 True
3 False
4 True
5 False
Toggle state is True.
"""
Edited by TrustyTony
Lardmeister 461 Posting Virtuoso
Here is a function to enter a list of numeric values:
# a function to input a list of numeric values
# this will work with Python2 and Python3
import sys
if sys.version_info[0] < 3:
input = raw_input
def get_list(prompt):
"""
loops until acceptable data or q (quit) is given
returns a list of the entered data
"""
data_list = []
while True:
sin = input(prompt)
if sin == 'q':
return data_list
try:
# check if number is integer or float data type
if '.' not in sin:
data = int(sin)
else:
data = float(sin)
data_list.append(data)
except ValueError:
print("Enter numeric data!")
print('-'*20) # 20 dashes
num_list = get_list("Enter a number (q to quit): ")
print(num_list) # test
griswolf 304 Veteran Poster
I prefer to send the quit condition as a second argument to the list entry function. That way, if you need 'q' as a valid list member, you can use something else to stop the loop (also works better for folks whose language does not use a 'q' word to mean "quit"). The second argument can be a string to match against, or it could be a function that takes a string and returns a boolean. The latter is the most general, but also more trouble than it is worth in many cases.
Edited by griswolf because: clarify language issue
Ene Uran 638 Posting Virtuoso
Could be the start of a word game:
# a simple rotate cipher
from collections import deque
def rotate_right(text, n=1):
"""
use deque to rotate text n steps to the right
return rotated text
"""
rot_right = deque(text)
rot_right.rotate(n)
return "".join(rot_right)
def rotate_left(text, n=1):
"""
use deque to rotate text n steps to the left
return rotated text
"""
rot_left = deque(text)
rot_left.rotate(-n)
return "".join(rot_left)
# cipher the text by rotating 3 steps
text = 'peanuts'
n = 3
print(rotate_right(text, n)) # utspean
# decipher the text
text = 'utspean'
print(rotate_left(text, n)) # peanuts
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague
Temperature conversion from C to F or F to C is allways popular. Here is a way to make you scratch your head ...
'''Class_Temperature2.py
a class to convert F to C or C to F
tested with python32, python33
Python27 needs class Temperature(object)
'''
class Temperature():
"""
allows you to convert F to C or C to F
double underline prefix makes method private to class
"""
def __init__(self):
self.celsius = 0.0
def __getFahrenheit(self):
return 32 + (1.8 * self.celsius)
def __setFahrenheit(self, f):
self.celsius = (f - 32) / 1.8
# property() combines get and set methods into one call
# celsius and fahrenheit define each other
# only one is needed to be given
fahrenheit = property(__getFahrenheit, __setFahrenheit)
# create the class instance
t = Temperature()
# convert Celcius to Fahrenheit
t.celsius = 0
print("%0.1f C = %0.1f F" % (t.celsius, t.fahrenheit))
# convert Fahrenheit to Celsius
t.fahrenheit = 98
print("%0.1f F = %0.1f C" % (t.fahrenheit, t.celsius))
'''result ...
0.0 C = 32.0 F
98.0 F = 36.7 C
'''
Edited by vegaseat because: exception for python27
TrustyTony 888 ex-Moderator Team Colleague Featured Poster
Yes, it makes me to scratch mine. After running the code:
>>> t.fahrenheit = 10
>>> print("%0.1f F = %0.1f C" % (t.fahrenheit, t.celsius))
10.0 F = 37.0 C
>>> t.celsius=10
>>> print("%0.1f F = %0.1f C" % (t.fahrenheit, t.celsius))
10.0 F = 10.0 C
>>>
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague
Thanks Tony, seems to happen with Python27 only.
Python27 needs to inherit object:
class Temperature(object)
With Python3 object is default.
Edited by vegaseat
richieking 44 Master Poster
Python like java operates on object. At least python is not purely OB. but the concepts are similer.
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague
A class that creates a persistent list can be used for some interesting applications ...
'''Class__persist1.py
find all integers in a series of texts
create a persistent list of all finds
tested with Python27, Python32 and Python33
'''
import re
class Persist_list_int():
"""
class to make a list persistent
"""
def __init__(self):
# this list is persistent
self.all_items = []
def __call__(self, text):
"""
allows class instance to be called with argument text
"""
# just a simple test of the persistent list
# regex to find all integers in a given text
items = re.findall("\d+", text)
self.all_items.extend(items)
return self.all_items
# create class instance
find_int = Persist_list_int()
# call instance
print(find_int('12 days and 17 hours')) # ['12', '17']
print(find_int('about 15 minutes ago')) # ['12', '17', '15']
print(find_int('we are leaving at 6:45')) # ['12', '17', '15', '6', '45']
print(find_int('you owe me $123.48')) # ['12', '17', '15', '6', '45', '123', '48']
Edited by vegaseat
TrustyTony 888 ex-Moderator Team Colleague Featured Poster
Here another processing for the vegaseat text. No re, no classes. list of list of ints result instead of flat list of strings. Added my own test case to show missing of the recognition of negative numbers. Negative numbers could be catched by re with [+-]*\d+ as shown
from itertools import groupby
from operator import methodcaller
import re
def find_int(t):
return [int(''.join(n)) for is_digit, n in groupby(t, methodcaller('isdigit'))
if is_digit]
tests = ('12 days and 17 hours',
'about 15 minutes ago',
'we are leaving at 6:45',
'you owe me $123.48',
'Temperature can go until -40 C in Finland')
print([re.findall('[+-]*\d+', t) for t in tests])
#negative value is not catched as negative!
print([find_int(t) for t in tests])
"""Output
[['12', '17'], ['15'], ['6', '45'], ['123', '48'], ['-40']]
[[12, 17], [15], [6, 45], [123, 48], [40]]
"""
Edited by TrustyTony
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.