'__neg__' implementation. i am learning magic methods in python - python

this is a polynomial class
class Polynomial(object):
def __init__(self, polynomial):
self.p = tuple(polynomial)
def get_polynomial(self):
return self.p
def __neg__(self):
return tuple([tuple([-i[j] if j==0 else i[j] for j in range(len(i))])for i in self.p])
def __add__(self, other):
pass
def __sub__(self, other):
pass
def __mul__(self, other):
pass
def __call__(self, x):
pass
def simplify(self):
pass
def __str__(self):
return 'something'
if i use the below code, i am getting error that -p has syntax error. is there a different way to override the magic methods ?
p = Polynomial([(2, 1), (1, 0)])
print p
print p.get_polynomial()
q = ‑p; q.get_polynomial()
i am getting syntax error at q = -p

The problem is that your __neg__ method returns a tuple, instead of an instance of your Polynomial class.
Thus when you try calling get_polynomial it will happen on a tuple, resulting in an error stating that tuple doesn't have a method called get_polynomial.
AttributeError: 'tuple' object has no attribute 'get_polynomial'
As such your __neg__ method must return an instance of your Polynomial class, like this:
def __neg__(self):
return Polynomial([tuple([-i[j] if j == 0 else i[j] for j in range(len(i))]) for i in self.p])

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)

python; how to pass one argument through multiple methods in a class

I am learning about class structure in python. Would like to know if it's possible to pass one argument through more than one method.
class Example(object):
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(y):
sq = Example.square(y)
cu = Example.cube(sq)
return cu
two = Example(2)
print(two.squarethencube())
Error is on line 10; AttributeError: 'int' object has no attribute 'x'
The goal is to use the 'squarethencube' method to pass '2' to square(), which is 4. Then pass '4' to cube(). The desired output is '64'. Obviously, you can write a function to do the math in a very simple way; the question here is how to use multiple methods.
I understand the error in that .x is getting assigned as an attribute onto the output of cube(sq). I was getting the same error, but on line 7, before I changed the argument to y (from self.x).
I've found some similar answers here but I need a simpler explanation.
Currently, square and cube are methods bound to the class; however, you are accessing them in squarethencube by class name, but they are methods, and thus rely on a reference to the class from an instance. Therefore, you can either create two new instances of the class or use classmethod:
Option1:
class Example(object):
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(self, y):
sq = Example(y).square()
cu = Example(y).cube()
return cu
Option 2: use a classmethod:
class Example(object):
def __init__(self, x):
self.x = x
#classmethod
def square(cls, x):
return x**2
#classmethod
def cube(cls, x):
return x**3
def squarethencube(self, y):
sq = Example.square(y)
cu = Example.cube(sq)
return cu
class Example:
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(self):
return (self.x**2)**3
two = Example(2)
print(two.squarethencube())

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

Comparison of hashable objects

I have a tuple of python objects, from which I need a list of objects with no duplicates, using set() (this check for duplicate objects is to be done on an attribute.). This code will give a simple illustration:
class test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return self.t
l = (test(1), test(2), test(-1), test(1), test(3), test(2))
print l
print set(l)
However, it did not work. I can do it on an iteration over l, but any idea why set() is not working? Here is the official documentation.
From the documentation you linked to:
The set classes are implemented using dictionaries. Accordingly, the
requirements for set elements are the same as those for dictionary
keys; namely, that the element defines both __eq__() and __hash__().
To be more specific, if a == b then your implementation must be such that hash(a) == hash(b). The reverse is not required.
Also, you should probably call hash in __hash__ to handle long integers
class Test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return hash(self.t)
def __eq__(self, other):
return isinstance(other, Test) and self.t == other.t
Small nit picks:
Your implementation of __eq__ doesn't give the other object a chance to run its own __eq__. The class must also consider its members as immutable as the hash must stay constant. You don't want to break your dicts, do you?
class Test:
def __init__(self, t):
self._t = t
#property
def t(self):
return self._t
def __repr__(self):
return repr(self._t)
def __hash__(self):
return hash(self._t)
def __eq__(self, other):
if not isinstance(other, Test):
return NotImplemented # don't know how to handle `other`
return self.t == other.t

Decorating arithmetic operators | should I be using a metaclass?

