I created this chart to summarize the information I found on engineersalary.com.
The green bars on the left show relative number of jobs for each discipline. The bars in the chart show the salary ranges of the bottom 10%, middle 50%, and top 10%, respectively. The bars are cut off at $40k on the left and $150k on the right, so the bottom 10% and top 10% bars may extend beyond those bounds.
No data was given for average starting salary by degree level, for Aerospace Engineering.
A recent post on stackoverflow.com piqued my interest — how can we implement a sort of type signature for functions in Python? I.e., a function like
def foo(x, y):
A call to
foo(3,4) should result in
7 and not
'34'. This arguably goes against Python’s duck typing principles, but let us humor the idea for just a moment. The following Python features will be helpful:
- Reified types: types are first class citizens in Python…try
print int to see for yourself.
inspect: we need some code reflection to get the function parameter names, in order of application.
Here’s what I came up with (and you can view my original submission on the StackOverflow):
def __wrapped__(*args, **kwargs):
arglist = inspect.getargspec(fn).args
mod_args = dict([(vid, ctype(rval)) for vid, ctype, rval in zip(arglist, sig, args)])
for k, v in kwargs.items():
mod_args[k] = sig[arglist.index(k)](v)
except ValueError, e:
raise TypeError("%s() got an unexpected keyword argument." % fn.__name__)
The breakdown is as follows. Inside the function decorator, we use inspection to get
arglist — a list of the arguments to
fn our function, in the order they should be applied. Then we zip
sig (containing the types following the order of the arguments), and
args (the actual values of the arguments passed to
fn) together in our list comprehension; this allows us to apply a type cast to each of the
[(vid, ctype(rval)) for vid, ctype, rval in zip(arglist, sig, args)]
As you can see, I also tacked on the argument name (
vid here is supposed to stand for “variable identifier”), which will come in handy soon.
The next step is to merge and convert the passed keyword arguments to the arguments we’ve already constructed. If the user passes a keyword argument that isn’t supposed to be passed, we will raise a more appropriate
TypeError as opposed to having a more obtuse
ValueError come up.
And that’s about it! Let’s try it out:
@signature(int, int, str)
def foo(x, y, z):
print type(z), z
foo(3, '4', z=["testing", "123"])
And indeed the output is: