Today was hard!

Notes

‘*args’

  • way to get multiple arguments without having to assign placeholders for them
  • it scoops up all the arguments and gives it to the function in a tuple. I could then loop over it with for.
  • I just put * in front of one of my placholders et voilà, def example_func(*catch_everything)
  • I can define placeholders to catch specific arguments, but those need to be before my ‘*args’.
  • Edge Case: I could have my arguments in a list/tuple already. I can just add the structure with a * in front of it and Python will unpack it for me. If I have a list, catch_me_if_you_can=[1,2,4] then I can pass the elements individually, as arguments with a def example_func(*[catch_me_if_you_can])
  • Another kinda frequent edge case: ‘*args’ catches everything that is unassigned. so if i have something with a default value, it will get trampled by the data from my args. Best thing to do is to set the default after the ‘*args’ like so, example_func(a, *args, b=10)

Keyword Arguments

  • Normally in the form of name = value
  • Kinda like addressing lists vs dictionaries. Where instead of an index, I can now call an argument with a name.
  • So I can go def name(FirstName='', LastName='') and then put in stuff in whatever order I want to like name(LastName='Brontë', FirstName='Emily'. Pretty handy!
  • Try not to mix and match positional and keyword arguments. Python looks for positional arguments first, then keyword arguments. So if you have them, then the positional arguments have to come first!

‘**kwargs’

  • these scoop up keywords arguments into a dictionary. I can do everything with this, just like any other dictionary
  • I just put * in front of one of my placholders et voilà encore, def example_func(**catch_everything)

Combining Arguments

  • Arguments in decreasing order. Stick to the order as far as possible.
    • mandatory parameters (no defaults)
    • optional parameters (with defaults)
    • *args
    • **kwargs (with and without defaults)
  • Use them for different kinds of input

Variable scopes

  • Just because I have indentation, with an if or an else or a for, does not mean that I change a variable’s scope. Variables within those indented blocks could still be global, or the scope of the thing above
  • The slight exception is the variable within comprehensions. Variables inside them, have their own private scope
  • The scope changes, mainly, when we define functions. Generally …
    • If I am in a function, I’m in a local scope
    • If I am out of it, I’m in a global scope
    • with some exceptions
  • So always think, am I in a function body … or not? (excepting comprehensions)
  • When Python looks for variable values it looks in the LEGB sequence. (left to right).
    • Local (starts here if I’m in a function)
    • Enclosing
    • Global (starts here if I’m not in a function, rather in the main body of the program)
    • Built-in
  • The globals function will have all the global variables for the program. It’s a dict with variable names as keys and the variable assignments as values
  • The locals function will have all the local variables for a function in the program, when it runs. It’s also a dict with variable names as keys and the variable assignments as values or I could also look at the function_name.code.co_varnames to peek at the local stuff
    • Parameters to a function are also local variables.
    • I should define my local variables, before I use them in a function, or I get an UnboundLocalError
    • If I want to use and modify a global variable in a function, I should declare it at the beginning of my function. For example, if I have a global variable x, and I want to use it in a function, then I say global x in the beginning of the function.
    • I can mutate elements of global variable, if they are mutable structures. As in, I cannot change list A to another set of entries, but I can append to list A, or delete items from list A. As long as you are not assigning to a variable, rather using object methods, you should be ok.
  • The built-ins scope, houses many things that are needed by Python, but are not reserved keywords. Stuff like list. I can use it to create lists, but it’s not reserved. I can redefine it if I want to (or more commonly redefine it by mistake)
    • This feels like one of the few places, Python allows me to shoot myself in the foot.
    • Do a dir(__builtins__) and review the names every now and then, and don’t use them in your code.

Kinda Advanced Stuff

  • While I said, they were verbs, functions can alse be nouns. I can just pass them as objects to other functions or elsewhere.
  • I can pass a function as an argument as in the case of sorted(someIterableofPositiveNegativeNumbers, key=abs) where I am passing the abs function as a keyword to the sorted function, which then uses abs to get the absolute values of the numbers first and then sorts them according to those values.
  • I can collect arguments for the inner functions I call with *args and **kwargs and then pass to them again with *args and **kwargs.
  • I can also take some data as an argument along with a function and apply that function to that data. Like I did above. The main function I create acts like some glue program. This process of applying function to data, is called mapping and the functions I create to do this are map functions. Python has a built in map function.
  • I can create functions, plop them into a dictionary and then call them as needed in my actual function, by accessing the dictionary keys and supplying arguements. This approach is called a dispatch table

Learning / Feedback/ Experiences from doing exercises

  • Getting used to the way, Python behaves. And beginning to love its consistency for the most part.
  • I write slow, step by step code. while it works, Reuven’s solutions are short and make me go, oh why did I not think of that? Maybe optimised thinking will come with time?
  • I have to use Python tutor a lot to get what is actually happening.
  • I’ve learnt to just dive in blind when begining to write programs. The more I think about stuff, the more I feel, like I can’t do this. So I just start. And build it line by line, error by error. And more often than not, it solves it self. Optimised solutions present themselves after I have the rough and ready solution done. “Aah! I could’ve written it this way”
  • And I am done with the introduction to functions! Hurrah! This course stretched me a bit, and showed me I still have a ways to go.

Read all about my Python functions journey here