Python Forum
creating a variable in a method and using in another method - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: creating a variable in a method and using in another method (/thread-21544.html)



creating a variable in a method and using in another method - ridgerunnersjw - Oct-04-2019

Good evening......
Can someone please tell me the correct way to create a variable within a method and then be able to re-use that variable internal to the class within another method? As an example I tried this below with __usb and __SG....in particular __SG gets defined in open method and I want to re-use it in close method...Thank you for all responses

	def open(self):
		k = visa.ResourceManager()
		try:
			__usb = k.list_resources()[1]
		except IndexError:
			print ('Make sure equipment is turned on')			
		try:
			__SG = k.open_resource(__usb)
		except:
			print ('USB Resource could not be opened')
		else:		
			print ('Success opening USB resource')
		
	def close(self):
		__SG.close()
		print ('Success closing resource')	



RE: creating a variable in a method and using in another method - stullis - Oct-04-2019

To do that, you would need to instantiate the variable as a field:

class Example:
    def do_stuff(self):
        self.x = 22

    def do_more_stuff(self):
        return self.x * 4
Your code has a potential bug. Because __SG and __usb are in try blocks, there is no guarantee they will be instantiated. In turn, if __usb isn't instantiated, line 8 will raise an error; if __SG isn't instantiated, close() will raise an error.


RE: creating a variable in a method and using in another method - burningkrome - Oct-04-2019

Well, the first observarion is, these appear to be methods within a class (thus the use of "self" in the "def open(self):" and "def close(self):". The "self" refers to the object of that class, after it has been instantiated. In order for a variable of that class's instantiated object to be visible to something outside the instantiated object for that class, you must tie it to the "self."

I.e.
class MyObject:
    def __init__(self):
        self.k = visa.ResourceManager()

    def open(self):
        
        try:
            self.__usb = self.k.list_resources()[1]
        except IndexError:
            print ('Make sure equipment is turned on')          
        try:
            self.__SG = self.k.open_resource(__usb)
        except:
            print ('USB Resource could not be opened')
        else:       
            print ('Success opening USB resource')
             
    def close(self):
        self.__SG.close()
        print ('Success closing resource') 
    
>>> import MyObject
>>> o = MyObject()
>>> print(o.__SG) 
HOWEVER, you have named this variable with a preceding double underscore "__" this tells other developers you specifically do not want them messing with the "self.__SG" variable directly. If you DO want objects outside the class instantiated object to interact with this variable, remove the double underscore. If you really don't want things messing with it directly, sou should set a getter/setter, as such...

class MyObject:
    def __init__(self):
        self.k = visa.ResourceManager()

    @property
    def sg(self):
        try: return self.__SG
        except (ValueError, AttributeError):
            raise AttributeError("The property 'sg' has not be set.")

    @sg.setter
    def sg(self, value):
        raise AttributeError("The value of the property 'sg' can not be set externally")
    
    def open(self):
        
        try:
            self.__usb = self.k.list_resources()[1]
        except IndexError:
            print ('Make sure equipment is turned on')          
        try:
            self.__SG = self.k.open_resource(__usb)
        except:
            print ('USB Resource could not be opened')
        else:       
            print ('Success opening USB resource')
             
    def close(self):
        self.__SG.close()
        print ('Success closing resource') 
    
>>> import MyObject
>>> o = MyObject()
>>> print(o.sg)
<some value appears>
>>> o.sg = "My new value"
<raises error>



RE: creating a variable in a method and using in another method - buran - Oct-04-2019

(Oct-04-2019, 08:02 AM)burningkrome Wrote: In order for a variable of that class's instantiated object to be visible to something outside the instantiated object for that class, you must tie it to the "self."
Actually self (note that we use 'self' pure as convention, same for 'cls' to refer the class) ties it to the specific instance of the class (instance attribute), otherwise it would be class attribute accessible to all instances of the class


Some experiments to show difference between the class and instance attributes (incl. mutable vs. immutable)
class Foo:
    foo = 1
    my_list = []
    def __init__(self, bar):
        self.bar = bar
        print(f'class attribute foo at the start of __init__:{Foo.foo}')
        Foo.foo += 2
        print(f'class attribute foo after add 2 in __init__:{self.foo}')
        Foo.my_list.append(bar)
        self.my_list.append(bar*2)

    @classmethod
    def tripple(cls):
        print(f'class attribute foo beforer tripple:{cls.foo}')
        cls.foo *= 3
        print(f'class attribute foo after tripple:{cls.foo}')



spam = Foo(5)
print(f'class foo:{spam.foo}')
print(f'bar: {spam.bar}')
print(f'my_list: {spam.my_list}')
spam.tripple()
# create spam.foo instance attribute
# it overrides the  class foo attribute when you use spam.foo
spam.foo += 1
print(f'instance foo: {spam.foo}')

# class attribute still exists but is not accesible via spam.foo
spam.tripple()
print(f'instance foo:{spam.foo}')
spam.my_list.append('spam')
print('--- eggs instance ---')
eggs = Foo('eggs')
print(eggs.foo)
print(eggs.bar)
print(eggs.my_list)
Output:
class attribute foo at the start of __init__:1 class attribute foo after add 2 in __init__:3 class foo:3 bar: 5 my_list: [5, 10] class attribute foo beforer tripple:3 class attribute foo after tripple:9 instance foo: 10 class attribute foo beforer tripple:9 class attribute foo after tripple:27 instance foo:10 --- eggs instance --- class attribute foo at the start of __init__:27 class attribute foo after add 2 in __init__:29 29 eggs [5, 10, 'spam', 'eggs', 'eggseggs']
Note the behaviour of mutable class attribute my_list. It can create problems or create opportunities (e.g. shared attribute between all instances of a class)


RE: creating a variable in a method and using in another method - ridgerunnersjw - Oct-04-2019

Thanks everyone for your comments....Please bear with me as I am new to this....I am experimenting with some of the comments above, in particular

class test:
	t = visa.ResourceManager()
	
	def __init__(self):
			self.k = visa.ResourceManager()
			m = visa.ResourceManager()
I have a file sandbox.py....I import sandbox....
I can see t by using sandbox.test.t (please jump in and correct me if I go awry)...By not using the parentheses after test (ie sandbox.test() implies I have NOT created an instance, is this correct?)

Now to see k I must do something like j = sandbox.test(); j.k....Is this correct? (seems to work)

I ALSO notice here that j.t works too...guessing that is because the instance is a subset of the class so all is good

How do I access m? Does it have to live outside the instance creation (__init__)? Seems it could live anywhere assuming you don't put self tag on it....

Last question: can I declare 'self' attributes in methods other than __init__ ? and are they accessible by external and internal?

thanks again for all the help out there! Everyone is very responsive....this is a great forum


RE: creating a variable in a method and using in another method - buran - Oct-04-2019

I see big confusion with respect to OOP basics. I would suggest you check a tutorial on class basics., e.g. we have one - https://python-forum.io/Thread-Classes-Class-Basics