Is it possible to change the behavior of a method on consecutive runs?
For example, we have the following two classes:
#dataclass
class A():
foo: str = None
def print_message(self, first_time=True):
if first_time:
print("foo is set for the first time!")
else:
print("foo is re-assigned!")
class B(A):
_x = None
#property
def foo(self) -> str:
""" foo getter"""
return _x
#foo.setter
def foo(self, value: str):
""" foo setter"""
self._x = value
self.print_message()
I would like the following behavior:
my_B = B(foo = 'moo')
# "foo is set for the first time!" is printed
my_B.foo = 'koo'
# "foo is re-assigned!" is printed
Ok, I've got it. The _x should be checked in the setter: if it is None, then the variable is assigned for the first time. Works even with the default value of foo in A:
from dataclasses import dataclass
#dataclass
class A():
foo: str = 'moo'
def print_message(self, first_time=True):
if first_time:
print("foo is set for the first time!")
else:
print("foo is re-assigned!")
class B(A):
_x = None
#property
def foo(self) -> str:
""" foo getter"""
return _x
#foo.setter
def foo(self, value: str):
""" foo setter"""
if self._x is None:
self.print_message()
else:
self.print_message(first_time=False)
self._x = value
And we've got:
my_B = B()
# "foo is set for the first time!" is printed
my_B.foo = 'koo'
# "foo is re-assigned!" is printed
my_B.foo = 'soo'
# "foo is re-assigned!" is printed
As expected!
Related
The following is my python code. I think output_ports and input_ports have diffrent address.
class test():
def __init__(self) -> None:
pass
class INode(object):
node_name = "INode"
config = None
output_ports = []
input_ports = []
def __init__(self) -> None:
super().__init__()
pass
def NodeStart(slef):
pass
def GetOutputPort(self):
print(self)
index = len(self.output_ports)
# self.output_ports[index] = test()
self.output_ports.append(test())
# return self.output_ports[index]
def GetInputPort(self):
print(self)
index = len(self.output_ports)
self.input_ports.append(test())
class AdbCollectNode(INode):
def __init__(self) -> None:
super(AdbCollectNode, self).__init__()
self.node_name = "s"
pass
def LinkNode(node_output, node_input):
node_output.GetOutputPort()
node_input.GetInputPort()
if __name__ == '__main__':
adb_node = AdbCollectNode()
adb_node_1 = AdbCollectNode()
adb_node_2 = AdbCollectNode()
LinkNode(adb_node_1, adb_node_2)
LinkNode(adb_node_1, adb_node)
print(id(adb_node_1.input_ports))
print(id(adb_node.input_ports))
print(id(adb_node_2.input_ports))
print(id(adb_node_1.output_ports))
print(id(adb_node.output_ports))
print(id(adb_node_2.output_ports))
id() output as follow:
4549382592
4549382592
4549382592
4549356224
4549356224
4549356224
I think the subclass variables address are the same。 why not same?
So I have this class:
class UniversalHash(HashClass):
##################################################
def __init__(self):
super().__init__()
self.__MParamK = int(0)
self.__MParamC = int(0)
self.__MParamD = int(0)
# Override #
def FindHash(self, Key):
return (((self.__MParamK * Key) + self.__MParamC) % self.__MParamD) % self.__MParamL
def SetParamK(self, Value):
self.__MParamK = Value
def SetParamC(self, Value):
self.__MParamC = Value
def SetParamD(self, Value):
self.__MParamD = Value
And the parent class:
class HashClass:
##################################################
def __init__(self):
self.__MParamL = int(0)
def SetParamL(self, Value):
self.__MParamL = Value
def GetParamL(self):
return self.__MParamL
def FindHash(self, Key):
pass
When I try to access to the variable __MParamL (the variable created in the parent), it gives me an exception telling me that the variable is not an attribute of this class, I have searched on the web and it seems this is the correct way to write the code (maybe the overridden function is the problem?). Any help is appreciated
When you name an instance attribute with a leading double underscore, it will get name mangled, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self.__y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_A__y': 42}
Instead, you should just use a single underscore, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self._y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_y': 42}
I'd like to create a dictonary: {int, Class} in a loop, however the class object is being overriden.
I am pretty sure that this is a basic problem, but I am stuck
class Simple:
simpleDic = {
'name': {""},
'age': {1}}
def __init__(self, name, age):
self.simpleDic['name'] = name
self.simpleDic['age'] = age
def __str__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def foo():
myDict = {}
for x in range(3):
myDict[x] = Simple('Name' + str(x), x)
print(('{}: {}\n'.format("Creating", myDict[x])))
for key in myDict:
print(('{}: {}\n'.format("Printing" + str(key), myDict[key])))
#### Main program here ####
foo()
The output is as follows:
You're problem is on the last print
You're printing myDict[x] when you should print myDict[key]
x contains the last value from the first iteration, so you're practically printing the same key all over
Following your question in this comments:
class Simple:
def __init__(self, name, age):
self.simpleDic = {"name": name, "age": age}
def __str__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def __repr__(self):
return "{} {}\n".format(self.simpleDic['name'], self.simpleDic['age'])
def foo():
myDict = {}
for x in range(3):
myDict[x] = Simple('Name' + str(x), x)
print(('{}: {}\n'.format("Creating", myDict[x])))
print(myDict)
I'm overwriting the MutableSet from collections.abc, and I want to be able to determine whenever its instance equates to True/False.
I know about the magic methods for comparisons, but I am looking for behaviour like checking an empty set/list that Python provides.
class Example():
pass
e = Example()
if e:
print("This shall work - the default of an instance is True")
# What I'd like is something similar to...
if []:
pass
else:
print("This shall be false because it's empty, there wasn't a comparison")
I've looked in the cookbook: Special methods Data model - Other various websites - I can't seem to find the answer :(
Ultimately I would like to be able to go:
class A:
def __init__(self, value: int):
self.value = value
def __cool_equality_method__(self):
return self.value > 5
a = A(10)
b = A(3)
if a:
print("This happens")
if b:
print("This doesn't happen")
What about __bool__ simply?
class A:
def __bool__(self):
if not getattr(self, 'trueish', None):
return False
else:
return True
a = A()
if a:
print("Hello")
a.trueish = True
if a:
print("a is True")
You need to implement the __bool__ method on your class, which is simply your old __cool_equality_method__ renamed to __bool__:
class A:
def __init__(self, value: int):
self.value = value
def __bool__(self):
return self.value > 5
a = A(10)
b = A(3)
if a:
print("This happens")
if b:
print("This doesn't happen")
"""
This happens
"""
First, let's consider this working example using get and set methods for the variable x
class Foo:
def __init__(self):
self._x = 0
def set_x(self, x):
self._x = x
def get_x(self):
return self._x
class Bar:
def __init__(self, set_method):
self._set_method = set_method
def set_x(self, x):
self._set_method(x)
f = Foo()
f.set_x(5)
print(f.get_x())
# Prints 5
b = Bar(f.set_x)
b.set_x(10)
print(f.get_x())
# Prints 10
As you can see I pass the possibility to set the variable x of the instance f of class Foo, to the instance b of class Bar.
Now, I would like to do the same, but with property decorators instead, roughly like this
class Foo:
def __init__(self):
self._x = 0
#property
def x(self):
return self._x
#x.setter
def x(self, x):
self._x = x
class Bar:
def __init__(self, x_property):
self._x_property = x_property
def set_x(self, x):
self.x_property = x
f = Foo()
f.x = 5
print(f.x)
# Prints 5
b = Bar(f.x)
b.set_x(10)
print(f.x)
# Prints 5
What happens is that the value 5, instead of the property, gets passed to instance b, meaning that b can't access x in instance f. Is there a nice way to solve this?
I would then also like to do the same thing for the get method. In the first code that requires me to pass both methods, but if there is a way to get the second code to work I would hopefully only have to pass on the property which I then can set and get as a normal variable.
I would really want to use the property decorators or similar as it cleans up my code a lot. I use python 3.5.2.
Thanks,
Andreas
You can accomplish this by accessing the fset attribute of Foo.x. Note the use of class-dot notation rather than instance-dot. fset takes two arguments: the instance to access and the value to write. Here is a working example
class Foo:
#property
def x(self):
return self._x
#x.setter
def x(self, x):
self._x = x
class Bar:
def __init__(self, x_property):
self.x_property = x_property
def set_x(self, foo, value):
self.x_property(foo, value)
f = Foo()
f.x = 5
print(f.x)
b = Bar(Foo.x.fset)
b.set_x(f, 10)
print(f.x)
Notice that we had to pass f to set_x because we need it to invoke the setter. You could eliminate the f param by using partial from the functools module to bind f to the property setter. Pass the partial binding in to the constructor of Bar.
class Bar:
def __init__(self, x_property):
self.x_property = x_property
def set_x(self, value):
self.x_property(value)
f = Foo()
b = Bar(partial(Foo.x.fset, f))
b.set_x(10)
print(f.x)
It might be wise to rename x_property and this point. It is really just a function as far as Bar is concerned. It wouldn't have to be a property.