For example, when I have such a Node class defined.
class Node:
def __init__(self, val=None, next=None):
self.val = val
self.next = next
def __bool__(self):
return self.val is not None
When I initialize it with empty arguments, like below. Is there a way to self-define method to say a is None?
a = Node()
a is None # False, but can it be true if I want?
While you cannot override the is comparison, you can at least override the equality operator if you want to quickly check up whether a specific parameter (or condition) within your class should yield True on comparison, e.g.:
class Node:
def __init__(self, val=None, next=None):
self.val = val
self.next = next
def __eq__(self, obj):
return obj == self.val
n = Node()
print(n == None) # True
n = Node(5)
print(n == None) # False
No, but...
You cannot override the is, and, or or operators.
Defining __bool__ allows you to write statements like
class Node:
def __init__(self, val):
self.val = val
def __bool__(self):
return self.val is not None # <--- added "return"
for val in (0, 1, True, None):
n = Node(val)
# These three are equivalent
if n:
assert n.__bool__()
assert n.val is not None
# These three are equivalent
else:
assert not n.__bool__()
assert n.val is None
https://docs.python.org/3/reference/datamodel.html#object.bool
This may not do exactly what you want but you could overwrite the __new__ class method so that, when the class constructor is called with no arguments, the None object is returned instead of an instance of Node.
I think this should work (my metaclass knowledge is spotty).
class Node:
def __new__(cls, val=None, next=None):
if val is None and next is None:
return None
return super().__init__(cls, val, next)
def __init__(self, val, next):
if self is None:
return
...
It is my duty to recommend that you not go down this route, however. Fiddling with __new__ is tricky and dangerous and is probably more trouble than it's worth.
How do you make class to iterate by its internal numpy array :
Just idea which does not work :
class ABC:
def __init__(self):
self.ary = np.zeros(50)
def __iter__(self): return np.nditer(self.ary)
def next(self): ...??..
Also how to make assignment work too :
abc = ABC()
abc[5] = 12
abc[7:9] 0
From documentation,
iterator.__next__():
Return the next item from the container. If there are no further items, raise the StopIteration exception. This method corresponds to the tp_iternext slot of the type structure for Python objects in the Python/C API.
For setting and getting values for container class, you need to implement __getitem__ and __setitem__.
For your sample code
class ABC():
def __init__(self):
self.ary = np.zeros(50)
self.index = self.ary.shape[0]
def __iter__(self):
return np.nditer(self.ary)
def next(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
def _check_indx(self, idx):
if abs(idx) >= self.ary.shape[0]:
raise IndexError(f"Invalid Index {idx} for array with shape {self.ary.shape}")
def __setitem__(self, idx, value):
self._check_indx(idx)
self.ary[idx] = value
def __getitem__(self, idx):
self._check_indx(idx)
return self.ary[idx]
In python, I have a class with a method that returns a generator:
class foo():
data = [1, 2, 3]
def mygen(self):
for d in self.data:
yield d
instance = foo()
print([i for i in instance.mygen()])
But I can't reverse this:
print([i for i in reversed(instance.mygen())])
TypeError: 'generator' object is not reversible
So I thought I could implement a class which returns a generator when calling __iter__, like this
class foo():
data = [1, 2, 3]
def mygen(self):
return _ReversibleIterator(self)
class _ReversibleIterator(object):
def __init__(self, obj):
self.obj = obj
def __iter__(self):
for d in obj.data:
yield d
def __reversed__(self):
for d in reversed(obj.data):
yield d
But I think this isn't quite the same, because the _ReversibleIterator class doesn't have a next() method.
So what is the pythonic way to create a class method that returns an iterator that can be reversed()?
(Obviously I'm just using [1,2,3] as an example. The real thing to iterate over is less trivially reversible)
According to the docs, reversed must have one of two things to work with: a __reversed__ method OR a __len__ and a __getitem__ method. If you think about it, this makes sense because most generators can't support reversed because they generate results on the fly: they don't know what the next, let alone the last element is going to be. However, if you know its length and have random-access to any index, it can be reversed.
class foo():
data = [1, 2, 3]
def mygen(self):
return _ReversibleIterator(self)
class _ReversibleIterator(object):
def __init__(self, obj):
self.obj = obj
self.index = 0
def __iter__(self):
self.index = 0
return self
def __reversed__(self):
return reversed(self.obj.data)
def __next__(self):
try:
el = self.obj.data[self.index]
except IndexError:
raise StopIteration
self.index += 1
return el
or
class _ReversibleIterator(object):
def __init__(self, obj):
self.obj = obj
self.index = 0
def __iter__(self):
self.index = 0
return self
def __len__(self):
return len(self.obj.data)
def __getitem__(self, i):
return self.obj.data[i]
def __next__(self):
try:
el = self[self.index]
except IndexError:
raise StopIteration
self.index += 1
return el
By the way, if you would like, you can replace for d in whatever: yield d with yield from whatever.
This is how I am defining my linkedList
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
I am trying to convert a string to a linkedList
stringTotal = "abc"
head = stringToListNode(stringTotal)
#this method should return a -> b -> c
def stringToListNode(stringTotal):
for i in stringTotal:
currentNode = ListNode(i)
How can I get the next letter of the string and make it the next node?
Try this:
def stringToListNode(stringTotal):
previousNode = None
first = None
for i in stringTotal:
currentNode = ListNode(i)
if first is None:
first = currentNode
if previousNode is not None:
previousNode.next = currentNode
previousNode = currentNode
return first
One nice way to do this might be to define a from_string classmethod on your ListNode class that will recursively build a linked list for you and return the head:
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
#classmethod
def from_string(cls, s):
if s:
n = cls(s[0])
n.next = ListNode.from_string(s[1:])
return n
n = ListNode.from_string('hello')
print(n.next.next.next.next.val)
>>> 'o'
You can create an insert method as an attribute of ListNode, that can be called on the next attribute should that latter already store a node of ListNode:
class ListNode(object):
def __init__(self, x=None):
self.val = x
self.next = None
def insert(self, val):
if self.val is None:
self.val = val
else:
getattr(self.next, 'insert', lambda x:setattr(self, 'next', ListNode(x)))(val)
def __str__(self):
return '{}, {}'.format(self.val, str(self.next) if self.next else '')
def __repr__(self):
return 'List(<{}>)'.format(str(self))
#classmethod
def insert_vals(cls, s):
l = cls()
for i in s:
l.insert(i)
return l
_list = ListNode.insert_vals('abc')
print(_list)
Output:
List(<a, b, c, >)
Note, however, that the operation accomplished in method insert can also be performed as a simple function, however, it is not as clean as an instance attribute:
class ListNode(object):
def __init__(self, x=None):
self.val = x
self.next = None
def __str__(self):
return '{}, {}'.format(self.val, str(self.next) if self.next else '')
def __repr__(self):
return 'List(<{}>)'.format(str(self))
def insert_val(_l:ListNode, value:str) -> None:
if _l.val is None:
_l.val = value
else:
if isinstance(_l.next, ListNode):
insert_val(_l.next, value)
else:
_l.next = ListNode(value)
_l = ListNode()
for i in 'abc':
insert_val(_l, i)
>>>_l
Output:
List(<a, b, c, >)
Let's say we have a class:
NOTE: this is a dummy class only.
class C(object):
def __init__(self):
self.a = -10
self.b = 5
self.c = 2
def modify(self, **kwargs):
for keyword in kwargs:
vars(self)[keyword] = kwargs[keyword]
return(self)
And we want to use this modify method to change values in our object:
myclass = C()
myclass = myclass.modify(a=10)
But when I want to change the value based on the original one, I have to write this:
myclass = C()
myclass = myclass.modify(a=myclass.a/10)
Or:
myclass = myclass.modify(a=abs(myclass.a))
My question is, is there a way, to create a global variable in a module, that I can import and use it as a placeholder for current value, so I can use this formula:
from globvars import current
myclass = C()
myclass = myclass.modify(
a=abs(current) % current ** 2,
b=current//2,
c=bool(current)
)
First I tried to a create a class, which will store the operation it is taking and a value, and modify() will look first for its variable as a keyword and then execute the function. Actually it is only working for simple situations like: current+10 or current**2.
But when I realised, I want to use this current for example with an hsba(current) (color converter) function, where current is pointing to an object stored in an other object, I just give up, I can't write this to every class I'm going to use..
Is there a solution for this? Maybe it's quite easy, I just can't see it :)
Thanks in advance for replies!
Here is a working solution. It is not complete and full of pretty bad design choices, but I hope it helps.
class Expr(object):
def __init__(self, op, left, right):
self.op = op
self.left = left
self.right = right
def __call__(self, current):
l = self._replace_current(self.left, current)
r = self._replace_current(self.right, current)
return self._do_operation(l, r)
def _replace_current(self, val, current):
if val == 'current':
return current
elif isinstance(val, Expr): # recurse
return val(current)
else:
return val
def _do_operation(self, l, r):
if self.op == '+':
return l + r
elif self.op == '*':
return l * r
elif self.op == '-':
return l - r
def __add__(self, other):
return self._left_op('+', other)
def __radd__(self, other):
return self._right_op('+', other)
def __mul__(self, other):
return self._left_op('*', other)
def __rmul__(self, other):
return self._right_op('*', other)
def __sub__(self, other):
return self._left_op('-', other)
def __rsub__(self, other):
return self._right_op('-', other)
def _left_op(self, op, other):
if isinstance(other, Current):
return Expr(op=op, left=self, right='current')
else:
return Expr(op=op, left=self, right=other)
def _right_op(self, op, other):
if isinstance(other, Current):
return Expr(op=op, left='current', right=self)
else:
return Expr(op=op, left=other, right=self)
class Current(Expr):
def __init__(self):
super(Current, self).__init__(None, None, None)
def __call__(self, current):
return current
def _left_op(self, op, other):
return Expr(op=op, left='current', right=other)
def _right_op(self, op, other):
return Expr(op=op, left=other, right='current')
current = Current()
class YourObj(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __call__(self, **kw):
for key, val in kw.iteritems():
# You should probably make sure it is actually an attribute of YourObj
if isinstance(val, Expr):
current = self.a
new_val = val(current)
setattr(self, key, new_val)
else:
setattr(self, key, val)
And you can do something like:
obj = YourObj(a=4, b=5)
obj(a=current - 4 + current * current)
This is basically an expression interpreter embedded in python's math operations.
Whenever you use an operation on current (like +), it will return an Expr (because it overrides __add__ and __radd__) that will register which operation this is, and what are each of its operands. These expressions can be nested, so if you say current + 4 - current, it will return Expr(op='-', left=Expr(op='+', left='current', right=4), right='current').
An expression can then be evaluated by calling it like a function and passing it the value that should replace 'current'. When you evaluate an expression, it will:
replace all the occurences of 'current' by the value passed
recursively evaluate the nested functions
return the end result of the whole expression
When you do obj(a=current + 4), the __call__ method of YourObj is called. It will evaluate the expression resulting of current + 4 and store it in a.
I hope this is clearer. Maybe I should rename some of the 'current' to make it less confusing.
Your modify method could take the name of the attribute to modify, and a function that takes the current value of the attribute and returns its new computed value. Then you can do something like:
def compute_new_value(current):
new_value = abs(current) % current ** 2
return new_value
myclass = C()
myclass.modify('a', compute_new_value)
For simple cases, lambda makes it less verbose:
myclass.modify('a', lambda cur: cur + 4)
And your class:
class C(object):
[...]
def modify(self, attr_name, func):
cur_value = getattr(self, attr_name)
new_value = func(cur_value)
setattr(self, attr_name, new_value)
Edit: I may have missed something. Since you're writing myclass = myclass.modify..., should the modify method return a copy of the object ?
You have a poor design, in my opinion, but you could do this using eval(). Of course, that just makes your design smell even more. Still...
class C(object):
# ...
def modify(self, **kwargs):
for name, expr in kwargs.iteritems():
setattr(self, name, eval(expr, vars(self)))
obj = C()
obj.modify(a="a+2", b="b*42")
The downside is that you have to pass the expressions as strings. Also, with this simple implementation, you can only use values defined on the instance in the expression (e.g., you cant access class attributes, or any attributes of parent classes, or globals). You could add the ability to use class attributes or globals and even parent classes by building the v dictionary in the appropriate order, of course:
def modify(self, **kwargs):
vardict = {} # allow globals and self attributes to be used in expressions
vardict.update(globals())
vardict.update(vars(self))
for name, expr in kwargs.iteritems():
value = eval(expr, v)
setattr(self, name, eval(expr, vardict))
vardict[name] = value
If you want a current variable that holds the current value, you could use this (inside the loop, since it needs to change for each attribute processed):
v["current"] = getattr(self, name, None)
One of the biggest drawbacks here is that you can't easily access variables from the caller's scope, although you could dig them out of the stack frame I guess... ugh. Or make the caller interpolate those into the string... double ugh.
Morphyn's answer is the proper way to do it, in my opinion. A lambda is hardly complicated
This was my old solution.. (sort of, this a dummy version of it)
class __current__(object):
def do(self, e, v = None):
c = __current__()
c.exp = e
if v is not None:
c.val = v
return(c)
def __abs__(self):
return(self.do(abs))
def __rpow__(self, v):
return(self.do(pow, v))
current = __current__()
class C(object):
def __call__(self, **kwargs):
for keyword, value in kwargs.iteritems():
try:
expression = value.exp
try:
value = expression(vars(self)[keyword], value.val)
except AttributeError:
value = expression(vars(self)[keyword])
except AttributeError:
value = value
setattr(self, keyword, value)
And the usage:
MyObj = C()
MyObj(a = -2)
MyObj(a = abs(current))
MyObj(a = 2 ** current)