python way to make integer class with additional data - python

Good day!
I'm think about class in python to store a map tiles inside, such as
map = [[WorldTile() for _ in range(10)] for _ in range(10)]
i create class
class WorldTile:
def __init__(self, val):
self.resource = val
self.objects = dict()
def __repr__(self):
return self.resource
def __str__(self):
return '%s' % (str(self.resource))
def __cmp__(self, other):
return cmp(self.resource, other)
def __add__(self, other):
self.resource += other
return self.resource
def __sub__(self, other):
self.resource -= other
return self.resource
but something going wrong.
i'l try
x = WorldTile.WorldTile(7)
print type(x), id(x), x
print x > 2, x < 5, x > 0
#x += 5
print type(x), id(x), x
print x, str(x), type(x)
print x.objects
they work fine, but if i'l uncomment line x += 5 x becoming an <type 'int'>
totally, i'm want to have class, with i can work as integer ( x = x +-*\ y etc ), but also can access additional fields if necessary ( x.objects )
i think i need override assignemet method, but that not possible in python. Any other way for me?

You could override __iadd__ for +=.
However, your current __add__ is broken. You could fix it by making it return a (new) instance of WorldTile rather than an int:
def __add__(self, other):
return WorldTile(self.resource + other)
This will work for both + and += (handling self.objects is left as an exercise for the reader).

Related

Not iterable object in python

