Skip to content

Instantly share code, notes, and snippets.

@KCarretto
Created December 27, 2018 22:06
Show Gist options
  • Save KCarretto/00301d983822db105c088358ab592f97 to your computer and use it in GitHub Desktop.
Save KCarretto/00301d983822db105c088358ab592f97 to your computer and use it in GitHub Desktop.
Python Typing Code Example
"""
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
"""
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