#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    76
    Rep Power
    2

    Weird, unintentional looping effect


    Code:
    class room():
    	def __init__(self,name='NONAME',sub='NOSUB',entrytext='The game appears to be broken.',button_bindings=[]):
    		self.name=name
    		self.sub=sub
    		self.entrytext=entrytext
    		self.button_bindings=button_bindings
    	def enter(self):
    		curr_room=self
    
    def link(room1,room2,cost=1):
            room1.button_bindings.append((room2.enter,cost))
            room2.button_bindings.append((room1.enter,cost))
    
    global curr_room
    curr_room=room()
    
    #for para in room.entrytext:
    #        for line in wrap(para,64):
    #                print(line)
    #        print('')
    
    hallway=room(name='Laboratories',
            sub='Hallway',
            entrytext=())
    
    testroom=room(name='Laboratories',
    	sub='Test Room 1',
    	entrytext=("""Banana banana banana banana"""))
    
    print(hallway.button_bindings)
    print(testroom.button_bindings)
    link(hallway,testroom)
    print('Linked.')
    print(hallway.button_bindings)
    print(testroom.button_bindings)
    So, since I can't just put the entry binding in the initial call (the second room will never be instantiated, no matter which order I start in) I created a 'link' function that should append to a list of button bindings a method for that room's entry method which I could then attach to a real button.
    For some odd reason, the link method gives each room not only the first tuple I appended, but also the other one.

    This is frankly just plain weirding me out at this point. Any help?
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,894
    Rep Power
    481
    Several threads recently addressed this issue. As python imports a module it executes all statements with no indentation. Unless it's a class definition. Then python executes code at the next indentation level.

    (of course if python finds an "if" or other block starting statement at the left hand side it evaluates that block. Which is why
    Code:
    if __name__=='__main__':
        print('I am the main module')
    works.)

    You've effectively written this, in which the default argument to shareable_list was evaluated once when the module loaded. You can also look up the id.
    Code:
    class c:
        '''
            >>> o.shareable_list.append('shared data')
            >>> o.private_list.append('private.  Really.')
            >>> q.private_list.append('PRIVY TO q')
            >>> print(o)
            private and shareable:  <['private.  Really.']>   <['shared data']>
            >>> print(p)
            private and shareable:  <[]>   <['shared data']>
            >>> print(q)
            private and shareable:  <['PRIVY TO q']>   <['a', 'n', 'y', ' ', 'o', 'b', 'j', 'e', 'c', 't']>
            >>> 
        '''
        def __init__(self,private_list = None, shareable_list=[]):
            self.shareable_list = shareable_list
            self.private_list = [] if private_list is None else private_list
        def __str__(self):
            return'private and shareable:  <{}>   <{}>'.format(str(self.private_list), str(self.shareable_list))
    Let's play a little game. Python works as I expect.
    Code:
    >>> def f():
    ...     return lambda a=[]:a
    ... 
    >>> id(f()())
    140017082308656
    >>> a=list(range(1000000))  # consume some memory
    >>> id(f()())
    140017082308656
    >>>
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    39
    Rep Power
    3

    Default arguments


    Although it looks weird there is no looping going on. Instead what has happened is your default argument has resulted in every class pointing to the same list unless you specify a list as part of the initialisation. That is
    Code:
    hallway.button_bindings == test.button_bindings # returns True
    Thus your link function is appending to the same list. Two easy fixes; you could always included the button_bindings in the initialisation although this defeats the object of having default arguments, ie
    Code:
    hallway = room("Lab","Hallway",button_bindings=[])
    Second simple fix which makes sense would be to not allow button bindings to be passed in, ie
    Code:
    def __init__ (self,name='NONAME',sub='NOSUB',entrytext='The game appears to be broken.'):
        self.name = name
        self.sub = sub
        self.entrytexy = self.entrytext
        self.button_bindings = list()
    If you do want to allow button bindings to be initialised along with the object you could code it something like the following.
    Code:
    def __init__ (self,name='NONAME',sub='NOSUB',entrytext='The game appears to be broken.',button_bindings=None):
        self.name = name
        self.sub = sub
        self.entrytexy = self.entrytext
        self.button_bindings = list()
        if button_bindings:
            self.button_bindings.append(button_bindings)
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    76
    Rep Power
    2
    Thanks b4 and Quackajack.

    I do want arguments to be passed in; there are going to be more button binding types than simply the link bindings, and for those it'll be much easier to initialize them on instantiation.

    Once more, thanks.

IMN logo majestic logo threadwatch logo seochat tools logo