0

I have try to append a List of Classes inside another List of Classes as the code below.

class Power:                                                                                                                
  def __init__(power, name='VDD', value='1.8'):                                                                             
  | power.name    = name                                                                                                    
  | power.value   = value                                                                                                   
                                                                                                                            
class Condition:                                                                                                            
  def __init__(condition, name='TYP', power=[]):                                       
  | condition.name    = name                                                                                                                                                                                             
  | condition.power   = power                                                                                                                                                                                                                                                                                                       
  def addpower(condition, power, value):                                                                                    
  | condition.power.append( Power( name=power, value=value ) )                                                              
                                                                                                                            
class WorkingCell:                                                                                                          
  def __init__(cell, name='name', cond=[]):                                                                                                            
  | cell.name       = name                                                                                                                                                                                                
  | cell.cond       = cond                                                                                                  
  def setpower(cell, cond, power, value):                 
  | for x in cell.cond:                                   
  | ¦ if( x.name == cond ):                                
  | ¦ ┆ x.addpower( power=power, value=value )          
  | ¦ ┆ break

I added two conditions into cell as below.

cell.cond.append( Condition( name='FAST' ) )
cell.cond.append( Condition( name='SLOW' ) )

Afterward, I appended two Power class's elements into seperate condition, according to condition name.

cell.setpower( cond='FAST', power='VDD', value='0.9' )
cell.setpower( cond='FAST', power='VCCQ', value='1.9' )
cell.setpower( cond='SLOW', power='VDD', value='0.65' )
cell.setpower( cond='SLOW', power='VCCQ', value='1.65' )

As a result, it was appended all that powers into two conditions as well (I formatted print-out result by myself for easier debugging).

{name : 'cell_1', 
 cond : {name : 'FAST', power : {name : 'VDD', value : '0,9'
                                 name : 'VCCQ', value : '1.9'
                                 name : 'VDD', value : '0.65'
                                 name : 'VCCQ', value : '1.65'}
         name : 'SLOW', power : {name : 'VDD', value : '0,9'
                                 name : 'VCCQ', value : '1.9'
                                 name : 'VDD', value : '0.65'
                                 name : 'VCCQ', value : '1.65'}
        }
}

Then, I checked it by address where all that Power objects were storing. Surprisingly, all of that powers of two individual conditions were stored at the same address.


{name : 'cell_1', 
 cond : {name : 'FAST', power : {<__main__.Power object at 0x2b0d6d906c88>
                                 <__main__.Power object at 0x2b0d6d906d68>
                                 <__main__.Power object at 0x2b0d6d906da0>
                                 <__main__.Power object at 0x2b0d6d906e10>}
         name : 'SLOW', power : {<__main__.Power object at 0x2b0d6d906c88>
                                 <__main__.Power object at 0x2b0d6d906d68>
                                 <__main__.Power object at 0x2b0d6d906da0>
                                 <__main__.Power object at 0x2b0d6d906e10>}
        }
}                            

I am wondering that why I already accessed to individual conditions according to their own names, but it still appended Power objects into both conditions.

EDIT: As Aagam Sheth, I missed explaining my expected output. Hence, the description below is one.

{name : 'cell_1', 
 cond : {name : 'FAST', power : {name : 'VDD', value : '0,9'
                                 name : 'VCCQ', value : '1.9'}
         name : 'SLOW', power : {name : 'VDD', value : '0.65'
                                 name : 'VCCQ', value : '1.65'}
        }
}
  • Can you provide the expected output. And how did you get the print-out results. – Aagam Sheth Apr 16 '21 at 03:30
  • Dear @AagamSheth, I added my expected output as your requirement. However, as I mentioned above, I formatted the output to explain it clearer. My own code have more data to show and it is more complicated to describe all instead of focusing on my editted code above to show the problem clearer. Yet, I use `attrs=vars(cell)` and `attrs=vars(cell.cond)` to convert all items. Then, I use `print( ', '.join("%s: %s" % item for item in attrs.items()))` to print them out. – Đức Minh Phạm Apr 16 '21 at 03:54
  • @ĐứcMinhPhạm I have edited my answer below. It solves your problem with attrs=var(cell.cond). The issue is with __init__ method where you have supplied a mutable default parameter list. Please change it as below described in my answer – Aagam Sheth Apr 16 '21 at 04:06

1 Answers1

0

This is the expected output.

Name: cell_1, 
    Condition: {
        Name: FAST, Power: {
             Name: VDD, Value: 0.9
             Name: VCCQ, Value: 1.9
        Name: SLOW, Power: {
             Name: VDD, Value: 0.65
             Name: VCCQ, Value: 1.65
  
// Memory reference of power objects are also different
Name: cell_1, 
    Condition: {
        Name: FAST, Power: {
         [<__main__.Power object at 0x000001F46DBFE880>, 
          <__main__.Power object at 0x000001F47E10EF40>],
        Name: SLOW, Power: {
         [<__main__.Power object at 0x000001F47E2C6F40>, \
          <__main__.Power object at 0x000001F47E2C6400>],

I guess this is what you want.

Some insignificant changes:

  1. first parameter of all the methods to self as it is the convention and power, condition, cell was confusing.
  2. I used the dunder method __str__ to print for simplicity cause i dont know how you got that output.
  3. I changed the method names to better suit the pep8.

Significant changes :

  1. The default parameter is set to list in the __init__ methods. CHange that to None and handle the None input afterward to initialize a list.

The source for above output.

class Power:
    def __init__(self, name='VDD', value='1.8'):
        self.name = name
        self.value = value

    def __str__(self):
        print('\t\t\t', f'Name: {self.name}, Value: {self.value}')
        return ''


class Condition:
    def __init__(self, name='TYP', power=None): # handled the mutable default argument
        if power is None: # handled the mutable default argument
            power = []
        self.name = name
        self.power = power

    def add_power(self, power, value):
        self.power.append(Power(name=power, value=value))

    def __str__(self):
        print(f'Name: {self.name}, Power: {{')
        print('\t\t', f'{[str(pow) for pow in self.power]},')
        return ''


class WorkingCell:
    def __init__(self, name='name', cond=None): # handled the mutable default argument
        if cond is None:  # handled the mutable default argument
            cond = []
        self.name = name
        self.cond = cond

    def set_power(self, cond, power, value):
        for x in self.cond:
            if x.name == cond:
                x.add_power(power=power, value=value)
                break

    def __str__(self):
        print(f'Name: {self.name}, \n Condition: {{')
        print('\t', f'{[str(condi) for condi in self.cond]}')
        return ''


if __name__ == '__main__':
    cell = WorkingCell(name='cell_1')  #  initialized the cell
    cell.cond.append(Condition(name='FAST'))
    cell.cond.append(Condition(name='SLOW'))
    cell.set_power(cond='FAST', power='VDD', value='0.9')
    cell.set_power(cond='FAST', power='VCCQ', value='1.9')
    cell.set_power(cond='SLOW', power='VDD', value='0.65')
    cell.set_power(cond='SLOW', power='VCCQ', value='1.65')

    attrs = vars(cell)
    print(', '.join("%s: %s" % item for item in attrs.items()))
    attrs = vars([condi for condi in cell.cond][0])
    print(', '.join("%s: %s" % item for item in attrs.items()))
    attrs = vars([condi for condi in cell.cond][0])
    print(', '.join("%s: %s" % item for item in attrs.items()))

**For reference: **

  1. Default Parameter Values in Python
  2. “Least Astonishment” and the Mutable Default Argument
Aagam Sheth
  • 685
  • 7
  • 15