0

I tried to solve the following problem the last few hours but it didn't work out.

I have two python files, one for creating classes and the second one for actually working with those classes.

I create the class hh (=households) as follows but we can focus only on the fltCash attribute because that's where the issue occurs; I used setters/getters only for this attribute at the bottom of the code as I was hoping that it could fix this issue.

# agent: households
class hh(agent):
  def __init__(self, intId = 0,
             # Income
             fltCash = [100],
             fltWage = [25],
             fltInterest = [25],
             fltDividend = [25],
             fltTransfer = [25],

             # Employment
             intEmployerId = [-1],

             # MinWage Preferences
             fltIncomeweight = 1,
             fltLoyalty2Employer = [-1], 

             # Utility Function
             fltPref_a = 0.5,
             fltPref_b = 1,

             # Variables
             intMinWage = -1
             ):

    # def in superclass agent
    agent.__init__(self, intId)

    # def in childclass hh
    self.fltCash = fltCash
    self.fltWage = fltWage
    self.fltInterest = fltInterest
    self.fltDividend = fltDividend
    self.fltTransfer = fltTransfer
    self.intEmployerId = intEmployerId
    self.fltIncomeweight = fltIncomeweight
    self.fltLoyalty2Employer = fltLoyalty2Employer
    self.fltPref_a = fltPref_a
    self.fltPref_b = fltPref_b
    self.intMinWage = intMinWage

    ## Setter / Getter Section
    @property
    def fltCash(self):
        return self.__fltCash

    @fltCash.setter
    def fltCash(self, value):
        if value.isdigit():
            self.__fltCash = value
        else:
            print("Ungueltiger Wert fuer fltCash: {}".format(value))

In another file I define my main class where I create an object from this class. However, right after initializing the fltCash attribute of this object contains not a list with only the default value but a list which various integers which seem to be random to me.

Has anyone a clue what's the reason for this behaviour and/or how to avoid it?

Any help would be highly appreciated.

Best Lukas

EDIT: Here is a simplified version of my code, I figure it's very stupid bug in my code but I can't find it:

import random as rd

class agent:
  def __init__(self, intId = 0):
    self.intId = intId

class hh(agent):
  def __init__(self, intId = 0, fltCash = [100]):

    # def in superclass agent
    agent.__init__(self, intId)

    # def in childclass hh
    self.fltCash = fltCash


class firm(agent):
   def __init__(self, intId = 0, fltCurrentAssets = [50]):

    # def in superclass agent
    agent.__init__(self, intId)

    # def in childclass hh
    self.fltCurrentAssets = fltCurrentAssets

def main(): 
  ### create agents
  luke = hh(intId=3)
  univie = firm(intId=2)

  ## HERE I'D EXPECT [100] AND [100]
  print(luke.fltCash)
  print(univie.fltCurrentAssets)

  ### action
  i = 0
  while True:
      fltTransfer = rd.randrange(0,51)

      if luke.fltCash[i] > univie.fltCurrentAssets[i]:
          luke.fltCash.append(luke.fltCash[i] - fltTransfer)
          univie.fltCurrentAssets.append(fltTransfer + univie.fltCurrentAssets[i])
      else:
          luke.fltCash.append(fltTransfer + luke.fltCash[i])
          univie.fltCurrentAssets.append(univie.fltCurrentAssets[i] - fltTransfer)
      i += 1

      if luke.fltCash[i] < 0 or univie.fltCurrentAssets[i] < 0:
          print("Game over! Luke: {}, \n Univie: {}".format(luke.fltCash,\
              univie.fltCurrentAssets))
          del luke
          del univie
          break
      if i > 10: 
          del luke
          del univie
          break
Wolf
  • 9,679
  • 7
  • 62
  • 108
Lukas
  • 1
  • 1
  • One more thing: I figured that this issue disappears if i explicitly initialize the fltCash attribute within the main class. But I figure that there must be another way to solve this.. – Lukas Mar 22 '18 at 08:57
  • Try to change the codes in init function like self.__fltCash = fltCash, instead of self.fltCash, due to you may cause nested attributes error. – Menglong Li Mar 22 '18 at 08:59
  • [Default Parameter Values in Python](http://effbot.org/zone/default-values.htm "Default Parameter Values in Python") – Wolf Mar 22 '18 at 09:10
  • To better focus on the actual problem, reduce your example as far as possible: A class with just one member and the `__init__` function. Is the strange behaviour still there? Now try to remove the class around `__init__` change it to a simple function. – Wolf Mar 22 '18 at 09:14
  • @Wolf I think this does not cause the issue as I create my object within each call: def main_test(): luke = cl.hh(intId=3) – Lukas Mar 22 '18 at 09:16
  • Can you build a MCVE for this? [How to create a Minimal, Complete, and Verifiable example - Help Center - Stack Overflow](https://stackoverflow.com/help/mcve "How to create a Minimal, Complete, and Verifiable example - Help Center - Stack Overflow") – Wolf Mar 22 '18 at 09:19
  • @Lukas *`cl.hh(intId=3)`* -- in this example `fltCash` isn't affected – Wolf Mar 22 '18 at 09:29
  • @Wolf I added a simplified version of the code in the question above. I figure that my issue is strongly related to the link you posted but I thought python would remove both objects at the end of my code. Hence it must create brand new objects whenever I call my function for another time. However, python reuses the old attribute lists.. – Lukas Mar 22 '18 at 09:43
  • 1
    I hope it already counts as MCVE :-) thank you very much for your help! – Lukas Mar 22 '18 at 09:44
  • Exactly this (reusing objects) is described in the Python documentation. Read [8.6. Function definitions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions). After 40+ lines you'll read **Default parameter values are evaluated from left to right when the function definition is executed** (more closely: ***when* the function definition is executed**) some explanation follows – Wolf Mar 22 '18 at 09:49
  • It's maybe more `MCVE`ish than the initial code, but you can do much more to it. I confess that's real work but I believe it's good to do it yourself. – Wolf Mar 22 '18 at 09:56
  • Ok I understand! But the issue is alive even if i write the code similar but not in an explicit function. But there must be a way to delete an object with all its attributes forever. But with 'del', this not the case.. – Lukas Mar 22 '18 at 10:07
  • maybe this `def f(x=None): x = x or [1]; x.append('x'); return x;` could help. – Wolf Mar 22 '18 at 15:10

0 Answers0