Skip to content

[New classes concept exercise]: ellens-alien-game #2876

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 50 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e165ac3
New concept exercise: ellens-alien-game
PaulT89 Jan 26, 2022
8b396ec
Update config.json
PaulT89 Jan 24, 2022
7646897
Delete introduction-draft.md
PaulT89 Jan 24, 2022
349a580
Create introduction
PaulT89 Jan 24, 2022
b3147c4
Rename introduction to introduction.md
PaulT89 Jan 24, 2022
a10beaa
Update and rename design-draft.md to design.md
PaulT89 Jan 24, 2022
238362a
Fixed typo in instructions.md
PaulT89 Jan 25, 2022
38b1943
Formatting with YAPF
PaulT89 Jan 25, 2022
40741ae
Update config.json
PaulT89 Jan 25, 2022
d5cf099
Update exercises/concept/ellens-alien-game/.meta/config.json
PaulT89 Jan 25, 2022
41350d3
Improve wording and formatting for code formatting
PaulT89 Jan 25, 2022
adc99cc
Using comprehension for our list of aliens
PaulT89 Jan 25, 2022
15dde35
Rename alien_class_test.py to classes_test.py
PaulT89 Jan 25, 2022
a3bd24e
Rename alien_class.py to classes.py
PaulT89 Jan 25, 2022
fa82ca2
Added pytest decorators to classes.py
PaulT89 Jan 25, 2022
2c784c8
Filled design.md with content
PaulT89 Jan 25, 2022
98949d3
Added missing pytest decorator
PaulT89 Jan 25, 2022
42ce67f
Update instructions.md
PaulT89 Jan 25, 2022
8d8b678
Update design.md
PaulT89 Jan 26, 2022
942e3c5
Update classes.py
PaulT89 Jan 26, 2022
5e39d36
Update hints.md
PaulT89 Jan 26, 2022
bdc5e27
remove trailing whitespace
Jan 26, 2022
36d30b1
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
36a2018
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
3438440
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
c5e6417
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
63e7f08
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
8cd75e8
Update exercises/concept/ellens-alien-game/.meta/exemplar.py
PaulT89 Jan 26, 2022
28302fd
Update instructions.md
PaulT89 Jan 26, 2022
aced0d5
Update exemplar.py
PaulT89 Jan 26, 2022
f8854d9
Update exercises/concept/ellens-alien-game/.docs/instructions.md
PaulT89 Jan 26, 2022
8e23109
design.md: Removed `properties` from Concepts
PaulT89 Jan 28, 2022
ce0a3bb
Code Files Cleanup
BethanyG Feb 16, 2022
6bcce85
Edited Instructions to Match Exemplar
BethanyG Feb 16, 2022
4072b3d
Merge branch 'exercism:main' into main
PaulT89 Feb 16, 2022
c831df9
Merge branch 'main' of github.com:PaulT89/python
PaulT89 Feb 16, 2022
000155d
Merge branch 'main' of github.com:PaulT89/python
PaulT89 Feb 16, 2022
e38e6c9
Added contents to intro
PaulT89 Feb 16, 2022
a373881
Added content to about
PaulT89 Feb 16, 2022
79275b7
Add content to concept intro
PaulT89 Feb 16, 2022
a51ab9a
Merge pull request #1 from PaulT89/code-files-edits
PaulT89 Feb 16, 2022
a243002
Added two links + descriptions
PaulT89 Feb 16, 2022
e89094e
Update config.json
PaulT89 Feb 16, 2022
99b81d5
Added blurb to config.json
PaulT89 Feb 16, 2022
d39229e
Apply suggestions from code review
BethanyG Feb 16, 2022
2ed9675
Added additional resources to links.json
BethanyG Feb 16, 2022
38d9c09
Added links + fixed typos
PaulT89 Feb 17, 2022
e9789e5
Fixed typos
PaulT89 Feb 17, 2022
31eb5f4
General Cleaning
PaulT89 Feb 17, 2022
4108002
Fixed typos + removed whitespace
PaulT89 Feb 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions concepts/classes/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"blurb": "TODO: add blurb for this concept",
"authors": ["bethanyg", "cmccandless"],
"blurb": "Classes and Objects are integral to object oriented programming, in which programs are made up of objects that interact with one another. Classes are definitions combining data with behaviour and are used to create objects. Objects can represent real world entities or more abstract concepts.",
"authors": ["bethanyg", "DjangoFett", "PaulT89"],
"contributors": []
}


