Created
December 27, 2018 22:06
-
-
Save KCarretto/00301d983822db105c088358ab592f97 to your computer and use it in GitHub Desktop.
Python Typing Code Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Defines concrete types of Person. | |
""" | |
from typing import ClassVar, List, Optional | |
from person import TPerson, Person # Update this to reflect whatever directory structure. | |
class Friend(Person): | |
""" | |
Represents a Person that is a friend. | |
""" | |
happy_level: int | |
# All friends agree upon the top enemy, and all friends become enemies with them. | |
public_enemy_num_one: ClassVar[Optional["Enemy"]] | |
_friends: List["Friend"] # Only friends can be friends | |
_enemies: List["Enemy"] # Only enemies can be enemies | |
def __init__(self, happy_level: int, name: str): | |
super().__init__(name) | |
self.happy_level = happy_level | |
self._friends = [] | |
self._enemies = [] | |
@property | |
def friends(self) -> List["Friend"]: | |
""" | |
Returns: | |
List[Friend]: A list of this persons friends. | |
""" | |
return self._friends | |
@property | |
def enemies(self) -> List["Enemy"]: | |
""" | |
Returns: | |
List[Enemy]: A list of this persons enemies. | |
""" | |
if Friend.public_enemy_num_one not in self._enemies: | |
self._enemies.append(Friend.public_enemy_num_one) | |
return self._enemies | |
def make_enemy(self, enemy: "Enemy") -> None: | |
""" | |
Args: | |
enemy (Enemy): A new foe. | |
""" | |
try: | |
self._friends.remove(enemy) | |
except ValueError: | |
pass | |
self._enemies.append(enemy) | |
def make_friend(self, friend: "Friend") -> None: | |
""" | |
Args: | |
friend (Friend): A new mate. | |
""" | |
if friend is Friend.public_enemy_num_one: | |
raise Exception("No one can make friends with... THEM.") | |
try: | |
self._enemies.remove(friend) | |
except ValueError: | |
pass | |
self._friends.append(friend) | |
def celebrate(self, attendees: List[TPerson]) -> int: | |
""" | |
Celebrate a persons birthday. | |
Args: | |
attendees (List[Person]): List of people at the celebration. | |
Returns: | |
int: Net happiness generated by the event. | |
""" | |
if Friend.public_enemy_num_one in attendees: | |
return -1000000 | |
net_happy = 0 | |
for guest in attendees: | |
if guest in self.enemies: | |
pass | |
return net_happy | |
class Enemy(Person): | |
""" | |
Represents a person who cannot have friends, and is never happy. | |
""" | |
_targets: List[TPerson] | |
_evil_level: int | |
def __init__(self, evil_level: int, name: str): | |
super().__init__(name) | |
self._evil_level = evil_level | |
self._targets = [] | |
@property | |
def evil_level(self) -> int: | |
""" | |
Returns: | |
int: The evil level of this foe. | |
""" | |
return self._evil_level | |
@property | |
def targets(self, requester: TPerson) -> List["Friend"]: | |
""" | |
Don't show the requester if they are a target. | |
Returns: | |
List[Friend]: A list of targets. | |
""" | |
return list(filter(lambda x: x is not requester, self._targets)) | |
def frustrate(self, amount: int) -> int: | |
""" | |
Frustrated enemies become more evil. | |
Args: | |
amount (int): The amount of frustration. | |
Returns: | |
int: The total increase in evil due to this outrage. | |
""" | |
amount = abs(amount) * 2 # Make it double. | |
self._evil_level += amount | |
return amount | |
def celebrate(self, attendees: List[TPerson]) -> int: | |
""" | |
Celebrations make enemies frustrated. The more frustrated, the more evil. The more evil, the | |
more frustrated. | |
Args: | |
attendees (List[TPerson]): The list of scum that attended the "celebration." | |
Returns: | |
int: The net happiness generated. | |
""" | |
net_happy = 0 | |
net_happy -= self.frustrate(self.evil_level) | |
net_happy -= self.frustrate(len(attendees)) | |
return net_happy |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Defines the Person base class and related methods. | |
""" | |
from abc import ABC, abstractmethod | |
from typing import List, Type, TypeVar | |
# We create a new TypeVar bound to Person, which is used for generic functions that accept an | |
# instance of a concrete subclass of Person as a parameter. | |
TPerson = TypeVar("TPerson", bound="Person") | |
class Person(ABC): | |
""" | |
A person interface. | |
""" | |
name: str | |
_age: int | |
# In __init__ we do not need to type self or provide a return type. | |
def __init__(self, name: str, initial_age: int): | |
self.name = name | |
self._age = initial_age | |
@classmethod | |
def create(cls: Type[TPerson], *args, **kwargs) -> TPerson: | |
""" | |
People factory method :o | |
We require *args and **kwargs are passed here because we are making a generic factory at the | |
top level class. This will obfuscate the required parameters for subclasses of Person. | |
Implementing this might not be a good idea in most cases, but it is being used to | |
demonstrate functionality of TypeVar and TPerson. | |
Args: | |
cls (Type[TPerson]): We choose to provide a type to cls in this method because we | |
acknowledge that this method may be called from subclasses of Person. This allows | |
the type checker to infer the return value of this factory based on the class this | |
method is called from. | |
*args: Any positional arguments used for construction. | |
**kwargs: Any keyword arguments used for construction. | |
Returns: | |
TPerson: An instance of the class this method was called from. Friend.create will return | |
an instance of friend, instead of an (invalid) instance of Person. | |
""" | |
return cls(*args, **kwargs) | |
@property | |
def age(self) -> int: | |
""" | |
Returns: | |
int: The current age of this person. | |
""" | |
return self._age | |
def birthday(self, attendees: List[Person]) -> bool: | |
""" | |
Increment a persons age as they celebrate. | |
Returns: | |
bool: True if the person was happy with their celebration. | |
""" | |
self._age += 1 | |
was_happy = self.celebrate(attendees) > 0 | |
return was_happy | |
@abstractmethod | |
def celebrate(self, attendees: List[Person]) -> int: | |
""" | |
Celebrate a persons birthday. | |
Args: | |
attendees (List[Person]): List of people at the celebration. | |
Returns: | |
int: Net happiness generated by the event. | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment