Back to Freecodecamp

Step 8

curriculum/challenges/english/blocks/learn-encapsulation-by-building-a-projectile-trajectory-calculator/662fa453ec8033322b3ab2e3.md

latest3.5 KB
Original Source

--description--

It's time to talk about encapsulation and getters. You have written the three instance attributes to be private using a leading double underscore. Note that these attributes are called private by convention: although they can still be accessed from outside, it is agreed upon to not do that.

Getters are what can be used to get the values from outside. To define a getter, you define a method that returns the value of the desired attribute and give it a @property decorator:

py
class Nest:
    ...
    @property
    def number_of_eggs(self):
        return self.__number_of_eggs

The decorator changes the method into a property, meaning that the method is not called like a regular method, but it's used like an attribute:

py
n = Nest()
print(n.number_of_eggs)

In the example above, the private attribute __number of eggs is accessed through the number_of_eggs property of n.

Create a getter named speed and make it return the value of the private attribute __speed.

--hints--

You should define a speed method.

js
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').has_function('speed')
`))})

Your speed method should have a single parameter, self.

js
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').find_function('speed').has_args('self')
`))})

Your speed method should have a @property decorator.

js
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').find_function('speed').has_decorators('property')
`))})

Your speed method should return the value of the private attribute __speed.

js
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.speed == 22
`))})

--seed--

--seed-contents--

py
import math

GRAVITATIONAL_ACCELERATION = 9.81
PROJECTILE = "∙"
x_axis_tick = "T"
y_axis_tick = "⊣"

class Projectile:
    __slots__ = ('__speed', '__height', '__angle')

    def __init__(self, speed, height, angle):
        self.__speed = speed
        self.__height = height
        self.__angle = math.radians(angle)
        
    def __str__(self):
        return f'''
Projectile details:
speed: {self.__speed} m/s
height: {self.__height} m
angle: {round(math.degrees(self.__angle))}°
displacement: {round(self.__calculate_displacement(), 1)} m
'''

    def __calculate_displacement(self):
        horizontal_component = self.__speed * math.cos(self.__angle)
        vertical_component = self.__speed * math.sin(self.__angle)
        squared_component = vertical_component**2
        gh_component = 2 * GRAVITATIONAL_ACCELERATION * self.__height
        sqrt_component = math.sqrt(squared_component + gh_component)
        
        return horizontal_component * (vertical_component + sqrt_component) / GRAVITATIONAL_ACCELERATION
        
    def __calculate_y_coordinate(self, x):
        height_component = self.__height
        angle_component = math.tan(self.__angle) * x
        acceleration_component = GRAVITATIONAL_ACCELERATION * x ** 2 / (
                2 * self.__speed ** 2 * math.cos(self.__angle) ** 2)
        y_coordinate = height_component + angle_component - acceleration_component

        return y_coordinate
    
    def calculate_all_coordinates(self):
        return [
            (x, self.__calculate_y_coordinate(x))
            for x in range(math.ceil(self.__calculate_displacement()))
        ]

--fcc-editable-region--
    
--fcc-editable-region--

ball = Projectile(10, 3, 45)
print(ball)
coordinates = ball.calculate_all_coordinates()