Why does one property work and the other not? - python-3.x

It happens that I have two property implementations. but one works and the other does not. That is, that in one it does not even enter the setters.
I gave myself the task of wandering online, and this happens to me is very rare, both are supposed to work.
Do you know why this happens?
Thank you
class QuickTasks():
def __init__(self, name=None, value=None):
self.name = name
self.value = value
#property
def name(self):
return self._name
#name.setter
def name(self, value):
if isinstance(value, str):
self._name = value
else:
raise TypeError("name must be str")
#property
def value(self):
return self._value
#value.setter
def value(self, value):
if isinstance(value, int):
self._value = value
else:
raise TypeError("value must be int")
obj = QuickTasks(name=4, value='j')
print(obj.name)
obj.name = 5
print(obj.name)
################################################################
class TreeNode(object):
def __init__(self, value = None):
self.value = value
self._left_node = None
self._right_node = None
#property
def value(self):
return self._value
#value.setter
def value(self, value):
if isinstance(value, int):
self._value = 8
else:
raise TypeError("value must be int")
def main():
tree_node = TreeNode(3)
#tree_node.value = 3
print (tree_node.value)
if __name__ == '__main__':
print("")
main()

When you hit the line:
obj = QuickTasks(name=4, value='j')
and it assigns to self.name in the QuickTasks initializer, it raises a TypeError, which you don't catch. That bypasses the rest of your code entirely, skipping all uses of the value property (and of TreeNode entirely).

Related

Question about setter and calling MyClass()

I have a class like this:
class A:
b = ""
#property
some_property(self):
raise Error()
#some_property.setter
def some_property(self, some_property_var)
self.b = some_property_var
and i want to do A(some_property='A'), but i can't because
TypeError: A() takes no arguments
. Is there any way to make it work?
I think this is a better example of how to demonstrate what you are trying to do;
#set a property in a class in python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
#property
def age(self):
return self._age
#age.setter
def age(self, age):
self._age = age
p = Person("John", 36)
So in your case;
class A:
def __init__(self, b):
self.b = b
#property
def b(self):
return self._b
#b.setter
def b(self, b):
self._b = b
a = A(1)
print(a.b)
Based on your comments;
#create a class that takes keyword arguments
class A:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
a = A(a=1, b=2)

Python: detect changes in a subclass

Let's consider the following example:
class SubClass:
def __init__(self):
self._param = None
#property
def param(self):
print('read param')
return self._param
#param.setter
def param(self, value):
print('set param')
self._param = value
class MainClass:
def __init__(self):
self._var = SubClass()
#property
def var(self):
print('read var')
return self._var
#var.setter
def var(self, value):
print('set var')
self._var = value
If I do:
cls = MainClass()
cls.var.param = 3
I obtain:
'read var'
'set param'
How can I make MainClass aware that var.param has changed?
Useful additional info: consider that in my actual code param is not a scalar but an array with hundreds of elements, so I would like to avoid to create a copy and then just compare them. Moreover, param and var are not the only properties.
One approach is to pass a method from MainClass as an argument when instantiating SubClass, and have SubClass call it whenever it changes a variable:
class SubClass:
def __init__(self, changed):
self._param = None
self.changed = changed
#property
def param(self):
print('read param')
return self._param
#param.setter
def param(self, value):
print('set param')
self._param = value
self.changed('param')
class MainClass:
def __init__(self):
self._var = SubClass(self.changed)
def changed(self, name):
print("Subclass changed: ", name, getattr(self._var, name))
#property
def var(self):
print('read var')
return self._var
#var.setter
def var(self, value):
print('set var')
self._var = value
m = MainClass()
m.var.param = 'test'

python lost data-descriptor as a instance attribute?

