# General Code Techniques ## String slicing Can use this to get specific items or a range of items within a list If you wanted to get a specific range in ``` list = [1,2,3,4,5] ``` You can access 2-4 by going ``` list[1:3] ``` To access the last element of a list you can use: ``` list[-1] ``` ## For loops without counters We can use for loops as below to access the entire object or thing we are looping for: (haha guess where this is from) ``` for user in data['users']: if user.get('token'): is token: found = True return found ``` This allows us to access specific items within this data dictionary ## Loops with counters For loops with counters are as follows: (from lab09_deploy) ``` for i in range(len(numbers)): if numbers[i] is whatever: found = True i += 1 return found ``` While loops with counters are as follows: ``` while i < len(numbers): if numbers[i] is whatever: found = True i += 1 return found ``` ## Importing libraries and files We can import different ways: (this project will haunt me forever) 1. `import src.channel` 2. `from src.channel import channel_join_v1, channel_messages_v1` There are other ways but they aren't really good practice so just putting these 2 here ## Raising Exceptions To raise exceptions we can do this different ways, we have been shown the following: 1. In a conditional ``` if user_found is False: raise AccessError('User not found') ``` 2. Throwing and catching errors ``` try: find_user_id(token) except: Exception('Token invalid') ``` To test these exceptions we need to import pytest in our test file and run code like so: ``` def test_exception(): with pytest.raises(Exception): channels_create(None, None, None) ``` ## Map, Filter, Reduce Map - creates a list, takes in a list of length `n` and takes functions of that list * Modifies elements of a list - can use this instead of using if anf for loops to do so Filter - takes ina list and generates a sub list from it - filtering out specific things according the rule you set lambda - is a way of writitng a really short function * applies a condition and returns a true or false ## Destructuring Is the process where you have a tuple and break it to its components This allows us to assign names to tuples - and makes it easier to read code ## Enumerate If you want to know the index, we can use this function instead of having `i += 1` ## Decorators These are ways we are able to make our code more readable and more automated (yay pythonic...sorta) We use decorators using the `@` key The most common decorator that we have seen in this course if for our fixtures and our server like so: ``` @pytest.fixture def auth_set_up(): ``` ``` @app.route(config.url + '/whateverroute', method= [GET]) ``` We can use this to automate the process of our functions working too. Decorators give us the capacity to pass whole functions into each other. An example of this has been provided below: This is adapted from Hayden's Wk8 Lab Code: ``` def uppercase_transform(function): def wrapper(name : str): return function(name).upper @uppercase_transform def first_name(): return 'Jennifer' @uppercase_transform def last_name(): return 'Jareau' ``` Here we can see that the name of the function we want to 'wrap' or decorate our first name and last name function. The decorator servers to apply the same process to the two different functions. This makes the code a lot cleaner and easier to work with. ## args and kwargs args are the arguments - we are used to seeing this type of argument in our code e.g.: `def argument(thing1, thing2)` * Here the arguments that are passed through will directly correspond to the order they are in in this function * So if we messed up the order of passing through, the function will have a little bit of a breakdown and not perform as intended kwargs - this is a key word argument e.g.: `def argument(name=thing1, location=place1, food=food1)` * Here it does not matter what order we pass things through as, as long as we have the key word of the argument the function will work as expected * You can choose not to specifically name all the key words, but the second you start, all the succeeding arguments that you pass in will need key words like so * `argument(thing1, location=place1, food=garlic_bread)` #### To set up a function to take in args and kwargs ``` **kwargs *args # only do this in defining a function and its parameters ``` The great thing about these args and kwargs is that if you pass in more parameters than necessary, the function will only take as many as it needs and won't break down if there are too many