In [5]:
from sys import version_info
print(version_info)
In [41]:
from math import sqrt
EUCLIDEAN, STREETS = object(), object()
ARENA_TYPE = STREETS
# in python3, you don't need to derive from object, since there are no old-style classes
class Mob:
"""
Any mobile object in the game.
"""
# not sure why this was breaking...
# def __new__(cls, *args, **kwargs):
# # runs before instantiation
# return object.__new__(cls, *args, **kwargs)
def __init__(self, x, y):
self._x, self._y = x, y
def __repr__(self):
return '{0.__name__}({1.x}, {1.y})'.format(type(self), self)
def __str__(self):
return repr(self)
def move(self):
pass
@property
def x(self):
return self._x
@property
def y(self):
return self._y
@x.setter
def x(self, value):
if value < 0:
raise ValueError("can't move outside of the arena")
self._x = value
@y.setter
def y(self, value):
if value < 0:
raise ValueError("can't move outside of the arena")
self._y = value
if ARENA_TYPE == EUCLIDEAN:
@staticmethod
def distance(mob1, mob2):
return sqrt((mob1.x + mob2.x)**2 + (mob1.y + mob2.y)**2)
else:
@staticmethod
def distance(mob1, mob2):
return abs(mob1.x - mob2.x) + abs(mob1.y - mob2.y)
mob1 = Mob(0, 0)
mob2 = Mob(12, 3)
Mob.distance(mob1, mob2)
Out[41]:
Instance methods are created on the fly; this does not apply to class methods or properties.
In [47]:
mob3 = Mob(1, 1)
assert Mob is Mob
assert mob3 is mob3
print(list(map(id, [mob3.x, mob3.x])))
print(list(map(id, [mob3.move, mob3.move])))
Mob.__dict__
Out[47]:
James likes dis
In [48]:
from dis import dis
def create_mob():
return Mob(1,1)
dis(create_mob)
If you want to find the hooks for function calls in the CPython code, just grep for CALL_FUNCTION now.
Here's where metaclasses come in... (somehow)
In [55]:
from dis import dis
def create_monster():
class Monster(Mob):
def __init__(self, hp, *args, **kwargs):
self.hp = hp
Mob.__init__(*args, **kwargs)
dis(create_monster)
Looking at the CPython code, you'll see that you only use the first metaclass you find in the inheritance chain. Or is it only the metaclass of the first class (as in, the class itself)?
You can create your own object sytem in python...but probably don't.
What would you use metaclasses for?
In [71]:
class Monster(Mob):
def __init__(self, hp, *args, **kwargs):
self._hp = hp
Mob.ty__init__(*args, **kwargs)
@property
def hp(self):
return self._hp
class Boss(Monster):
def __init__(self, prize, *args, **kwargs):
self.prize = prize
Monster.__init__(*arg, **kwargs)
# you can ensure that classes you inherit from have certain attributes
assert hasattr(Monster, 'hp')
assert issubclass(Monster, Mob)
# metaclasses allow you contrain derived classes at the parent class level
# --> we don't want subclasses of Monster to be able to move outside the arena
class metaclass(type):
def __init__(self, name, bases, body):
print(self, name, bases, body)
# place contraints here...
if name == 'Derived':
raise ValueError('no!')
return type.__init__(self, name, bases, body)
class Base(metaclass=metaclass):
pass
class Derived(Base):
pass