324 changes: 323 additions & 1 deletion concepts/classes/about.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,324 @@
#TODO: Add about for this concept.
# About

`Classes` combine data with behavior.
Class are used to create copies or `instances`, commonly known as `objects`.
Objects can represent real world entities (_such as Cars or Cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_).
Classes are integral to an [object oriented programming][oop] (OOP) approach, which asks the programmer to think about modeling a problem as one or more objects that interact with one another, keep state, and act upon data.

## Classes

Classes are the definitions of new _object types_, and from which new `instances` of objects are created.
They often bundle data (_known as `fields`, `attributes`, `properties`, `data members`, or `variables`_) with code or functions (_known as `methods`_) that operate on that data.
In this sense, classes are _blueprints_ or sets of instructions from which many objects of a similar type can be built and used.
A complex program can have many classes, each building many different flavors of objects.
The process of building and customizing an object from a class is known as `instantiation` (_or creating an instance of the class_).

A class definition in Python is straightforward:

```python
class My_Class:
# Class body goes here
```

### Class Attributes

Class fields (_otherwise known as properties, attributes, data members, or variables_) can be added to the body of the class.

```python
class My_Class:
number = 5
string = "Hello!"
```

An instance (_object_) of `My_Class` can be created and bound to a name:

```python
>>> new_object = My_Class()

# Class is instantiated and resulting object is bound to the "new_object" name.
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.My_Class at 0x15adc55b0>
```

`Class attributes` are shared across all objects (_or instances_) created from a class, and can be accessed via [`dot notation`][dot notation] - a `.` placed after the object name and before the attribute name:

```python
>>> new_object = My_Class()

# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5

# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'

# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = My_Class()

>>> second_new_object
<__main__.My_Class at 0x15ad99970>

# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True
```

Class attributes are defined in the body of the class itself, before any other methods.
They are owned by the class - allowing them to be shared across instances.
Because these attributes are shared by all instances of the class, their value can be accessed and manipulated from the class directly.
Altering the value of class attributes alters the value _**for all objects instantiated from the class**_:

```python
>>> obj_one = My_Class()
>>> obj_two = My_Class()

# Accessing a class attribute from an object.
>>> obj_two.number
5

# Accessing the class attribute from the class itself.
>>> My_Class.number
5

# Modifying the value of the "number" class attribute.
>>> My_Class.number = 27

# Modifying the "number" class attribute changes the "number" attribute for all instantiated objects.
>>> obj_one.number
27

>>> obj_two.number
27
```

Having a bunch of objects with synchronized data at all times is not particularly useful.
Fortunately, objects created from a class can be customized with their own `instance attributes` (_or instance properties, variables, or fields_).
As their name suggests, instance attributes are unique to each object, and can be modified independently.

## Customizing Object Instantiation with `__init__()`

The special ["dunder method"][dunder] (_short for "double underscore method"_) `__init__()` is used to customize class instances, and can be used to initialize instance attributes or properties for objects.
For its role in initializing instance attributes, `__init__()` is also referred to as a `class constructor` or `initializer`.
`__init__()` takes one required parameter called `self`, which refers to the newly initiated or created object.
Instance attributes or properties can then be defined as parameters of `__init__()`, following the `self` parameter.

