Object in List : how?

Peter Otten __peter__ at web.de
Mon Jul 25 04:50:44 EDT 2022


On 25/07/2022 02:47, Khairil Sitanggang wrote:
> Regarding your comment : "
> *However, usually object creation and initialization iscombined by allowing
> arguments to the initializer:*" , so which one of the two classes Node1,
> Node2 below is more common in practice? Option 2, I guess.
> Thanks,
>
>
> # option 1:
> class Node1:
>      def __init__(self, a):
>          self.a = a
>          self.b = self.calculation()
>
>      def calculation(self):
>          r = self.a + 10
>          return r
>
> # option 2:
> class Node2:
>      def __init__(self, a, b):
>          self.a = a
>          self.b = b
>
>          self.b = self.calculation()
>
>      def calculation(self):
>          r = self.a + 10
>          return r
>
> nd1 = Node1(10)
> nd2 = Node2(10, 0) # 0 is dummy, will be overwritten by the call to
> calculation()

An attribute that can be calculated from other attributes should never
be modified through other means. Some day you may want b to become
something else, write, for example,

node = Node2(10, "twenty")

and because by then you have forgotten about the calculation() call end
up with a buggy script. But manually invoking the calculation() method
is also bug prone. You have to remember to repeat it every time you
change a:

node = Node1(10)
assert node.b == 20  # OK

node.a = 20
assert node.b == 30 # fails, a and b are out of sync.

The solution Python has to offer is called "property". Properties in
their simplest form are calculated read-only attributes, i. e. when you
write

print(node.b)

under the hood node.a + 10 is calculated. Here's how to change Node1 to
turn b into such a property:

class Node3a:
     def __init__(self, a):
         self.a = a
     def calculation(self):
         return self.a + 10
     b = property(calculation)

node = Node3a(42)
print(node.b)  # 52

node.a = 1
print(node.b)  # 11

Often you are not interested in exposing both the calculation() method
and the property. For cases when you only want to access the property
Python provides a way to define the property with a "decorator":

class Node3b:
     def __init__(self, a):
         self.a = a
     @property
     def b(self):
         return self.a + 10

When you compare the two classes you can see that I

(1) renamed calculation() to b() and

(2) replaced

def b(self): ...
b = property(b)

with

@property
def b(self): ...

thus avoiding the repetitons of the name.

Are there any disadvantages to properties?

What I presented as an advantage, that the value of the attribute is
recalculated every time the attribute is accessed, may sometimes become
a disadvantage, e. g. when it takes a very long time to calculate. In
most cases that should not be a problem, though.


More information about the Python-list mailing list