Is there a way to define a class instance is None? - python

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.

Related

Python class does not have value

I am a Javascript engineer and am switching into a JS/Python role. Working on some easy leetcodes to get some quick Python practice.
I'm looking to create a LinkedList here and perhaps I am coming at it from a JS mindset?
Error:
AttributeError: type object 'LinkedListNode' has no attribute 'value'
utils.py
# LinkedList Methods
def createLinkedList(arr):
head = createLinkedListNode(None, arr.pop(0))
def populateList(arr, prevNode):
if arr:
node = createLinkedListNode(None, arr.pop(0))
prevNode.next = node
if arr:
populateList(arr, node)
populateList(arr, head)
return head
def createLinkedListNode(next, value):
class LinkedListNode:
def __init__(self):
self.next = next
self.value = value
return LinkedListNode
deleteNode.py
from python.utils import createLinkedList, linkedListToArray
useCase1 = [4, 5, 1, 9]
linkedList = createLinkedList(useCase1)
^ linkedList.value doesn't exist?
Some misunderstandings with python classes:
The class LinkedListNode should not defined in function.
Return LinkedListNode is actually returning the class itself, but not the Instance. To return the instance, you have to call the class. return LinkedListNode()
Using next as instance variable is not ideal. next is an iteration function in python, so when you set self.next = next, you are actually assigning the function to self.next
If you want to set a variable, for example self.next_value = next_value, you should put next_value as a parameter of __init__ function, like def __init__(self, next_value)
Here is a simple demo of Linked List:
class LinkedList:
def __init__(self, value):
self.value = value
self.next_value = None
def __iter__(self):
yield self.value
if self.next_value is not None:
yield from self.next_value
# else raise StopIteration
def __getitem__(self, index):
if index == 0:
return self.value
else:
return self.next_value[index-1]
# recursively get the next value
def __str__(self):
return str(self.value) + ' -> ' + str(self.next_value)
def __len__(self):
if self.next_value is None:
return 1
else:
return 1 + len(self.next_value)
# recursively get the length
def append(self, value):
if self.next_value is None:
self.next_value = LinkedList(value, self)
else:
self.next_value.append(value)
a = LinkedList(2)
a.append(1)
a.append(3)
for num in a:
print(num, end=", ")
print()
print(a[1])
print(a)
print(len(a))
Output:
2, 1, 3,
1
2 -> 1 -> 3 -> None
3
createLinkedListNode() returns the LinkedListNode class itself, not an instance of the class.
Why are you defining classes and functions inside of other functions? That's an odd way of doing things.

Convert string to a linkedlist in Python

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, >)

More Pythonic way to define custom __eq__ method using try, assert, except

