Re: Object in List : how?
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?
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?
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?
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?
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?
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