Re: Object in List : how?

2022-07-25 Thread Khairil Sitanggang
Again, thank you so much for all your suggestions; it's even easier for me
now to proceed with my coding with all the guidance in one place (this
email thread).  I highly appreciate all of your help.
I love this python community :)

Regards,
-Irfan


On Mon, Jul 25, 2022 at 12:38 PM Dennis Lee Bieber 
wrote:

> On 23 Jul 2022 22:55:47 GMT, r...@zedat.fu-berlin.de (Stefan Ram) declaimed
> the following:
>
> >Dennis Lee Bieber  writes:
> >>  if len([node for node in nodelist if node.no == no1]):
> >>  print("Found at least one occurence")
> >
> >  I'm not sure you need the "len"; an empty list already is falsy.
> >
>
> Just wanted to be explicit for the OP.
>
>
> --
> Wulfraed Dennis Lee Bieber AF6VN
> wlfr...@ix.netcom.com
> http://wlfraed.microdiversity.freeddns.org/
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-25 Thread Dennis Lee Bieber
On Fri, 22 Jul 2022 23:28:11 -0500, Khairil Sitanggang 
declaimed the following:


>class Node:
>def __init__(self):
>self.NO = 0
>self.A = 20
>
>NODE = Node()
>NODELIST = []
>

Comment...

The convention is that ALL CAPS is used to indicate something that is
to be treated as a CONSTANT. Classes get capitalized initial letters. Names
of variable data is traditionally all lower case, lower case with _ between
"words" (eg: lower_case), or camel case (eg: camelCase).

>NODE.NO = 10
>NODELIST.append(NODE)
>
>NODE.NO = 20
>NODELIST.append(NODE)
>
>NODE.NO = 30
>NODELIST.append(NODE)
>
>
>NO1 = 20
>if NO1 not in NODELIST[:].NO  ???

The [:], in this statement, just says "make a copy of nodelist". The
/list/ does not have an attribute named "NO". You have to ask for each
element IN the list.

