Python Mixed Flashcards

1
Q

NumPy Array

A
  • A multi-dimensional array provided by the Numerical Python library.
  • Homogeneous: All elements are of the same type (lists are heterogenous).
  • Efficient in terms of memory and speed.
  • Supports a wide range of mathematical operations natively.
  • Fixed in size once created.

””””
More than one dimension:
np.array([[1, 2], [3, 4]])
array([[1, 2],
[3, 4]])
“”””
Minimum dimensions 2:
np.array([1, 2, 3], ndmin=2)
array([[1, 2, 3]])
“”””
Type provided:
np.array([1, 2, 3], dtype=complex)
array([ 1.+0.j, 2.+0.j, 3.+0.j])

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

zip function

A
  • Combines two or more iterables into a sequence of tuples.
  • Each tuple contains elements from the input iterables paired together.
  • Stops when the shortest iterable is exhausted.
  • Example: zip([1, 2, 3], [‘a’, ‘b’, ‘c’]) -> [(1, ‘a’), (2, ‘b’), (3, ‘c’)]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Iterables

A
  • Objects that can be looped over or traversed.
  • Returns an iterator to loop over its elements.
  • Examples include lists, dictionaries, strings, and sets.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Tuples

A
  • Ordered and immutable collections.
  • Used to represent data where order is significant and modification is not permitted.
  • Defined using parentheses, e.g., (1, ‘a’, 3.4) –> Can be unpacked: a, b, c = (1, ‘a’, 3.4)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Binary tree

A

Each node has at MOST 2 children

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Binary search tree

A

a binary tree in which all the left children of a node <= n (node in question) < all right descendants

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Static memory allocation

A

E.g., stacks or arrays: will manage memory for you and assume a fixed amount of memory upon instantiation with a cap on how much data may be added.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

dynamic memory allocation

A

e.g., heaps or linked lists: allow you to allocate and reallocate memory within the life of the program.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Nodes

A

An individual node contains data and links to other nodes. Each data structure adds additional constraints or behavior to these features to create the desired structure.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Pointers

A

The link or links within the node are sometimes referred to as pointers. This is because they “point” to another node

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the time complexity of a linear search algorithm?

A

O(N)

N/2 depicted as O(N) in Big O connotation

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is the time complexity for binary search?

A

O(log N)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How many search comparisons will a binary algorithm make in a sorted 1000-element list?

A

log(1000)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

list of integers 1 to n, with one missing, find it

A

use n*(n+1)/2 formula to find sum of full list, then subtract sum of missing list

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Display the first five rows of the DataFrame, including column titles

A

Df.head()
further commands:
Df.columns
Df.info()
Df.describe()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

for a Dataframe df, create a rolling window for the “return” column

A

df[‘return’].rolling(window=…)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

What does .apply(lambda x: (x + 1).prod() - 1) accomplish in the context of rolling windows?

A
  • Applies a custom calculation to each rolling window.
  • lambda x: Defines an anonymous function for the calculation.
  • (x + 1): Adds 1 to each element (useful for compounding returns)
  • .prod(): Computes the product of elements in the window, compounding the returns.
    • 1: Adjusts the final compounded product back to a % format.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

iterate over dict_x

A

for key, value in dict_x.items():

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What are the three main operations for a stack?

A
  • Push: adds data to the top of the stack
  • Pop: removes and provides data from the top of the stack
  • Peek: reveals data on the top of the stack
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

hash function will first compute…

A

a value using some scoring metric –> this is the hash value, hash code, or just the hash.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Our hash map implementation then takes that hash value …. the size of the array (missing word…)

A

mod

22
Q

mod = modulo operation

A

a modulo n (abbreviated as a mod n) is the remainder of the Euclidean division of a by n, where a is the dividend and n is the divisor.

23
Q

defining feature of all hash functions: they greatly reduce any possible inputs into a much smaller range of potential outputs –> thus known as…

A

compression functions.

24
Q

Is hashing a reversible process?

A

No

25
Q

Many hash functions implementations for strings take advantage of the fact that strings are represented internally as numerical data. Frequently a hash function will perform … of the data bitwise, which is computationally simple for a computer to do but also can predictably assign numbers to strings.

