# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## Function in Python
#
#

# ### Defining the Function

def print_greeting():
    print("Hello World")


print_greeting()


# The functino header always starts with the "def" keyword that indicates that this is a Function Defination.   
# def unction_name(arrgument):
#             #Function_Body
#             
#

# # Print Vs. Return in Functions

# Heare are two valid functions. One returns a value and one simply prints a value, without returning anything.

# this prints something, but does not return anything
def show_plus_ten(num):
    print(num + 10)


show_plus_ten(3)


# this returns something
def add_ten(num):
    return(num + 10)


add_ten(4)


# Volume of a cylinder: formula  = pi*h**r**2
def cylinder_volume(height , radius):
    pi = 3.14159
    return height*pi*radius**2


cylinder_volume(5 , 3)


# ### Default Arguments
# We can add default arguments in a function to have default values for parameters that are unspecified in a function call.

def cylinder_volume(height , radius = 5):
    pi  = 3.14
    return height * pi * radius**2


# In the example above, radius is set to 5 if that parameter is omitted in a function call. If we call cylinder_volume(10), the function will use 10 as the height and 5 as the radius. However, if we call cylinder_volume(10, 7) the 7 will simply overwrite the default value of 5.

cylinder_volume(10,7)

cylinder_volume(height=10, radius=7) 


# ## Nested Function
# In this exercise, inside a function three_shouts(), you will define a nested function inner() that concatenates a string object with !!!. three_shouts() then returns a tuple of three elements, each a string concatenated with !!! using inner(). Go for it!

# Complete the function header of the nested function with the function name inner() and a single parameter word.
#
# Complete the return value: each element of the tuple should be a call to inner(), passing in the parameters from three_shouts() as arguments to each call

# +
# Define three_shouts
def three_shouts(word1, word2, word3):
    """Returns a tuple of strings
    concatenated with '!!!'."""

    # Define inner
    def inner(word):
        """Returns a string concatenated with '!!!'."""
        return word + '!!!'

    # Return a tuple of strings
    return (inner(word1) , inner(word2) , inner(word3))

# Call three_shouts() and print
print(three_shouts('a', 'b', 'c'))


# -

# ## Problem
# #Let's once again work further on your mastery of scope! In this exercise, you will use the keyword "nonlocal" within a nested function to alter the value of a variable defined in the enclosing scope.

# ## Hint
# #Assign to echo_word the string word, concatenated with itself.
# #Use the keyword nonlocal to alter the value of echo_word in the enclosing scope.
# #Alter echo_word to echo_word concatenated with '!!!'.
# #Call the function echo_shout(), passing it a single argument 'hello'.
#

# +
# Define echo_shout()
def echo_shout(word):
    """Change the value of a nonlocal variable"""
    
    # Concatenate word with itself: echo_word
    echo_word = word*2
    
    # Print echo_word
    print(echo_word)
    
    # Define inner function shout()
    def shout():
        """Alter a variable in the enclosing scope"""    
        # Use echo_word in nonlocal scope
        nonlocal echo_word
        
        # Change echo_word to echo_word concatenated with '!!!'
        echo_word = echo_word+'!!!'
    
    # Call function shout()
    shout()
    
    # Print echo_word
    print(echo_word)

# Call function echo_shout() with argument 'hello'
echo_shout('hello')


# +
# Define report_status
def report_status(**kwargs):
    """Print out the status of a movie character."""

    print("\nBEGIN: REPORT\n")

    # Iterate over the key-value pairs of kwargs
    for key, value in kwargs.items():
        # Print out the keys and values, separated by a colon ':'
        print(key + ": " + value)

    print("\nEND REPORT")
# Define report_status
def report_status(**kwargs):
    """Print out the status of a movie character."""

    print("\nBEGIN: REPORT\n")

    # Iterate over the key-value pairs of kwargs
    for key, value in kwargs.items():
        # Print out the keys and values, separated by a colon ':'
        print(key + ": " + value)

    print("\nEND REPORT")

# First call to report_status()

report_status(name ="luke" , affiliation  = 'jedi' , status = "missing")
# Second call to report_status()
report_status(name="anakin", affiliation="sith lord", status="deceased")
# First call to report_status()

report_status(name ="luke" , affiliation  = 'jedi' , status = "missing")
# Second call to report_status()
report_status(name="anakin", affiliation="sith lord", status="deceased")
# -

# In this exercise, we will generalize the Twitter language analysis that you did in the previous chapter. You will do that by including a default argument that takes a column name.

# +
# Define count_entries()
import pandas as pd
tweets_df = pd.read_csv('tweets.csv')
def count_entries(df, col_name='lang'):
    """Return a dictionary with counts of
    occurrences as value for each key."""

    # Initialize an empty dictionary: cols_count
    cols_count = {}

    # Extract column from DataFrame: col
    col = df[col_name]
    
    # Iterate over the column in DataFrame
    for entry in col:

        # If entry is in cols_count, add 1
        if entry in cols_count.keys():
            cols_count[entry] += 1

        # Else add the entry to cols_count, set the value to 1
        else:
            cols_count[entry] = 1

    # Return the cols_count dictionary
    return cols_count

# Call count_entries(): result1
result1 = count_entries(tweets_df)

# Call count_entries(): result2
result2 = count_entries(tweets_df ,'source')

# Print result1 and result2
print(result1)
print(result2)


# -

# Wow, you've just generalized your Twitter language analysis that you did in the previous chapter to include a default argument for the column name. You're now going to generalize this function one step further by allowing the user to pass it a flexible argument, 
# that is, in this case, as many column names as the user would like!

# +
# Define count_entries()
def count_entries(df, *args):
    """Return a dictionary with counts of
    occurrences as value for each key."""
    
    #Initialize an empty dictionary: cols_count
    cols_count = {}
    
    # Iterate over column names in args
    for col_name in args:
    
        # Extract column from DataFrame: col
        col = df[col_name]
    
        # Iterate over the column in DataFrame
        for entry in col:
    
            # If entry is in cols_count, add 1
            if entry in cols_count.keys():
                cols_count[entry] += 1
    
            # Else add the entry to cols_count, set the value to 1
            else:
                cols_count[entry] = 1

    # Return the cols_count dictionary
    return cols_count

# Call count_entries(): result1
result1 = count_entries(tweets_df, 'lang')

# Call count_entries(): result2
result2 = count_entries(tweets_df, 'lang', 'source')

# Print result1 and result2
print(result1)

print(result2)
# -



StarcoderdataJupyterScriptsDedupFiltered