The code below works(EDIT: actually, turns out it doesn't!), but I don't like the hanging return True statement that appears after the try: except: block.
class MySlottedClass(object):
def __new__(klass, **slots):
klass.__slots__ = []
for k in slots:
klass.__slots__.append(k)
return super(MySlottedClass,klass).__new__(klass)
def __init__(self, **slots):
for k,v in slots.items():
setattr(self,k,v)
super(MySlottedClass,self).__new__()
def __eq__(self, other):
for slot in self.__slots__:
try:
assert getattr(self, slot) == getattr(other,slot), "Not Equal"
except (AssertionError, AttributeError):
return False
return True
##Testing
##Note that the above class definition is just a skeleton
##The below objects are created using 4 different but identically defined classes
##In the actual problem, I am using a metaclass to make these classes dynamically
msc1 = MySlottedClassABC(a=1,b=1,c=3)
msc2 = MySlottedClassAB(a=1,b=1)
msc3 = MySlottedClassBA(b=2,a=1)
msc4 = MySlottedClassXY(x=1,y=2)
assert msc1!=msc2
assert msc2==msc3
assert msc3==msc2
assert msc2!=msc4
Is there a more pythonic way of writing the __eq__ method for this class?
The return True is fine. I think the bigger problem is using an assert for flow control. Asserts do not run at all if the user passes -O to python on the command line. You should write something more like this:
for slot in self.__slots__:
if not hasattr(other, slot) or getattr(self, slot) != getattr(other,slot):
return False
return True
Also, __slots__ needs to be defined at the class level to work, not inside __init__:
class Foo(object):
__slots__ = ['a', 'b', 'c']
If you have a variable number of items, you probably should not be using __slots__ at all.
Ugh, nevermind I figured it out. It was pretty obvious:
def __eq__(self, other):
try:
for slot in self.__slots__:
assert getattr(self, slot) == getattr(other,slot), "Not Equal"
except (AssertionError, AttributeError):
return False
else:
return True
I should probably close this question so I don't look too dumb.
Edit: Nope, no good!
Thanks to everyone's help I now understand there are lots of problems with this way of doing it. First of all, I should not be using assert for this since it is mainly for testing, and can be turned off. Second of all, the code doesn't give the expected result for MySlottedClass(a=1,b=2)==MySlottedClass(a=1,b=2,c=3).
I came up with this way instead. Note that the class definition is repeated 4 times so I can test comparison of objects of different classes below; all of the classes are identical, however, until their instances are created. Also note that in the actual use case, I am using a metaclass to generate these classes automatically (and __eq__ is defined as a part of that metaclass).
class MySlottedClassAB(object):
def __new__(klass, **slots):
klass.__slots__ = []
for k in slots:
klass.__slots__.append(k)
return super(MySlottedClassAB,klass).__new__(klass)
def __init__(self, **slots):
for k,v in slots.items():
setattr(self,k,v)
super(MySlottedClassAB,self).__init__()
def __eq__(self, other):
if set(self.__slots__) != set(other.__slots__): return False
for slot in self.__slots__:
if getattr(self, slot) != getattr(other,slot):
return False
return True
def __ne__(self, other):
return not self == other
class MySlottedClassBA(object):
def __new__(klass, **slots):
klass.__slots__ = []
for k in slots:
klass.__slots__.append(k)
return super(MySlottedClassBA,klass).__new__(klass)
def __init__(self, **slots):
for k,v in slots.items():
setattr(self,k,v)
super(MySlottedClassBA,self).__init__()
def __eq__(self, other):
if set(self.__slots__) != set(other.__slots__): return False
for slot in self.__slots__:
if getattr(self, slot) != getattr(other,slot):
return False
return True
def __ne__(self, other):
return not self == other
class MySlottedClassXY(object):
def __new__(klass, **slots):
klass.__slots__ = []
for k in slots:
klass.__slots__.append(k)
return super(MySlottedClassXY,klass).__new__(klass)
def __init__(self, **slots):
for k,v in slots.items():
setattr(self,k,v)
super(MySlottedClassXY,self).__init__()
def __eq__(self, other):
if set(self.__slots__) != set(other.__slots__): return False
for slot in self.__slots__:
if getattr(self, slot) != getattr(other,slot):
return False
return True
def __ne__(self, other):
return not self == other
class MySlottedClassABC(object):
def __new__(klass, **slots):
klass.__slots__ = []
for k in slots:
klass.__slots__.append(k)
return super(MySlottedClassABC,klass).__new__(klass)
def __init__(self, **slots):
for k,v in slots.items():
setattr(self,k,v)
super(MySlottedClassABC,self).__init__()
def __eq__(self, other):
if set(self.__slots__) != set(other.__slots__): return False
for slot in self.__slots__:
if getattr(self, slot) != getattr(other,slot):
return False
return True
def __ne__(self, other):
return not self == other
And here are the testing procedures:
##Testing
msc1 = MySlottedClassABC(a=1, b=2, c=3)
msc2 = MySlottedClassAB(a=1, b=2)
msc3 = MySlottedClassBA(b=2, a=1)
msc4 = MySlottedClassXY(x=1, y=2)
assert msc1 != msc2
assert msc2 != msc1
assert msc2 == msc3
assert msc3 == msc2
assert msc3 != msc4
assert msc4 != msc3
However, after testing Joran Beasley's answer, I discovered to my surprised it produces IDENTICAL results to that above, with much shorter and more sensible code. So it seems the best way to accomplish this is to simply compare the two __dict__ attributes.
Seems like you are trying to recreate a namedtuple. Using namedtuple will allow to create classes on the dynamically, test for equality and other interesting things. The downside is that since tuples are immutable, so to are namedtuples and you will have to create a new object instead of updating an attribute. namedtuples will not check the order of your slots, so you must order your slots lexicographically or add your own __eq__ method that accounts for slot order.
Example usage:
from collections import namedtuple
MySlottedClassAB = namedtuple("MySlottedClassAB", ['a', 'b'])
MySlottedClassABC = namedtuple("MySlottedClassABC", ['a', 'b', 'c'])
class MySlottedClassBA(namedtuple("MySlottedClassBA", ['b', 'a'])):
def addAB(self):
return self.a + self.b
msc1 = MySlottedClassAB(a=1, b=2)
msc2 = MySlottedClassBA(b=2, a=1)
msc3 = MySlottedClassABC(1, 2, 3)
print(msc1)
print(msc2)
print(msc3)
print("{} == {} is {}".format(msc1, msc1, msc1==msc1))
print("{} == {} is {}".format(msc1, msc2, msc1==msc2))
print("{} == {} is {}".format(msc1, msc3, msc1==msc3))
print("msc2.addAB() is {}".format(msc2.addAB()))
If the order of your slots and mutability are important the following will work (for python 2).
class MySlottedClassMeta(type):
def __init__(cls, name, bases, attrs):
super(MySlottedClassMeta, cls).__init__(name, bases, attrs)
def __new__(metacls, name, bases, attrs):
assert "__slots__" in attrs
attrs["_ordered_slots"] = tuple(sorted(attrs["__slots__"]))
attrs["__init__"] = create_init(attrs["__slots__"])
attrs["__eq__"] = create_eq()
attrs["__str__"] = create_str()
cls = super(MySlottedClassMeta, metacls).__new__(metacls, name, bases, attrs)
return cls
def create_init(slots):
args = ", ".join(slots)
assignments = "\n ".join("self.{0} = {0}".format(attr) for attr in slots)
init_source = """
def __init__(self, {}):
{}
""".format(args, assignments)
exec(init_source, globals(), None)
return __init__
def create_eq():
def __eq__(self, other):
try:
same_slots = self._ordered_slots == other._ordered_slots
except AttributeError:
return False
if not same_slots:
return False
return all(getattr(self, attr) == getattr(other, attr)
for attr in self._ordered_slots)
return __eq__
def create_str():
def __str__(self):
attr_values = ", ".join("{}={}".format(s, getattr(self, s)) for s in self.__slots__)
return "{}({})".format(self.__class__.__name__, attr_values)
return __str__
class MySlottedClassXY(object):
__slots__ = ['x', 'y']
__metaclass__ = MySlottedClassMeta
class MySlottedClassYX(object):
__slots__ = ['y', 'x']
__metaclass__ = MySlottedClassMeta
xy1 = MySlottedClassXY(x=1,y=2)
xy2 = MySlottedClassXY(1, 2)
yx = MySlottedClassYX(x=1, y=2)
print(xy1.__slots__)
print(yx.__slots__)
assert xy1 == xy1
assert xy1 == xy2
assert xy1 == yx
It's work noting that __slots__ are overkill in almost all circumstances. Guido Van Rossum stated that they were a premature optimisation based on unfounded fears about the performance of attribute lookups in new style classes. Guido does also state that __slots__ can reduce the memory footprint of program when you need to create lots of small objects.
I feared that all of the changes in the [new] class system were going to have a negative impact on performance. ... Thus the use of __slots__ was a way to optimize the lookup of data attributes—a fallback, if you will, in case people were disappointed with the performance impact of the new class system. This turned out unnecessary, but by that time it was of course too late to remove __slots__.
http://python-history.blogspot.co.uk/2010/06/inside-story-on-new-style-classes.html
def __eq__(self,other):
return self.__dict__== other.__dict__
should work

Implement and/or tree in python

I need to implement an And/or tree in python so I can evaluate boolean expressions,
I had an idea of creating a class that contains andNode, orNode and leafNode. The first two are are internal nodes that must have and or or values, the leafNode must have and integer value and represent the final leaves of the tree.I tried this but it doesn't seem to work:
class Node:
def __init__(self,leaf):
self.orNode = None
self.andNode = None
self.leaf = leaf
class and_or_tree (Node):
def __init__(self):
self.root=None
I need to test if an element exists in the tree, the height and iterate through it.
I think an example of such Leaf and and/or nodes could be something like this:
class Leaf:
def __init__(self, v):
self.val = v;
def __call__(self):
return self.val
class AndNode:
def __init__(self, l, r):
self.left = l;
self.right = r;
def __call__(self):
return self.left() and self.right()
class OrNode:
def __init__(self, l, r):
self.left = l;
self.right = r;
def __call__(self):
return self.left() or self.right()
You can build a tree like this:
print AndNode(Leaf(True), Leaf(False))()
print AndNode(OrNode(Leaf(True), Leaf(False)), Leaf(True))()
Which outputs this:
False
True

Is it possible to create a variable as a placeholder for 'current' value of a class in python?

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)

Categories

Resources