A

a shift

26
Q

How is the storage location at the index given by a hash called?

A

hash bucket

27
Q

avoid a hash collision - strategies

A
  • separate chaining: updates the underlying data structure, e.g. linked lists instead of array
  • open addressing: one common method: probing (i.d. finding new array indices)
28
Q

open addressing techniques

A
  • Linear probing systems: e.g. jump by 1 or 5 steps
  • quadratic probing: e.g. 1, 4, 9, etc. to avoid clustering
29
Q

determine whether a HTTP get request worked, otherwise output “Invalid response”

A

assert response.status_code == 200, “Invalid response”

30
Q

parse the JSON content of an object and convert it into a Python data structure (in this case, a dictionary)

A

.json()

31
Q

drop NaN values in a pd frame

A

dropna()

32
Q

calculate a correlation matrix for a pd frame (with percentage changes as values

A

pd_frame.corr()

33
Q

perform matrix multiplication with numpy

A

np.matmul(matrix1, matrix2)

34
Q

function to in numpy and other numerical computing libraries identify the index of the maximum value in an array

A

argmax()

35
Q

generate random numbers from a normal distribution

A

np.random.normal() –> numpy function which takes two key parameters: loc and scale, which represent the mean and standard deviation of the distribution, respectively.

36
Q

calculate the exponential of all elements in an input array with e as the base of the logarithm

A

np.exp(x)

x can be a number, a list, or a NumPy array of numbers

Returns: An array of the same shape as x, with each element being e raised to the power of the corresponding element in x.
e^1 = e

37
Q

matrix multiplication between a matrix and an array

A

np.dot(…, …)

38
Q

transpose the weights vector from a column vector to a row vector - and for 1D numpy arrays?

A

.T –> transpose the weights vector from a column vector to a row vector

However, for 1D NumPy arrays, .T does not change its shape.

39
Q

check whether something ends or starts with a certain string

A

.endswith() or .startswith() –> accepts only string or tuple

40
Q

Recursion vs iteration

A

Recursion and iteration are both different ways to execute a set of instructions repeatedly. The main difference between these two is that in recursion, we use function calls to execute the statements repeatedly inside the function body, while in iteration, we use loops like “for” and “while” to do the same.

41
Q

Traversal vs iteration

A

“Traversal” just means walking through (all or some) elements of a data structure.

Historically, “iteration” in computer science is a special form of recursion for which no additional stack space is needed – in other words, tail recursion. This form is computationally exactly equivalent to what we now colloquially know as “iteration”, namely a finite loop (such as a for loop with a fixed lower and upper bound).

Now this makes iteration especially well suited (compared to general recursion) for traversing linear data structures. Note that it does not work for all containers (e.g. general graphs) because here you need to remember the already visited nodes (e.g. using depth-first search, which is defined recursively in terms of adjacent nodes, rather than via the C++ concept of iterators).

It is in this context that the term “iteration” is used in C++ applied to containers.

In summary: not every traversal is an iteration but every iteration (over a data structure) is a traversal. However, it’s worth noting that many people make no such distinction and use the terms interchangeably.

42
Q

tail-recursive function

A

A function is tail-recursive if it ends by returning the value of the recursive call
–> recursive function where the recursive call is the last statement the function executes

43
Q

heap

A

Heap is a special tree structure in which each parent node is less than or equal to its child node. Then it is called a Min Heap. If each parent node is greater than or equal to its child node then it is called a max heap. It is very useful is implementing priority queues where the queue item with higher weightage is given more priority in processing.

44
Q

What is Big O notation?

A

Big O Notation gives the upper-bound runtime or worst-case complexity of an algorithm

45
Q

What Are Objects And Classes?

A

Sure! In programming, think of a “class” as a blueprint for making something. It’s like the concept of a “car” in general; you know a car has wheels, seats, and an engine, but this general idea doesn’t tell you anything about a specific car, like its color or make.

Objects are like individual instances or examples of that blueprint. If a “class” is the general concept of a “car,” then an “object” would be a specific car, like a red Toyota Corolla with a sunroof.

Classes and Objects in terms of Grammar:

  1. Class = Noun: A class is like a “noun,” a general concept that describes things. For example, “Dog” is a noun that represents a general concept of a four-legged animal that barks.
  2. Object = Proper Noun: An object is like a “proper noun,” a specific instance of that general concept. For example, “Fido” would be a specific dog with its own unique traits and behaviors.
  3. Attributes = Adjectives: Attributes are qualities or characteristics of the object. Just like adjectives describe nouns, attributes describe or provide more details about objects. For example, the color of the car, or the breed of the dog.
  4. Methods = Verbs: Methods are actions that the object can perform. Like how verbs show what a noun can do, methods define what an object can do. For example, a dog can “bark,” or a car can “accelerate.”

Example:

Let’s take a class called “Dog.”

  • Class (Noun): Dog
  • Attributes (Adjectives): Breed, Color, Age
  • Methods (Verbs): Bark, Fetch

Now, let’s create an object from this class.

  • Object (Proper Noun): Fido
    • Attributes (Adjectives): Golden Retriever, Yellow, 3 years
    • Methods (Verbs): Fido can Bark, Fido can Fetch

So, a class is like the blueprint that tells us what a ‘Dog’ should have and be able to do, while an object is a specific ‘Dog’ with its own attributes and behaviors.

Treehouse Notes:
The class keyword lets us define a class. We use it just like we do the def keyword for making functions. Class definitions are blocks like function definitions.

class NewClass:

Inside of the class, variables are called attributes.

class NewClass:
    name_attribute = "Kenneth"

And functions that are defined inside of a class are called methods.
~~~
class NewClass:
name_attribute = “Kenneth”

def name_method(self):
    return self.name_attribute ~~~ Whenever we call a class, it creates an instance. Each instance has full access to the all of the attributes and methods of the class. ~~~ new_instance = NewClass() new_instance.name_method() ~~~
46
Q

In Python, only dictionaries, lists, tuples, and sets are objects. Is this true?

A

No, that statement is not true. In Python, nearly everything is an object. This includes not just dictionaries, lists, tuples, and sets, but also numbers, strings, functions, and even modules and classes themselves. Python is an object-oriented language, which means that it uses objects as a fundamental building block for constructing programs.

Examples:

  1. Numbers are objects: You can find out the type of an object using the type() function.
    python
     x = 42
     print(type(x))  # Output: <class 'int'>
  2. Strings are objects: They have methods like upper(), lower(), etc.
    python
     s = "hello"
     print(s.upper())  # Output: "HELLO"
  3. Functions are objects: You can assign them to variables, pass them as arguments, etc.
    ```python
    def my_function():
    print(“Hello from my_function”)func_var = my_function
    func_var() # Output: “Hello from my_function”
    ```
  4. Modules are objects: You can assign them to variables and manage them just like any other object.
    python
     import math
     print(type(math))  # Output: <class 'module'>
  5. Even Classes are objects: They are instances of a meta-class.
    ```python
    class MyClass:
    passprint(type(MyClass)) # Output: <class ‘type’>
    ```

So, in Python, the concept of an “object” is very broad and not limited to just a few data types.

47
Q

Sequence 1: The file characters.py contains:
~~~
class Thief:
pass
~~~
The following is run within terminal/console:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth
~~~

Sequence 2:
The file characters.py contains:
~~~
class Thief:
sneaky = True #attribute
~~~
The following is run within terminal/console:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth.sneaky
~~~

Explain the sequence 1 and 2, what’s happening in it?

A

Certainly! Let’s go through both sequences step-by-step.

Sequence 1:

  1. File Creation: The file characters.py contains a class definition for Thief. The pass statement is a placeholder indicating that the class is currently empty; it doesn’t have any attributes or methods yet.
    python
     class Thief:
       pass
  2. Console/Terminal Steps:
    • python: This command starts the Python interpreter.
    • from characters import Thief: This imports the Thief class from the characters.py file. Now you can create instances (objects) of this class.
    • kenneth = Thief(): This creates a new object of the Thief class and assigns it to the variable kenneth.
    • kenneth: This would display a representation of the kenneth object, something like <\_\_main\_\_.Thief object at 0x7f8f9c0>.

Sequence 2:

  1. File Creation: The file characters.py has been updated to include an attribute sneaky in the Thief class, set to True.
    python
     class Thief:
       sneaky = True  # attribute
  2. Console/Terminal Steps:
    • python: Starts the Python interpreter.
    • from characters import Thief: Imports the updated Thief class from the characters.py file.
    • kenneth = Thief(): Creates a new object of the Thief class and assigns it to the variable kenneth.
    • kenneth.sneaky: Accesses the sneaky attribute of the kenneth object. Since sneaky is set to True in the class definition, this would return True.

Summary:

  • In Sequence 1, you created an empty Thief class and made an instance of it. The instance didn’t have any special attributes or methods because the class was empty.
  • In Sequence 2, you added a sneaky attribute to the Thief class and set it to True. When you made an instance of this updated class, you could access this attribute, which returned True.

In both sequences, the steps in the terminal are to import the class and create an instance (object) of that class. The key difference is in the attributes that the class and its instances have.

48
Q

Sequence 1:
The file characters.py contains the following code:
~~~
import random

class Thief:
sneaky = True #attribute
def pickpocket(self): #methods
return bool(random.randint(0, 1))
~~~
The following code is run in console/terminal:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth.pickpocket() #returns false
Thief.pickpocket() #returns error as has no self
Thief.pickpocket(kenneth) #kenneth is self, returns false
~~~

Sequence 2:
The file characters.py contains the following code:
~~~
import random

class Thief:
sneaky = True #attribute
def pickpocket(self): #methods
print(“Called by {}”.format(self))
return bool(random.randint(0, 1))
~~~
The following code is run in console/terminal:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth.pickpocket()
Thief.pickpocket(kenneth)
~~~

Sequence 3:
The file characters.py contains the following code:
~~~
import random

class Thief:
sneaky = True #attribute
def pickpocket(self): #methods
if self.sneaky:
return bool(random.randint(0, 1))
return False
~~~
The following code is run in console/terminal:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth.pickpocket() #returns True
kenneth.pickpocket() #returns Talse
kenneth.pickpocket() #returns True
kenneth.sneaky = False
kenneth.pickpocket() #returns False
kenneth.pickpocket() #returns False
kenneth.pickpocket() #returns False
~~~

Explain the sequence 1,2,3 and what’s happening in it?

A

Absolutely! Let’s break down what’s happening in each of the sequences.

Sequence 1:

  1. File Code: In characters.py, a Thief class is defined with an attribute sneaky set to True and a method pickpocket that returns a random boolean value (True or False).```python
    import randomclass Thief:
    sneaky = True
    def pickpocket(self):
    return bool(random.randint(0, 1))
    ```
  2. Console Steps:
    • kenneth = Thief(): Creates an object kenneth of class Thief.
    • kenneth.pickpocket(): Calls the pickpocket method on the kenneth object. This returns False due to the random number generated.
    • Thief.pickpocket(): Tries to call pickpocket directly on the class, which results in an error because no self argument is provided.
    • Thief.pickpocket(kenneth): Calls pickpocket on the class, passing kenneth as the self argument. This works and returns False (due to random generation).

Sequence 2:

  1. File Code: Similar to Sequence 1, but the pickpocket method now includes a print statement to show which object called it.
    python
     def pickpocket(self):
       print("Called by {}".format(self))
       return bool(random.randint(0, 1))
  2. Console Steps:
    • kenneth.pickpocket(): Calls the method and prints “Called by <Thief>".</Thief>
    • Thief.pickpocket(kenneth): Similar to the above but called directly on the class. It also prints the same message.

Sequence 3:

  1. File Code: The pickpocket method now includes an if condition that checks the sneaky attribute before returning a random boolean.
    python
     def pickpocket(self):
       if self.sneaky:
         return bool(random.randint(0, 1))
       return False
  2. Console Steps:
    • kenneth.pickpocket(): Called multiple times and returns either True or False based on random generation, because sneaky is True.
    • kenneth.sneaky = False: Sets sneaky to False.
    • kenneth.pickpocket(): Now always returns False as sneaky is set to False.

Summary:

  • Sequence 1: Demonstrates basic class and method usage, including how to call methods both on an instance and directly on the class.
  • Sequence 2: Adds a print statement to show which instance is calling the method.
  • Sequence 3: Adds conditional logic to the method based on an attribute, demonstrating how methods can access and use the attributes of the instance on which they are called. It also shows how changing an attribute affects the behavior of methods.
49
Q

Challenge Task 1 of 1
This class should look familiar! First, I need you to add a method named praise to the Student class. It should take the self argument. Then, inside the praise method, return a positive message about the student using the name attribute. As an example, it could say “You’re doing a great job, Jacinta!” or “I really like your hair today, Michael!”. Feel free to change the name attribute to your own name, too!

File: first_class.py:
~~~
class Student:
name = “Your Name”
~~~

A

Task 1:
Variant 1:
~~~
class Student:
name = “Sethu”

def praise(self):
    return "You're doing a great job {}".format(self.name) ~~~

Variant 2:
~~~
class Student:
name = “Sethu”

def praise(self):
    return f"You're doing a great job, {self.name}!" ~~~

Run:
~~~
# Adding a method named ‘praise’ to the Student class
class Student:
name = “Your Name”

def praise(self):
    return f"You're doing a great job, {self.name}!"

Create an instance of the Student class to test the praise method
student_instance = Student()
praise_message = student_instance.praise()
praise_message
~~~

Result:
~~~
“You’re doing a great job, Your Name!”
~~~

50
Q

Sequence 1:
The file characters.py contains the following:
~~~
import random

class Thief:
sneaky = True #attribute

def pickpocket(self): #methods
if self.sneaky:
return bool(random.randint(0, 1))
return False

def hide(self, light_level):
return self.sneaky and light_level <10
~~~

The following code is run in Terminal/Console:
~~~
python
from characters import Thief
kenneth = Thief()
kenneth.hide(4)
kenneth.hide(14)
kenneth.sneaky = False
kenneth.hide(0)
~~~

Sequence 2:
The file characters.py contains the following:
~~~
import random

class Thief:
sneaky = True # attribute

def __init__(self, name, sneaky=True, **kwargs):
self.name = name
self.sneaky = sneaky

def pickpocket(self): # methods
return self.sneaky and bool(random.randint(0, 1))

def hide(self, light_level):
return self.sneaky and light_level < 10
~~~

The following code is run in Terminal/Console:
~~~
from characters import Thief
kenneth = Thief(“Kenneth”, False)
kenneth.name
kenneth.sneaky
~~~

Sequence 3:
The file characters.py contains the following:
~~~
import random

class Thief:
sneaky = True # attribute

def __init__(self, name, sneaky=True, **kwargs):
self.name = name
self.sneaky = sneaky

for key, value in kwargs.items():
  setattr(self, key, value)

def pickpocket(self): # methods
return self.sneaky and bool(random.randint(0, 1))

def hide(self, light_level):
return self.sneaky and light_level < 10
~~~

The following code is run in Terminal/Console:
~~~
from characters import Thief
kenneth = Thief(“Kenneth”, scars=None, favorite_weapon=”Wit”)
kenneth.name
kenneth.sneaky
kenneth.favorite weapon
~~~

Explain the sequence 1,2,3 and what’s happening in it?

A

Certainly, let’s explore each sequence in more detail, taking into account both the code within characters.py and the code run in the terminal.

Sequence 1

characters.py
- Thief class is defined with a class attribute sneaky set to True.
- Two methods, pickpocket() and hide(light_level), are also defined. pickpocket() returns a random boolean if sneaky is True, and hide() returns True if sneaky is True and light_level is less than 10.

Terminal/Console
- An object named kenneth is created from the Thief class.
- kenneth.hide(4) is called and would return True because light_level (4) is less than 10 and sneaky is True.
- kenneth.hide(14) would return False because light_level (14) is not less than 10.
- kenneth.sneaky is set to False.
- kenneth.hide(0) is called and would now return False because sneaky is False, irrespective of light_level.

Sequence 2

characters.py
- Thief class now includes an \_\_init\_\_ method to initialize name and sneaky attributes when a new object is created.
- pickpocket() is modified to return a boolean based on both sneaky and a random value between 0 and 1.

Terminal/Console
- A new object named kenneth is created with sneaky set to False and name set to “Kenneth”.
- Accessing kenneth.name would return “Kenneth”.
- Accessing kenneth.sneaky would return False.

Sequence 3

characters.py
- Thief class is further modified to accept arbitrary keyword arguments (**kwargs) in the \_\_init\_\_ method.
- These keyword arguments are set as attributes on the object using the setattr function.

Terminal/Console
- A new object named kenneth is created with additional attributes: scars is set to None, and favorite_weapon is set to “Wit”.
- Accessing kenneth.name would return “Kenneth”.
- Accessing kenneth.sneaky would return True (default value as no value for sneaky was provided during object creation).
- Accessing kenneth.favorite_weapon would return “Wit”. Note: The code has a typo and uses kenneth.favorite weapon which would actually result in a syntax error. It should be kenneth.favorite_weapon.

In summary, these sequences display the evolution of the Thief class, starting from a simple version to a more complex one that allows for custom attributes and initialization. The terminal/console interactions help to show how these class features can be accessed and modified for individual objects.

51
Q

Challenge Task 1 of 1
Alright, I need you to make a new method named feedback. It should take self and an argument named grade. Methods take arguments just like functions do.

Inside the feedback method, if grade is above 50, return the result of the praise method. If it’s 50 or below, return the reassurance method’s result.

first_class.py:
~~~
class Student:
name = “Your Name”

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name) ~~~
A