I am trying to write a function that returns the variables contained in a class of type Rule. I need to iterate through it and get all variables and store them in a set.
class Rule:
# head is a function
# body is a *list* of functions
def __init__(self, head, body):
self.head = head
self.body = body
def __str__(self):
return str(self.head) + ' :- ' + str(self.body)
def __eq__(self, other):
if not isinstance(other, Rule):
return NotImplemented
return self.head == other.head and self.body == other.body
def __hash__(self):
return hash(self.head) + hash(self.body)
class RuleBody:
def __init__(self, terms):
assert isinstance(terms, list)
self.terms = terms
def separator(self):
return ','
def __str__(self):
return '(' + (self.separator() + ' ').join(
list(map(str, self.terms))) + ')'
def __eq__(self, other):
if not isinstance(other, RuleBody):
return NotImplemented
return self.terms == other.terms
def __hash__(self):
return hash(self.terms)
My function is the following:
def variables_of_clause (self, c : Rule) -> set :
returnSet = set()
l = getattr(c, 'body')
for o in l:
returnSet.add(o)
Testing function
# The variables in a Prolog rule p (X, Y, a) :- q (a, b, a) is [X; Y]
def test_variables_of_clause (self):
c = Rule (Function ("p", [Variable("X"), Variable("Y"), Atom("a")]),
RuleBody ([Function ("q", [Atom("a"), Atom("b"), Atom("a")])]))
#assert
(self.variables_of_clause(c) == set([Variable("X"), Variable("Y")]))
I keep getting an error that says: TypeError: 'RuleBody' is not iterable.
RuleBody.terms is a list, not RuleBody, you can iterate over RuleBody.terms instead, however, you can make your RuleBody class iterable (by basically making it return RuleBody.terms's elements), using the __iter__ method:
class RuleBody:
... # everything
...
def __iter__(self):
return iter(self.terms)

How to perform value check inside class

So the task is to make a universal Vector class to perform add method whatever(str or int) the x,y values are.
So here is the code that i've tried to execute just to check if try,except somehow works inside a class
class Vector():
def __init__(self,x,y):
self.x = x
self.y = y
def __valuecheck__(self):
try:
self.x + "a"
except TypeError:
return str(self.x)
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return "Vector({},{})".format(self.x,self.y)
a = Vector(1,"a")
b = Vector("a",2)
c = a.__add__(b)
print(c)
The expected output is
Vector(1a,a2)
I've tried different variants, defining classic function e.g. def valuecheck(), as well tried adding try,except to add and init method, but none seem to work. Need your help guys, any tip is very appreciated!
Cheers!
I think I have found the answer.
class Vector():
def __init__(self,x,y):
self.x = x
self.y = y
def __valuecheck__(self):
try:
self.x + "a"
except TypeError:
return str(self.x)
def __repr__(self):
return "Vector({},{})".format(self.x,self.y)
def __add__(self, other):
mvbh = str(self.x), str(self.y) # My Vector Before Hand
myVector = ''.join(mvbh)
ovbh = str(other.x), str(other.y) # Other Vector Before Hand
otherVector = ''.join(ovbh)
final = "Vector({}, {})".format(myVector, otherVector) # Change this to create a new vector
print(final)
a = Vector(1,"a")
b = Vector("a",2)
a.__add__(b)
class Vector():
def __init__(self,x,y):
self.x = x
self.y = y
def __valuecheck__(self):
try:
self.x + "a"
except TypeError:
return str(self.x)
def __add__(self, other):
return Vector(str(self.x) + str(other.x), str(self.y) + str(other.y))
def __repr__(self):
return "Vector({},{})".format(self.x,self.y)
a = Vector(1,"a")
b = Vector("a",2)
c = a.__add__(b)
print(c)

Add non-lamda function to self of Python class

Adding lambda expression to self of a Python class is easy:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = lambda x: x
else:
self.eval = lambda x: x**2
return
def compute(self, y):
return self.eval(y)
In my case, self.eval is somewhat more complex such that it doesn't fit into a one-line lambda. I need def. How can I assign self.eval with a defined function though?
For performance reasons, I would like to not store self.x = x and not move the if into compute.
You can define a function anywhere:
class Foo(object):
def __init__(self, x):
if x > 0:
def eval(y):
return y
else:
def eval(y):
return y**2
self.eval = eval
def compute(self, y):
return self.eval(y)
Python functions are first class objects. You can assign any function to a variable:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = self.method1
else:
self.eval = self.method2
def method1(self, x):
return x
def method2(self, x):
return x * x
def compute(self, y):
return self.eval(y)
f1 = Foo(1)
print(f1.compute(10)) # 10 (method1)
f2 = Foo(-1)
print(f2.compute(10)) # 100 (method2)
At least in Python 3 it is trivial to add a method to an existing class. Just look at the following code:
>>> class A:
val = 2 # declare a class variable (will be the default value
>>> def func(self, x): # declare a function that will be added as a method
return self.val * x
>>> A.compute = func # add the compute method to class A
>>> a = A() # create an instance
>>> a.val # control the value of the member
2
>>> a.compute(3) # use the added method
6
>>> a.val=3 # change the value of the variable for the specific instance
>>> a.compute(4) # control that the new variable value is used
12

Reinserting set element creates holes

Generally if we need to insert an object to a set, we should make it hash-able (by implementing the hash function) and comparable (and implementing a compare function). Set does not provide a mechanism to access its elements and thus cannot be mutated directly though can easily be circumvented.
A general pattern to mutate a set item would be as follows
i = next(iter(x))
update(i)
x.add(i)
This generally seem to work for almost all cases except one when unexpected holes are created.
class Foo(object):
def __init__(self, x):
self.x = x
self.count = 0
def __hash__(self):
return hash((self.x, ))
def __iadd__(self, n):
self.count += n
def __eq__(self, other):
return self.x == other.x
>>> x = {Foo(1)}
>>> i = next(iter(x))
>>> i+=1
>>> x.add(i)
>>> x
set([None, <__main__.Foo object at 0x0279D8B0>])
My guess is mutating a set element while updating may cause unexpected behavior but invoking next would just fetch the value (a copy I guess) that should not be an issue.
Any idea what the problem may be?
Per the docs,
[__iadd__] should attempt to do the operation in-place (modifying self) and
return the result (which could be, but does not have to be, self)
Therefore,
def __iadd__(self, n):
self.count += n
return self
Then,
class Foo(object):
def __init__(self, x):
self.x = x
self.count = 0
def __hash__(self):
return hash((self.x, ))
def __iadd__(self, n):
self.count += n
return self
def __eq__(self, other):
return self.x == other.x
x = {Foo(1)}
i = next(iter(x))
i+=1
x.add(i)
print(x)
yields
set([<__main__.Foo object at 0x7f19ae8b9f10>])
You probably want to return self in iadd method.

What is the "metaclass" way to do this?

I want to write a program that accepts as input a number p and produces as output a type-constructor for a number that obeys integer arithmetic modulo p.
So far I have
def IntegersModP(p):
N = type('IntegersMod%d' % p, (), {})
def __init__(self, x): self.val = x % p
def __add__(a, b): return N(a.val + b.val)
... (more functions) ...
attrs = {'__init__': __init__, '__add__': __add__, ... }
for name, f in attrs.items():
setattr(N, name, f)
return N
This works fine, but I'd like to know what the Pythonic way to do this is, which I understand would use metaclasses.
Like this:
def IntegerModP(p): # class factory function
class IntegerModP(object):
def __init__(self, x):
self.val = x % p
def __add__(a, b):
return IntegerModP(a.val + b.val)
def __str__(self):
return str(self.val)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.val)
IntegerModP.__name__ = 'IntegerMod%s' % p # rename created class
return IntegerModP
IntegerMod4 = IntegerModP(4)
i = IntegerMod4(3)
j = IntegerMod4(2)
print i + j # 1
print repr(i + j) # IntegerMod4(1)
Metaclasses are for when your class needs to behave differently from a normal class or when you want to alter the behavior of the class statement. Neither of those apply here, so there's really no need to use a metaclass. In fact, you could just have one ModularInteger class with instances that record their value and modulus, but assuming you don't want to do that, it's still easy to do this with an ordinary class statement:
def integers_mod_p(p):
class IntegerModP(object):
def __init__(self, n):
self.n = n % IntegerModP.p
def typecheck(self, other):
try:
if self.p != other.p:
raise TypeError
except AttributeError:
raise TypeError
def __add__(self, other):
self.typecheck(other)
return IntegerModP(self.n + other.n)
def __sub__(self, other):
...
IntegerModP.p = p
IntegerModP.__name__ = 'IntegerMod{}'.format(p)
return IntegerModP

Categories