I'd like to implement an object, that bounds values within a given range after arithmetic operations have been applied to it. The code below works fine, but I'm pointlessly rewriting the methods. Surely there's a more elegant way of doing this. Is a metaclass the way to go?
def check_range(_operator):
def decorator1(instance,_val):
value = _operator(instance,_val)
if value > instance._upperbound:
value = instance._upperbound
if value < instance._lowerbound:
value = instance._lowerbound
instance.value = value
return Range(value, instance._lowerbound, instance._upperbound)
return decorator1
class Range(object):
'''
however you add, multiply or divide, it will always stay within boundaries
'''
def __init__(self, value, lowerbound, upperbound):
'''
#param lowerbound:
#param upperbound:
'''
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def init(self):
'''
set a random value within bounds
'''
self.value = random.uniform(self._lowerbound, self._upperbound)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "<Range: %s>" % (self.value)
#check_range
def __mul__(self, other):
return self.value * other
#check_range
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self.div(other)
#check_range
def __add__(self, other):
return self.value + other
#check_range
def __sub__(self, other):
return self.value - other
It is possible to use a metaclass to apply a decorator to a set of function names, but I don't think that this is the way to go in your case. Applying the decorator in the class body on a function-by-function basis as you've done, with the #decorator syntax, I think is a very good option. (I think you've got a bug in your decorator, BTW: you probably do not want to set instance.value to anything; arithmetic operators usually don't mutate their operands).
Another approach I might use in your situation, kind of avoiding decorators all together, is to do something like this:
import operator
class Range(object):
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def _from_value(self, val):
val = max(min(val, self._upperbound), self._lowerbound)
# NOTE: it's nice to use type(self) instead of writing the class
# name explicitly; it then continues to work if you change the
# class name, or use a subclass
return type(self)(val, rng._lowerbound, rng._upperbound)
def _make_binary_method(fn):
# this is NOT a method, just a helper function that is used
# while the class body is being evaluated
def bin_op(self, other):
return self._from_value(fn(self.value, other))
return bin_op
__mul__ = _make_binary_method(operator.mul)
__div__ = _make_binary_method(operator.truediv)
__truediv__ = __div__
__add__ = _make_binary_method(operator.add)
__sub__ = _make_binary_method(operator.sub)
rng = Range(7, 0, 10)
print rng + 5
print rng * 50
print rng - 10
print rng / 100
printing
<Range: 10>
<Range: 10>
<Range: 0>
<Range: 0.07>
I suggest that you do NOT use a metaclass in this circumstance, but here is one way you could. Metaclasses are a useful tool, and if you're interested, it's nice to understand how to use them for when you really need them.
def check_range(fn):
def wrapper(self, other):
value = fn(self, other)
value = max(min(value, self._upperbound), self._lowerbound)
return type(self)(value, self._lowerbound, self._upperbound)
return wrapper
class ApplyDecoratorsType(type):
def __init__(cls, name, bases, attrs):
for decorator, names in attrs.get('_auto_decorate', ()):
for name in names:
fn = attrs.get(name, None)
if fn is not None:
setattr(cls, name, decorator(fn))
class Range(object):
__metaclass__ = ApplyDecoratorsType
_auto_decorate = (
(check_range,
'__mul__ __div__ __truediv__ __add__ __sub__'.split()),
)
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def __mul__(self, other):
return self.value * other
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self / other
def __add__(self, other):
return self.value + other
def __sub__(self, other):
return self.value - other
As it is wisely said about metaclasses: if you wonder wether you need them, then you don't.
I don't fully understand your problem, but I would create a BoundedValue class, and us only instances of said class into the class you are proposing.
class BoundedValue(object):
default_lower = 0
default_upper = 1
def __init__(self, upper=None, lower=None):
self.upper = upper or BoundedValue.default_upper
self.lower = lower or BoundedValue.default_lower
#property
def val(self):
return self._val
#val.setter
def val(self, value):
assert self.lower <= value <= self.upper
self._val = value
v = BoundedValue()
v.val = 0.5 # Correctly assigns the value 0.5
print v.val # prints 0.5
v.val = 10 # Throws assertion error
Of course you could (and should) change the assertion for the actual behavior you are looking for; also you can change the constructor to include the initialization value. I chose to make it an assignment post-construction via the property val.
Once you have this object, you can create your classes and use BoundedValue instances, instead of floats or ints.

Categories