Task 1:
Certainly! To implement the feedback method, you can check the value of the grade argument and return the result of either the praise or reassurance method accordingly. Here’s how you can update the Student class in first_class.py:

```python
class Student:
name = “Your Name”

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name)

def feedback(self, grade):
    if grade > 50:
        return self.praise()
    else:
        return self.reassurance() ~~~

Now, the Student class has a feedback method that takes a grade argument. If grade is greater than 50, the method returns the result of praise(). Otherwise, it returns the result of reassurance().

You can test the feedback method by creating an instance of the Student class and calling it:

```python
student1 = Student()
student1.name = “Alice”

print(student1.feedback(60)) # Output: “You inspire me, Alice”
print(student1.feedback(40)) # Output: “Chin up, Alice. You’ll get it next time!”
~~~

52
Q

Challenge Task 1 of 2:
Our Student class is coming along nicely!
I’d like to be able to set the name attribute at the same time that I create an instance. Can you add the code for doing that?

Override the \_\_init\_\_ method by adding your own \_\_init\_\_ method to the Student class. Add self and name as arguments to the \_\_init\_\_ method. Inside of \_\_init\_\_, set self.name to the argument name.

first_class.py:
~~~
class Student:
name = “Your Name”

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name)

def feedback(self, grade):
    if grade > 50:
        return self.praise()
    return self.reassurance() ~~~

Challenge Task 2 of 2:
Sometimes I have other attributes I need to store on a Student instance. Add **kwargs as an argument to the \_\_init\_\_ method. Then use setattr inside the \_\_init\_\_ method to add attributes for any other key/value pairs I want to send to the instance when I create it.

first_class.py:
~~~
class Student:
name = “Your Name”

def \_\_init\_\_(self, name):
    self.name = name

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name)

def feedback(self, grade):
    if grade > 50:
        return self.praise()
    return self.reassurance() ~~~
A

Task 1:
~~~
class Student:
name = “Your Name”

def \_\_init\_\_(self, name):
    self.name = name

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name)

def feedback(self, grade):
    if grade > 50:
        return self.praise()
    return self.reassurance() ~~~

Task 2:
~~~
class Student:
name = “Your Name”

def \_\_init\_\_(self, name, **kwargs):
    self.name = name
    for key, value in kwargs.items():
        setattr(self, key, value)

def praise(self):
    return "You inspire me, {}".format(self.name)

def reassurance(self):
    return "Chin up, {}. You'll get it next time!".format(self.name)

def feedback(self, grade):
    if grade > 50:
        return self.praise()
    return self.reassurance() ~~~