Below, `My_Class` now has instance attributes called `location_x` and `location_y`.
As you can see, the two attributes have been assigned to the first and second indexes of the `location` (_a tuple_) argument that has been passed to `__init__()`.
The `location_x` and `location_y` attributes for a class instance will now be initialized when you instantiate an object from the class:

```python
class My_Class:
# These are class attributes, variables, or fields.
number = 5
string = "Hello!"

# This is the class "constructor", with a "location" parameter that is a tuple.
def __init__(self, location):

# This is an instance or object property, attribute, or variable.
# Note that we are unpacking the tuple argument into two seperate instance variables.
self.location_x = location[0]
self.location_y = location[1]

# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = My_Class((1, 2))

# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = My_Class((-8, -9))

# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1

>>> new_object_two.location_x
-8
```

Note that you only need to pass one argument when initializing `My_Class` above -- Python takes care of passing `self` when the class is called.

~~~~exercism/advanced
Another way of creating an instance variable is to simply access a class variable via an object, and change it to something else:

```python
>>> obj_one = My_Class()
>>> obj_two = My_Class()
>>> My_Class.string
'Hello!'

>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'

>>> obj_one.string
'Hello!'
```

Now, watch what happens when the class variable changes:

```python
>>> My_Class.string = "World!"
>>> obj_two.string

# obj_two.string has not changed
'Hi!'

>>> obj_one.string

# obj_one.string changed
'World!'
```

The attribute `string` is now an _instance variable_ in the case of `obj_two`, but remains a _class variable_ in `obj_one`.

This can also be done from within the class:

```python
class Demo:
new_var = 3

def add_two(self):
self.new_var += 2
```

The moment that `<object>.add_two()` is called, and `self.new_var += 2` is read, `new_var` changes from a class variable to an instance variable of the same name.

This can be useful during initialization when all instances of a class will need some attribute(s) to start with the same value.
However, the instance variable then shadows* the class variable, making the class variable inaccessible from the instance where it is shadowed. Given this situation, it may be safer and clearer to set instance attributes from the `__init__()` method as `self.<attribute>`.
~~~~
_*[_shadows_][shadowing]

## Methods

A `method` is a `function` that is bound to either the class itself (_known as a [class method][class method], which will be discussed in depth in a later exercise_) or an _instance_ of the class (object).
Methods that operate on an object or instance need to be defined with `self` as the first parameter.
You can then define the rest of the parameters as you would for a "normal" or non-bound function.
Methods that operate on a class need to be defined with both the `@classmethod` decorator and with `cls` as the first parameter.
Class methods are called on a class directly without first instantiating an object from the class.

```python
class My_Class:
number = 5
string = "Hello!"

# Class constructor.
def __init__(self, location):

# Instance properties
self.location_x = location[0]
self.location_y = location[1]

# Class Method. Uses the @classmethod decorator, and cls as the first parameter.
# Can be called without first making an instance of the class.
@classmethod
def change_string(cls, new_string):
#Class attributes are referred to with cls.
cls.string = new_string
return cls.string

# Instance method. Note "self" as first parameter.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
```

Like attribute access, calling a method simply requires putting a `.` after the object name, and before the method name.
The called method does not need a copy of the object as a first parameter -- Python fills in `self` automatically:

```python
class My_Class:
number = 5
string = "Hello!"

def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]

def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y

# Make a new test_object with location (3,7)
>>> test_object = My_Class((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)

# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)
```

Class attributes can be accessed from within instance methods in the same way that they are accessed outside of the class:

```python
class My_Class:
number = 5
string = "Hello!"

def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]

# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y

# Alter class variable number for all instances from within an instance.
def increment_number(self):
# Increment the 'number' class variable by 1.
My_Class.number += 1


>>> test_object_one = My_Class((0,0))
>>> test_object_one.number
5

>>> test_object_two = My_Class((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6
```

## Placeholding or Stubbing Implementation with Pass