class data_attr_set_pass(object):
def __init__(self, inner=None, name=""):
self.inner = inner
self.name = name
def __get__(self, instance, owner):
return self.inner
def __set__(self, instance, value):
pass
def __repr__(self):
return str(self.name) + ":" + str(self.inner)
class data_attr(object):
def __init__(self, inner=None, name=""):
self.inner = inner
self.name = name
def __get__(self, instance, owner):
return self.inner
def __set__(self, instance, value):
self.inner = value
def __repr__(self):
return str(self.name) + ":" + str(self.inner)
class non_data_attr(object):
def __init__(self, inner=None, name=""):
self.inner = inner
self.name = name
def __get__(self, instance, owner):
return self.inner
def __repr__(self):
return str(self.name) + ":" + str(self.inner)
class Myclass(object):
x = data_attr_set_pass(11, "class attr")
def __init__(self):
self.x = data_attr(890, "instance attr")
print(Myclass.x)
m = Myclass()
print(Myclass.x)
print(m.x)
print(Myclass.__dict__)
print(m.__dict__)
output:
11
11
11
{'__module__': '__main__', 'x': class attr:11, '__init__': <function Myclass.__init__ at 0x7f0dcc2d1378>, '__dict__': <attribute '__dict__' of 'Myclass' objects>, '__weakref__': <attribute '__weakref__' of 'Myclass' objects>, '__doc__': None}
{}
I had some tests for usage of python data-descriptor. And one test had very strange behaviour. I know that descriptor should be class attr, it's just a test:).
I put pass in __set__ of class data_attr_set_pass. So as far as I know, self.x = data_attr(890, "instance attr") in __init__ will put data_attr(890, "instance attr") into self.__dict__. But it can be found nowhere.
why does it happend and where can I find the data-descriptor?
==================================================================
It's really my misunderstanding, I just run first test in code below in which I put 2 into self.__dict__["x"] directly, the second one can prove it.
class Myclass(object):
x = data_attr_set_pass(11, "class attr")
def __init__(self):
self.__dict__["x"] = 2
print(Myclass.x)
m = Myclass()
print(Myclass.x)
print(m.x)
print(Myclass.__dict__)
print(m.__dict__)
print('================')
class Myclass(object):
x = data_attr_set_pass(1324, "class attr")
def __init__(self):
self.x = 2232
print(Myclass.x)
m = Myclass()
print(Myclass.x)
print(m.x)
print(Myclass.__dict__)
print(m.__dict__)
You say
I put pass in __set__ of class data_attr_set_pass. So as far as I know, self.x = data_attr(890, "instance attr") in __init__ will put data_attr(890, "instance attr") into self.__dict__.
But why would it do that? You didn't write data_attr_set_pass.__set__ to insert the value into the instance __dict__. You wrote your __set__ to do nothing but pass.
Assigning something to self.x does exactly what you wrote your __set__ to do: nothing.

TypeError: object() takes no parameters - python3