One convoluted way (I've not tested it) is:

if len([node for node in nodelist if node.no == no1]):
print("Found at least one occurence")

This is a list comprehension; it loops over each element in nodelist,
making a new list if the element attribute matches the criteria. Python
treats 0 as "false" and if no element matched, the list created is empty,
so len() is 0. Anything else implies a match was found.


-- 
Wulfraed Dennis Lee Bieber AF6VN
wlfr...@ix.netcom.comhttp://wlfraed.microdiversity.freeddns.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-25 Thread Weatherby,Gerard
“Private” properties are more simply / commonly designated by sticking an _ in 
front of the name.

class Node:

def __init__(self,a)
self._a = a

I recommend you read https://docs.python.org/3/tutorial/classes.html.


That’s not to say properties don’t have their uses, but making things “private” 
isn’t a major one.

—
Gerard Weatherby | Application Architect NMRbox | NAN | Department of Molecular 
Biology and Biophysics
 UConn Health 263 Farmington Avenue, Farmington, CT 06030-6406 uchc.edu
On Jul 25, 2022, 10:36 AM -0400, Khairil Sitanggang , wrote:
*** Attention: This is an external email. Use caution responding, opening 
attachments or clicking on links. ***

Thank you everyone. The specific requirements for that class:

*(1)* Provide the values of the "input" (via constructors).
*I think everyone agrees with the way it is implemented in the
example. *

*(2)* Provide other products such as *b* that can be of any type (array,
object, etc.). It is like an "output" if you will.
*I think everyone suggests that it should be designed such that people
should not be able (inadvertently) to change the value from outside the
class. I agree, as a matter of fact this is my intent as well.*

*(3)* About the function calc(), my intent is NOT to expose it outside the
class: it is "private".
*And I see the way to do that from your suggestions. *

Based on all your valuable suggestions, I should be able to accomplish the
3 goals.

By the way, I am writing this code for finite element analysis (FEA):
number crunching. Even though the final goal is to get the correct results,
I still want to write it following the correct python "grammar" and style.

Best regards,
-Irfan

On Mon, Jul 25, 2022 at 3:54 AM Peter Otten <__pete...@web.de> wrote:

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.

--
https://urldefense.com/v3/__https://mail.python.org/mailman/listinfo/python-list__;!!Cn_UX_p3!gibw_ZRRGmldOXyvOxYalA9ApszdEvnBdHnTgNVTbgvDAks80irsggsw45ZkniBHx0YRieVHhKAyn1gR$
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-25 Thread Khairil Sitanggang
Thank you everyone. The specific requirements for that class:

*(1)* Provide the values of the "input" (via constructors).
 *I think everyone agrees with the way it is implemented in the
example. *

*(2)* Provide other products such as *b* that can be of any type (array,
object, etc.). It is like an "output" if you will.
 *I think everyone suggests that it should be designed such that people
should not be able (inadvertently) to change the value from outside the
class.  I agree, as a matter of fact this is my intent as well.*

*(3)* About the function calc(), my intent is NOT to expose it outside the
class: it is "private".
 *And I see the way to do that from your suggestions. *

Based on all your valuable suggestions, I should be able to accomplish the
3 goals.

By the way, I am writing this code for finite element analysis (FEA):
number crunching. Even though the final goal is to get the correct results,
I still want to write it following the correct python "grammar" and style.

Best regards,
-Irfan

On Mon, Jul 25, 2022 at 3:54 AM Peter Otten <__pete...@web.de> wrote:

> 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.
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-25 Thread Peter Otten

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.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread dn
On 25/07/2022 12.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()

Let's start with calculation() - even though it is not your specific
question:

Given that "self" makes it into an instance-method, it will have access
to self.b! Accordingly, the intermediate variable "r" and its return
serves no purpose - assuming calculation() is only used to produce a
value for self.b - which would leave:

def calculation( self ):
self.b = self.a + 10

At which point, the method becomes pointless - may as well put its
single line in-line within __init__() - as I say, with above assumptions.


Some languages do expect that every identifier (data-attribute in this
case) be declared (as to type) and probably also initialised with a
value. Some languages, and some Style Guides require that all
data-attributes are declared within the constructor/initialiser.

Python requires neither of these.

Accordingly, if the "b" argument will only ever be a "dummy", there is
absolutely no need for it - indeed one could argue that its presence is
confusing because it gives the impression than it could assume any
value. (see elsewhere in this thread).

So, with assumptions and short of facts, "option 1" seems better (with
the additional consideration regarding calculation(), as above).
-- 
Regards,
=dn
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread 2QdxY4RzWzUUiLuE
On 2022-07-24 at 19:47:38 -0500,
Khairil Sitanggang  wrote:

> Regarding [Peter Otten's] 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.

No.  Please use option 1.

Another option would be to expose b as an optional parameter with a
default value:

class Node:
def __init__(self, a, b=0):
self.a = a
self.b = self.calculation() if b == 0 else b

There are other ways to write that particular assignment to b (because
the default is 0), but the relevant concept for right now is that
callers *can* supply a value for b, but that they don't *have* to:

n1 = Node(a) # uses a default value for b
n2 = Node(a, 22) # overrides the default; use 22 instead

Designing APIs can be tricky, and it's not an exact science.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread Khairil Sitanggang
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()





On Sun, Jul 24, 2022 at 2:23 AM Peter Otten <__pete...@web.de> wrote:

> On 23/07/2022 06:28, Khairil Sitanggang wrote:
> > Hello Expert:
> >
> > I just started using python. Below is a simple code.  I was trying to
> check
> > if, say, NO1 is not in the NODELIST[:].NO
> > How can I achieve this purpose?
> >
> > Regards,
> > -Irfan
> >
> >
> > class Node:
> >  def __init__(self):
> >  self.NO = 0
> >  self.A = 20
> >
> > NODE = Node()
> > NODELIST = []
> >
> > NODE.NO = 10
> > NODELIST.append(NODE)
> >
> > NODE.NO = 20
>
> This just overwrites the attribute; the previous value 10 is lost.
>
> > NODELIST.append(NODE)
> >
> > NODE.NO = 30
>
> This againoverwrites the attribute; the previous value 20 is lost.
>
> > NODELIST.append(NODE)
>
>
> You are three times appending the *same* node to the list.
> To create a new node you need to invoke the initializer:
>
> [I'm following a common convention and use lowercase names in my examples]
>
> nodelist = []
>
> # first node
> node = Node()
> node.no = 10
> nodelist.append(node)
>
> # second node
> node = Node()  # this is crucial
> node.no = 20
> nodelist.append(node)
>
> ... and so on. However, usually object creation and initialization is
> combined by allowing arguments to the initializer:
>
> class Node:
>  def __init__(self, no, a):
>  self.no = no
>  self.a = a
>
> nodelist = []
> for no in [10, 20, 30]:
>  nodelist.append(Node(no, 20))
>
> > NO1 = 20
> > if NO1 not in NODELIST[:].NO  ???
>
> You are checking if the list contains an item with a specific attribute
> value, so you cannot use the nodelist directly, you need an intermediate
> list that contains the attribute values:
>
> no1 = 20
> nos = [node.no for node in nodelist]
> if no1 not in nos:
>  print("not found")
>
> There's one disadvantage to this approach. If the node list is huge
> another huge list with the attribute values is built even though the
> first item in the nodelist may already have the searched-for attribute
> value. To avoid the overhead you could write a function:
>
> def contains_no(nodes, no):
>  for node in nodes:
>  if node.no == no:
>  return True
>  return False
>
> if not contains_no(nodelist, 20):
>  print("not found")
>
> But Python has something more elegant, a kind of /lazy/ /list/ called
> "generator expression" where each item is calculated on demand. With
> that you can write
>
> if 20 not in (node.no for node in nodelist):
>  print("not found")
>
> and your script will stop inspecting further nodes as soon as a matching
> node is found.
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread Khairil Sitanggang
Peter:
Thanks for the explanation. It is clear and easy to understand for a
beginner like me. I highly appreciate it.
Regards,
-Irfan

On Sun, Jul 24, 2022 at 2:23 AM Peter Otten <__pete...@web.de> wrote:

> On 23/07/2022 06:28, Khairil Sitanggang wrote:
> > Hello Expert:
> >
> > I just started using python. Below is a simple code.  I was trying to
> check
> > if, say, NO1 is not in the NODELIST[:].NO
> > How can I achieve this purpose?
> >
> > Regards,
> > -Irfan
> >
> >
> > class Node:
> >  def __init__(self):
> >  self.NO = 0
> >  self.A = 20
> >
> > NODE = Node()
> > NODELIST = []
> >
> > NODE.NO = 10
> > NODELIST.append(NODE)
> >
> > NODE.NO = 20
>
> This just overwrites the attribute; the previous value 10 is lost.
>
> > NODELIST.append(NODE)
> >
> > NODE.NO = 30
>
> This againoverwrites the attribute; the previous value 20 is lost.
>
> > NODELIST.append(NODE)
>
>
> You are three times appending the *same* node to the list.
> To create a new node you need to invoke the initializer:
>
> [I'm following a common convention and use lowercase names in my examples]
>
> nodelist = []
>
> # first node
> node = Node()
> node.no = 10
> nodelist.append(node)
>
> # second node
> node = Node()  # this is crucial
> node.no = 20
> nodelist.append(node)
>
> ... and so on. However, usually object creation and initialization is
> combined by allowing arguments to the initializer:
>
> class Node:
>  def __init__(self, no, a):
>  self.no = no
>  self.a = a
>
> nodelist = []
> for no in [10, 20, 30]:
>  nodelist.append(Node(no, 20))
>
> > NO1 = 20
> > if NO1 not in NODELIST[:].NO  ???
>
> You are checking if the list contains an item with a specific attribute
> value, so you cannot use the nodelist directly, you need an intermediate
> list that contains the attribute values:
>
> no1 = 20
> nos = [node.no for node in nodelist]
> if no1 not in nos:
>  print("not found")
>
> There's one disadvantage to this approach. If the node list is huge
> another huge list with the attribute values is built even though the
> first item in the nodelist may already have the searched-for attribute
> value. To avoid the overhead you could write a function:
>
> def contains_no(nodes, no):
>  for node in nodes:
>  if node.no == no:
>  return True
>  return False
>
> if not contains_no(nodelist, 20):
>  print("not found")
>
> But Python has something more elegant, a kind of /lazy/ /list/ called
> "generator expression" where each item is calculated on demand. With
> that you can write
>
> if 20 not in (node.no for node in nodelist):
>  print("not found")
>
> and your script will stop inspecting further nodes as soon as a matching
> node is found.
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread Khairil Sitanggang
Thank you.

On Sun, Jul 24, 2022 at 2:23 AM Peter Otten <__pete...@web.de> wrote:

> On 23/07/2022 06:28, Khairil Sitanggang wrote:
> > Hello Expert:
> >
> > I just started using python. Below is a simple code.  I was trying to
> check
> > if, say, NO1 is not in the NODELIST[:].NO
> > How can I achieve this purpose?
> >
> > Regards,
> > -Irfan
> >
> >
> > class Node:
> >  def __init__(self):
> >  self.NO = 0
> >  self.A = 20
> >
> > NODE = Node()
> > NODELIST = []
> >
> > NODE.NO = 10
> > NODELIST.append(NODE)
> >
> > NODE.NO = 20
>
> This just overwrites the attribute; the previous value 10 is lost.
>
> > NODELIST.append(NODE)
> >
> > NODE.NO = 30
>
> This againoverwrites the attribute; the previous value 20 is lost.
>
> > NODELIST.append(NODE)
>
>
> You are three times appending the *same* node to the list.
> To create a new node you need to invoke the initializer:
>
> [I'm following a common convention and use lowercase names in my examples]
>
> nodelist = []
>
> # first node
> node = Node()
> node.no = 10
> nodelist.append(node)
>
> # second node
> node = Node()  # this is crucial
> node.no = 20
> nodelist.append(node)
>
> ... and so on. However, usually object creation and initialization is
> combined by allowing arguments to the initializer:
>
> class Node:
>  def __init__(self, no, a):
>  self.no = no
>  self.a = a
>
> nodelist = []
> for no in [10, 20, 30]:
>  nodelist.append(Node(no, 20))
>
> > NO1 = 20
> > if NO1 not in NODELIST[:].NO  ???
>
> You are checking if the list contains an item with a specific attribute
> value, so you cannot use the nodelist directly, you need an intermediate
> list that contains the attribute values:
>
> no1 = 20
> nos = [node.no for node in nodelist]
> if no1 not in nos:
>  print("not found")
>
> There's one disadvantage to this approach. If the node list is huge
> another huge list with the attribute values is built even though the
> first item in the nodelist may already have the searched-for attribute
> value. To avoid the overhead you could write a function:
>
> def contains_no(nodes, no):
>  for node in nodes:
>  if node.no == no:
>  return True
>  return False
>
> if not contains_no(nodelist, 20):
>  print("not found")
>
> But Python has something more elegant, a kind of /lazy/ /list/ called
> "generator expression" where each item is calculated on demand. With
> that you can write
>
> if 20 not in (node.no for node in nodelist):
>  print("not found")
>
> and your script will stop inspecting further nodes as soon as a matching
> node is found.
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-24 Thread Peter Otten

On 23/07/2022 06:28, Khairil Sitanggang wrote:

Hello Expert:

I just started using python. Below is a simple code.  I was trying to check
if, say, NO1 is not in the NODELIST[:].NO
How can I achieve this purpose?

Regards,
-Irfan


class Node:
 def __init__(self):
 self.NO = 0
 self.A = 20

NODE = Node()
NODELIST = []

NODE.NO = 10
NODELIST.append(NODE)

NODE.NO = 20


This just overwrites the attribute; the previous value 10 is lost.


NODELIST.append(NODE)

NODE.NO = 30


This againoverwrites the attribute; the previous value 20 is lost.


NODELIST.append(NODE)



You are three times appending the *same* node to the list.
To create a new node you need to invoke the initializer:

[I'm following a common convention and use lowercase names in my examples]

nodelist = []

# first node
node = Node()
node.no = 10
nodelist.append(node)

# second node
node = Node()  # this is crucial
node.no = 20
nodelist.append(node)

... and so on. However, usually object creation and initialization is
combined by allowing arguments to the initializer:

class Node:
def __init__(self, no, a):
self.no = no
self.a = a

nodelist = []
for no in [10, 20, 30]:
nodelist.append(Node(no, 20))


NO1 = 20
if NO1 not in NODELIST[:].NO  ???


You are checking if the list contains an item with a specific attribute
value, so you cannot use the nodelist directly, you need an intermediate
list that contains the attribute values:

no1 = 20
nos = [node.no for node in nodelist]
if no1 not in nos:
print("not found")

There's one disadvantage to this approach. If the node list is huge
another huge list with the attribute values is built even though the
first item in the nodelist may already have the searched-for attribute
value. To avoid the overhead you could write a function:

def contains_no(nodes, no):
for node in nodes:
if node.no == no:
return True
return False

if not contains_no(nodelist, 20):
print("not found")

But Python has something more elegant, a kind of /lazy/ /list/ called
"generator expression" where each item is calculated on demand. With
that you can write

if 20 not in (node.no for node in nodelist):
print("not found")

and your script will stop inspecting further nodes as soon as a matching
node is found.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-23 Thread Khairil Sitanggang
dn,

Thanks for the good analogy and explanation.  I need some time to digest it.

Regards,
-Irfan


On Sat, Jul 23, 2022 at 6:55 PM dn  wrote:

> On 24/07/2022 09.57, MRAB wrote:
> > On 23/07/2022 05:28, Khairil Sitanggang wrote:
> >> Hello Expert:
> >>
> >> I just started using python. Below is a simple code.  I was trying to
> >> check
> >> if, say, NO1 is not in the NODELIST[:].NO
> >> How can I achieve this purpose?
> >>
> >> Regards,
> >> -Irfan
> >>
> >>
> >> class Node:
> >>  def __init__(self):
> >>  self.NO = 0
> >>  self.A = 20
> >>
> >> NODE = Node()
> >> NODELIST = []
> >>
> >> NODE.NO = 10
> >> NODELIST.append(NODE)
> >>
> >> NODE.NO = 20
> >> NODELIST.append(NODE)
> >>
> >> NODE.NO = 30
> >> NODELIST.append(NODE)
> >>
> >>
> >> NO1 = 20
> >> if NO1 not in NODELIST[:].NO  ???
> >
> > No, you can't do it that way. You have to iterate through the list and
> > check each member individually:
> >
> > if any(NO1 == N.NO for N in NODELIST):
> >
> > And another thing: you've created only 1 node, and you're changing it
> > each time before adding it to the list, so the list ends up with 3
> > references to the _same_ object.
>
> +1
>
>
> Imagine the object (Node) was instead a person, and a bunch of us-people
> get together in a room. You could shout (above the polite conversation)
> "is Fred here?" and Fred will reply - or if Fred is elsewhere, silence
> will reign. That works - but only because everyone knows their own name.
>
> Now imagine something like (my) grade school, where the teacher takes a
> roll/register to note who is present for (or absent from) class. In this
> case another staff-member could enter the room and instead of shouting
> (which would be rude), can ask the teacher "is Fred here?". The teacher
> is able to answer from the roll.
>
> The former case is (sort of) the solution proposed above - in looking
> for Fred, you walk through the room, asking each person in-turn "are you
> Fred?".
>
> The latter is the case for Node and what you were hoping to implement.
>
> Thus, an alternate approach is to keep a register of nodes. Note that
> this is more than a list, because each element of the list (each node)
> is also identified (on the list) by its name. So, two pieces of
> (related) data: the id of the node, and the node itself - the name of
> the person and the person him-/her-self.
>
> Assuming you only have one ID that will be used to access a node,
> Python's built-in dict[ionary] data-structure will provide the advantage
> of direct-access (instead of going through (on average) half the nodes,
> asking each one in-turn, are you ...
>
> So:
>
> > NODE = Node()
> > NODELIST = []
> >
> > NODE.NO = 10
> > NODELIST.append(NODE)
>
> becomes:
>
> graph = dict{}  # could be written as: graph = {}
> node10 = Node( 10 )
> graph[ node.id ] = node10
>
> or even:
>
> graph[ 20 ] = Node( 20 )
>
> if you don't need lots of nodes 'hanging around' outside of the 'list'
> (actually a dict) representing the graph.
>
>
> Then:
>
> > NO1 = 20
> > if NO1 not in NODELIST[:].NO  ???
>
> becomes a single line:
>
> the_node_required = graph[ 20 ]
>
> where "20" is the search-criteria.
>
> Does that make sense?
>
>
> If it does, and when you realise that you'd like to do more with the
> graph than retrieve single nodes (and more-importantly, should you want
> (or dare) to delve further into the depths of Object-Oriented
> Programming) you could declare a second class (graph) containing a
> number of "methods". If one of the methods implemented is __contains__()
> then you could indeed ask:
>
> if 20 in graph:
>
> ie "is Fred in-class today?"
> but just as we would ask "is Fred here?" rather than "is someone
> identified by the name 'Fred' here?", it would seem better form to write:
>
> if node( 20 ) in graph:
>
> ie is there a node with the id of 20, somewhere within the graph?
>
>
> Such might involve sub-classing OrderedDict, UserDict, or even UserList,
> from the Collections library in the (provided/"batteries-included")
> Python Standard Library:
> https://docs.python.org/3/library/collections.html
>
> If needed, the extra methods you choose to implement might include such
> functionality as connecting nodes 10 and 20 with a path/edge, being able
> to traverse edges, and so-on...
>
> Thus, we've covered two categories of class/object: one, a 'data-class'
> which contains data about a single node; the other a 'collection-class'
> which contains multiple nodes making-up the graph. A useful distinction
> and a common related-pair of data-constructs!
> --
> Regards,
> =dn
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-23 Thread dn
On 24/07/2022 09.57, MRAB wrote:
> On 23/07/2022 05:28, Khairil Sitanggang wrote:
>> Hello Expert:
>>
>> I just started using python. Below is a simple code.  I was trying to
>> check
>> if, say, NO1 is not in the NODELIST[:].NO
>> How can I achieve this purpose?
>>
>> Regards,
>> -Irfan
>>
>>
>> class Node:
>>  def __init__(self):
>>  self.NO = 0
>>  self.A = 20
>>
>> NODE = Node()
>> NODELIST = []
>>
>> NODE.NO = 10
>> NODELIST.append(NODE)
>>
>> NODE.NO = 20
>> NODELIST.append(NODE)
>>
>> NODE.NO = 30
>> NODELIST.append(NODE)
>>
>>
>> NO1 = 20
>> if NO1 not in NODELIST[:].NO  ???
> 
> No, you can't do it that way. You have to iterate through the list and
> check each member individually:
> 
>     if any(NO1 == N.NO for N in NODELIST):
> 
> And another thing: you've created only 1 node, and you're changing it
> each time before adding it to the list, so the list ends up with 3
> references to the _same_ object.

+1


Imagine the object (Node) was instead a person, and a bunch of us-people
get together in a room. You could shout (above the polite conversation)
"is Fred here?" and Fred will reply - or if Fred is elsewhere, silence
will reign. That works - but only because everyone knows their own name.

Now imagine something like (my) grade school, where the teacher takes a
roll/register to note who is present for (or absent from) class. In this
case another staff-member could enter the room and instead of shouting
(which would be rude), can ask the teacher "is Fred here?". The teacher
is able to answer from the roll.

The former case is (sort of) the solution proposed above - in looking
for Fred, you walk through the room, asking each person in-turn "are you
Fred?".

The latter is the case for Node and what you were hoping to implement.

Thus, an alternate approach is to keep a register of nodes. Note that
this is more than a list, because each element of the list (each node)
is also identified (on the list) by its name. So, two pieces of
(related) data: the id of the node, and the node itself - the name of
the person and the person him-/her-self.

Assuming you only have one ID that will be used to access a node,
Python's built-in dict[ionary] data-structure will provide the advantage
of direct-access (instead of going through (on average) half the nodes,
asking each one in-turn, are you ...

So:

> NODE = Node()
> NODELIST = []
> 
> NODE.NO = 10
> NODELIST.append(NODE)

becomes:

graph = dict{}  # could be written as: graph = {}
node10 = Node( 10 )
graph[ node.id ] = node10

or even:

graph[ 20 ] = Node( 20 )

if you don't need lots of nodes 'hanging around' outside of the 'list'
(actually a dict) representing the graph.


Then:

> NO1 = 20
> if NO1 not in NODELIST[:].NO  ???

becomes a single line:

the_node_required = graph[ 20 ]

where "20" is the search-criteria.

Does that make sense?


If it does, and when you realise that you'd like to do more with the
graph than retrieve single nodes (and more-importantly, should you want
(or dare) to delve further into the depths of Object-Oriented
Programming) you could declare a second class (graph) containing a
number of "methods". If one of the methods implemented is __contains__()
then you could indeed ask:

if 20 in graph:

ie "is Fred in-class today?"
but just as we would ask "is Fred here?" rather than "is someone
identified by the name 'Fred' here?", it would seem better form to write:

if node( 20 ) in graph:

ie is there a node with the id of 20, somewhere within the graph?


Such might involve sub-classing OrderedDict, UserDict, or even UserList,
from the Collections library in the (provided/"batteries-included")
Python Standard Library: https://docs.python.org/3/library/collections.html

If needed, the extra methods you choose to implement might include such
functionality as connecting nodes 10 and 20 with a path/edge, being able
to traverse edges, and so-on...

Thus, we've covered two categories of class/object: one, a 'data-class'
which contains data about a single node; the other a 'collection-class'
which contains multiple nodes making-up the graph. A useful distinction
and a common related-pair of data-constructs!
-- 
Regards,
=dn
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-23 Thread Khairil Sitanggang
Thank you.
I did it as you said. Yes, I forgot to create a new object Node() for each of 
the 3 instances.

The reason I wanted to do as I asked was that I expected Python provides that 
convenient feature (since it is a high level language). I use Matlab a lot and 
it is so rich of features that allow  us to process object array in many 
different ways.

Anyway, as I said, I just started playing with Python, and I like it so much. 
Thanks to Visual Studio Code making coding very enjoyable.



Get Outlook for iOS<https://aka.ms/o0ukef>

From: Python-list  on behalf 
of MRAB 
Sent: Saturday, July 23, 2022 4:57:34 PM
To: python-list@python.org 
Subject: Re: Object in List : how?

On 23/07/2022 05:28, Khairil Sitanggang wrote:
> Hello Expert:
>
> I just started using python. Below is a simple code.  I was trying to check
> if, say, NO1 is not in the NODELIST[:].NO
> How can I achieve this purpose?
>
> Regards,
> -Irfan
>
>
> class Node:
>  def __init__(self):
>  self.NO = 0
>  self.A = 20
>
> NODE = Node()
> NODELIST = []
>
> NODE.NO = 10
> NODELIST.append(NODE)
>
> NODE.NO = 20
> NODELIST.append(NODE)
>
> NODE.NO = 30
> NODELIST.append(NODE)
>
>
> NO1 = 20
> if NO1 not in NODELIST[:].NO  ???

No, you can't do it that way. You have to iterate through the list and
check each member individually:

 if any(NO1 == N.NO for N in NODELIST):

And another thing: you've created only 1 node, and you're changing it
each time before adding it to the list, so the list ends up with 3
references to the _same_ object.
--
https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Object in List : how?

2022-07-23 Thread MRAB

On 23/07/2022 05:28, Khairil Sitanggang wrote:

Hello Expert:

I just started using python. Below is a simple code.  I was trying to check
if, say, NO1 is not in the NODELIST[:].NO
How can I achieve this purpose?

Regards,
-Irfan


class Node:
 def __init__(self):
 self.NO = 0
 self.A = 20

NODE = Node()
NODELIST = []

NODE.NO = 10
NODELIST.append(NODE)

NODE.NO = 20
NODELIST.append(NODE)

NODE.NO = 30
NODELIST.append(NODE)


NO1 = 20
if NO1 not in NODELIST[:].NO  ???


No, you can't do it that way. You have to iterate through the list and 
check each member individually:


if any(NO1 == N.NO for N in NODELIST):

And another thing: you've created only 1 node, and you're changing it 
each time before adding it to the list, so the list ends up with 3 
references to the _same_ object.

--
https://mail.python.org/mailman/listinfo/python-list