In previous concept exercises and practice exercise stubs, you will have seen the `pass` keyword used within the body of functions in place of actual code.

The `pass` keyword is a syntactically valid placeholder - it prevents Python from throwing a syntax error or `NotImplemented` error for an empty function or class definition.
Essentially, it is a way to say to the Python interpreter, 'Don't worry! I _will_ put code here eventually, I just haven't done it yet.'

```python
class My_Class:
number = 5
string = "Hello!"

def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]

# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y

# Alter class variable number for all instances
def increment_number(self):
# Increment the 'number' class variable by 1.
My_Class.number += 1

# This will compile and run without error, but has no current functionality.
def pending_functionality(self):
# Stubbing or placholding the body of this method.
pass
```

[class method]: https://stackoverflow.com/questions/17134653/difference-between-class-and-instance-methods
[dunder]: https://www.dataindependent.com/python/python-glossary/python-dunder/
[oop]: https://www.educative.io/blog/object-oriented-programming
[dot notation]: https://stackoverflow.com/questions/45179186/understanding-the-dot-notation-in-python
[shadowing]: https://oznetnerd.com/2017/07/17/python-shadowing/
9 changes: 8 additions & 1 deletion concepts/classes/introduction.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
#TODO: Add introduction for this concept.
# Introduction

`Classes` are definitions combining data (_otherwise known as `attributes`, `properties`,`data members`, `variables`, or `fields`_) with `functions` (_otherwise known as `methods`_).
Class definitions are used to create copies or `instances` of the `class`, commonly known as `objects`.
Objects can represent real world entities (_such as Cars or Cats_) - or more abstract concepts (_such as integers, vehicles, or mammals_).
Each object is unique in computer memory and represents some part of an overall model.
Classes and Objects can be found in several programming paradigms, but are integral to [object oriented programming][oop] (OOP), in which programs are made up of objects that interact with one another.

[oop]:https://www.educative.io/blog/object-oriented-programming
40 changes: 32 additions & 8 deletions concepts/classes/links.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
[
{
"url": "http://example.com/",
"description": "TODO: add new link (above) and write a short description here of the resource."
"url": "https://docs.python.org/3/tutorial/classes.html",
"description": "The official Python Classes tutorial."
},
{
"url": "http://example.com/",
"description": "TODO: add new link (above) and write a short description here of the resource."
"url": "https://pybit.es/articles/when-classes/",
"description": "A handy guide as to when to use Classes, and when not to."
},
{
"url": "http://example.com/",
"description": "TODO: add new link (above) and write a short description here of the resource."
"url": "https://realpython.com/python3-object-oriented-programming/",
"description": "Another overview of what Classes are and how to apply them in Python."
},
{
"url": "http://example.com/",
"description": "TODO: add new link (above) and write a short description here of the resource."
"url": "https://www.pythonmorsels.com/topics/classes/",
"description": "Python Morsels Rundown on Classes."
},
{
"url": "https://dbader.org/blog/6-things-youre-missing-out-on-by-never-using-classes-in-your-python-code",
"description": "6 Things Youre Missing out on by never using Classes."
},
{
"url": "http://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html",
"description": "The History of Python: The Inside Story on New-Style Classes."
},
{
"url": "https://realpython.com/instance-class-and-static-methods-demystified/",
"description": "Pythons Instance, Class, and Static Methodes Demystified."
},
{
"url": "https://stackabuse.com/pythons-classmethod-and-staticmethod-explained/",
"description": "Pythons Classmethod and Staticmethod Explained."
},
{
"url": "https://www.digitalocean.com/community/tutorials/how-to-construct-classes-and-define-objects-in-python-3",
"description": "An even gentler introduction to Classes and Objects from Digital Ocean."
},
{
"url": "https://www.digitalocean.com/community/tutorials/understanding-class-and-instance-variables-in-python-3",
"description": "An even gentler introduction to Instance and Class Variables from Digital Ocean."
}
]
Loading