I'm trying to create a mutable string object by just subclassing str (Unlike the answer to this other question).
Here's my code so far:
class mstr(str):
def __new__(self, s):
self.s = list(s)
return str.__new__(self, s)
def __getitem__(self, index):
return self.s[index]
def __setitem__(self, index, value):
self.s[index] = value
def __eq__(self, other):
return ''.join(self.s) == other
def __ne__(self, other):
return ''.join(self.s) != other
def __lt__(self, other):
return len(self.s) < len(other)
def __gt__(self, other):
return len(self.s) > len(other)
def __le__(self, other):
return len(self.s) <= len(other)
def __ge__(self, other):
return len(self.s) >= len(other)
def __add__(self, other):
return ''.join(self.s) + other
def __mul__(self, other):
return ''.join(self.s) * other
def __hash__(self):
return hash(''.join(self.s))
def __str__(self):
return ''.join(self.s)
def main():
s = mstr("Hello ")
s[5] = " World!"
print(s)
if __name__ == '__main__':
main()
By just outputting this example, it's easy to be fooled by the __ str __ return value:
Hello World!
It's also easy to be fooled by the return value of __ add __ :
print(s + " Bloody madness!")
Output:
Hello World! Bloody madness!
But the immutable truth is revealed once we pass the mstr itself by the other argument of __ add __, as an example:
print(s + s)
Output:
Hello World!Hello
Removing all the extra methods:
class mstr(str):
def __new__(self, s):
self.s = list(s)
return str.__new__(self, s)
def __setitem__(self, index, value):
self.s[index] = value
self = ''.join(self.s) # Foolish attepmt.
Output of print(s) is just "Hello ".
So, how can I change the string object inside the string object? I mean, WHERE is the string actual and physical content stored in str or object or whatever? Wherever that is, I want to assign there.
It's in here:
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1]; // This part. (Not actually one char.)
/* ... */
} PyStringObject;
Unless you want to screw with the memory directly with ctypes or something, you can't get at it. If you do screw with it, weird things will break, because the assumption that that data is immutable isn't waived for string subclasses.
Related
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)
My code works perfectly except the last part. I want to recreate the object with repr function but it clearly doesn't work. I tried everything here and on the web but i'm still so confuse. Is there any way to do it and if so what is the syntax ?
class Modulo(object):
def __init__(self, grondtal, waarde = 0):
self.grondtal = grondtal
self.waarde = waarde % grondtal
def __call__(self, m):
return Modulo(self.grondtal, m)
def __add__(self, other):
return Modulo(self.grondtal, self.waarde + other.waarde)
def __sub__(self, other):
return Modulo(self.grondtal, self.waarde - other.waarde)
def __mul__(self, other):
return Modulo(self.grondtal, self.waarde * other.waarde)
def __eq__(self, other):
return self.waarde == other.waarde and self.grondtal == other.grondtal
def __ne__(self, other):
return not self.__eq__(other)
def __str__(self):
return '[%s %% %s]' % (str(self.grondtal), str(self.waarde))
def __repr__(self):
return '%s' %Modulo(self.grondtal, self.waarde)
You probably want this:
def __repr__(self):
return "Modulo(%d,%d)" % (self.grondtal, self.waarde)
Or, a little bit more generic:
def __repr__(self):
return "%s(%d,%d)" % (self.__class__.__name__, self.grondtal, self.waarde)
For example:
>>> m = Modulo(3,2)
>>> repr(m)
'Modulo(3,2)'
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
I am relatively new to python. I have a class Time, and I want to check if a set of Time objects contains another set of Time objects.
a = {Time(10,10)}
print {Time(10,10)}.issubset(a) >> "result is False"
for i in a:
print i in a >> "result is True"
And in the class, I have implemented these methods
def to_min(self):
return self.h * 60 + self.m
def __cmp__(self, other):
if isinstance(other, Time):
if self.to_min() > other.to_min():
return 1
else:
if self.to_min() == other.to_min():
return 0
else:
return -1
def __eq__(self, other):
if isinstance(other, Time):
if self.to_min() == other.to_min():
return True
else:
return False
def __gt__(self, other):
return self.to_min() > other.to_min()
def __ge__(self, other):
return self.to_min() >= other.to_min()
def __lt__(self, other):
return self.to_min() < other.to_min()
def __le__(self, other):
return self.to_min() <= other.to_min()
def __str__ (self):
return str(self.h) + ":" + str(self.m)
def __hash__(self):
return self.to_min()
I wonder what else should I implement or change to make the following lines of code to print to true. I have read the=at there is a contains method. But I am not going check if one Time object contains other components.
a = {Time(10,10)}
print {Time(10,10)}.issubset(a) >>
I replaced this
self.to_min() == other.to_min()
with this
self.__hash__() == other.__hash__()
And also edited the eq to return boollean, rather than integer
Now it works, I still wonders.
Anyway, this is full code if anyone is interested:
class Time(object):
'''
classdocs
'''
def __init__(self, h, m):
if isinstance(h, int) and isinstance(h, int):
self.m = m
self.h = h
if(self.m >= 60):
self.h += self.m // 60
self.m %= 60
def __add__(self, m):
return Time(self.h, self.m + m)
def to_min(self):
return self.h * 60 + self.m
def __cmp__(self, other):
print "__cmp__"
if isinstance(other, Time):
if self.to_min() > other.to_min():
return 1
else:
if self.__hash__() == other.__hash__():
return 0
else:
return -1
def __eq__(self, other):
print "__eq__"
if isinstance(other, Time):
if self.to_min() == other.to_min():
return True
else:
return False
def __gt__(self, other):
return self.to_min() > other.to_min()
def __ge__(self, other):
return self.to_min() >= other.to_min()
def __lt__(self, other):
return self.to_min() < other.to_min()
def __le__(self, other):
return self.to_min() <= other.to_min()
def __str__ (self):
return str(self.h) + ":" + str(self.m)
def __hash__(self):
print "__hash__"
return self.to_min()
# return 1
def __ne__(self, other):
print "__ne__"
return not self == other
# a = set([Time(10,10), Time(10,20)])
# b = set([Time(10,10)])
# print a in set([b])
a = {Time(10,10)}
print {Time(10,10)}.issubset(a)
# print b.issubset( a)
# for i in a:
# print i in a
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.