I am trying to work on some problem where I could use this code to learn how to implement Binary Search Tree, this code is based on http://interactivepython.org/runestone/static/pythonds/Trees/SearchTreeImplementation.html however there are come bugs in the original code, which I think should be fixed by doing the following.
Edited this code to remove a syntax error.
class TreeNode(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls, args, kwargs)
def __init__(self, key, val, left=None, right=None, parent=None):
self.key = key
self.payload = val
self.leftChild = left
self.rightChild = right
self.parent = parent
def hasLeftChild(self):
return self.leftChild
def hasRightChild(self):
return self.rightChild
def isLeftChild(self):
return self.parent and self.parent.leftChild == self
def isRightChild(self):
return self.parent and self.parent.rightChild == self
def isRoot(self):
return not self.parent
def isLeaf(self):
return not(self.leftChild or self.rightChild)
def hasAnyChildren(self):
return self.leftChild or self.rightChild
def hasBothChildren(self):
return self.leftChild and self.rightChild
def replaceNodeData(self, key, value, lc, rc):
self.key = key
self.payload = value
self.leftChild = lc
self.rightChild = rc
if self.hasLeftChild():
self.leftChild.parent = self
if self.hasRightChild():
self.rightChild.parent = self
class BinarySearchTree(TreeNode):
def __init__(self):
# self.root is refrence to TreeNode, which is root
# of primary TreeNode
self.root = None
self.size = 0
def size(self):
return self.size
def __len__(self):
return self.size
def __iter__(self):
return self.root.__iter__()
def put(self, key, val):
# checks if there is root
# if there is a root, lets transverse along tree
if self.root:
self._put(key, val, self.root)
else:
# else if there is not root, lets set a root
# which is a TreeNode instance
self.root = super(BinarySearchTree, cls).__new__(key, val)
self.size = self.size + 1
def _put(self, key, val, currentNode):
if key < currentNode.key:
if currentNode.hasLeftChild():
self._put(key, val, currentNode.leftChild)
else:
currentNode.leftChild = super(BinarySearchTree, cls).__new__(
key, val, parent=currentNode)
else:
if currentNode.hasRightChild():
self._put(key, val, currentNode.rightChild)
else:
currentNode.rightChild = super(BinarySearchTree, cls).__new__(
key, val, parent=currentNode)
def __setitem__(self, k, v):
self.put(k, v)
def get(self, key):
if self.root:
res = self._get(key, self.root)
if res:
return res.payload
else:
return None
else:
return None
def _get(self, key, currentNode):
if not currentNode:
return None
if key == currentNode.key:
return currentNode
if key < currentNode.key:
return self._get(key, currentNode.leftChild)
else:
return self._get(key, currentNode.rightChild)
def __getitem__(self, key):
# this method allows to access instance[index]
# format.
return self.get(key)
def __contains__(self, key):
"""
__contains__ overloads the 'in' operator
allows us to do something simliar to
if 'Northfield' in myZipTree:
print("oom ya ya")
"""
if self._get(key, self.root):
return True
else:
return False
def delete(self, key):
if self.size > 1:
nodeToRemove = self._get(key, self.root)
if nodeToRemove:
self.remove(nodeToRemove)
self.size = self.size - 1
else:
raise KeyError('Error, key was not found')
elif self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error, key was not found')
def __delitem__(self, key):
self.delete(key)
def remove(self, currentNode):
if currentNode.isLeaf():
# current Leaf has only one child
if currentNode == currentNode.parent.leftChild:
currentNode.parent.leftChild = None
else:
currentNode.parent.rightChild = None
elif currentNode.hasBothChildren():
# interior
succ = currentNode.findSuccessor()
succ.spliceOut()
currentNode.key = succ.key
currentNode.payload = succ.payload
else:
# The node to be deleted has only one child.
if currentNode.hasLeftChild():
if currentNode.isLeftChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
# this is a root node, replace it's data with it's
# left children
self.replaceNodeData(
currentNode.leftChild.key,
currentNode.leftChild.value,
currentNode.leftChild,
currentNode.rightChild
)
else:
if currentNode.isLeftChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
# this is a root node, replace it's data with it's
# left children
self.replaceNodeData(
currentNode.leftChild.key,
currentNode.leftChild.value,
currentNode.leftChild,
currentNode.rightChild
)
def __iter__(self):
if self:
if self.hasLeftChild():
for elem in self.leftChiLd:
yield elem
yield self.key
if self.hasRightChild():
for elem in self.rightChild:
yield elem
def findSuccessor(self):
succ = None
if self.hasRightChild():
succ = self.rightChild.findMin()
else:
if self.parent:
if self.hasLeftChild():
succ = self.parent
else:
self.parent.rightChild = None
succ = self.parent.findSuccessor()
self.parent.rightChild = self
return self
def findMin(self):
if self.hasLeftChild():
return self.leftChild.findMin()
else:
return self
def spliceOut(self):
if self.isLeaf():
if self.isLeftChild():
self.parent.leftChild = None
else:
self.parent.rightChild = None
elif self.hasAnyChildren():
if self.hasLeftChild():
if self.isLeftChild():
self.parent.leftChild = self.leftChild
else:
self.parent.rightChild = self.leftChild
self.leftChild.parent = self.parent
else:
if self.isLeftChild():
self.parent.leftChild = self.rightChild
else:
self.parent.rightChild = self.rightChild
self.rightChild.parent = self.parent
mytree = BinarySearchTree()
mytree[17] = "17"
mytree[5] = "5"
mytree[35] = "35"
mytree[2] = "2"
mytree[11] = "11"
mytree[9] = "9"
mytree[16] = "16"
mytree[7] = "7"
mytree[29] = "29"
mytree[38] = "38"
del(mytree[5])
print(mytree[5])
print(mytree[7])
print(mytree.size)
however when I running the code I am getting the following error, I am not very good in OOPs concepts, any educationatory lessons will be appreciated.
# vaibhavchauhan # startup001 in ~/Documents/Projects/interactivepython [19:17:01] C:1
$ python3 binarySearchTreeMod.py
Traceback (most recent call last):
File "binarySearchTreeMod.py", line 248, in <module>
mytree = BinarySearchTree()
File "binarySearchTreeMod.py", line 3, in __new__
return object.__new__(cls, args, kwargs)
TypeError: object() takes no parameters
That __new__ method shouldn't be there. Just remove it. It has a particular purpose, but if you're just learning you shouldn't need it at all.
The __new__ method is primarily used for subclassing immutable objects. That's not what you have, so you don't need it.
See the documentation for more information.

Override abstract setter of property in Python 3

What is the simplest / most pythonic way to override only the setter of an abstract property in Python 3? Variant 3 seems to mean the least effort for the derived class implementor. Is it correct? Does it have disadvantages?
import abc
class A1(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#property
def x(self):
return self._x
#x.setter
#abc.abstractmethod
def x(self, value):
self._x = value
class B1(A1):
#property
def x(self):
return super().x
#x.setter
def x(self, value):
print("B1 setter")
super(B1, self.__class__).x.fset(self, value)
b1 = B1(x=1)
b1.x = 3
print(b1.x)
class A2(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#abc.abstractmethod
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(_get_x, _set_x)
class B2(A2):
def _get_x(self):
return super()._get_x()
def _set_x(self, value):
print("B2 setter")
super()._set_x(value)
x = property(_get_x, _set_x)
b2 = B2(x=1)
b2.x = 3
print(b2.x)
class A3(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(
lambda self: self._get_x(),
lambda self, value: self._set_x(value))
class B3(A3):
def _set_x(self, value):
print("B3 setter")
super()._set_x(value)
b3 = B3(x=1)
b3.x = 3
print(b3.x)
So, yes, you listed a lot of ways in there - and although the one that requires more code is your variant 3, the most straighforard, least surprising way to do it is your variant 1 -
It just works, and is perfectly readable, no surprises - and there seems to be no simpler way than calling fget explicitly there.

Resources