简体   繁体   中英

Calling a Variable from Another Function in Python

I have spent the past few hours reading around but I'm not really understanding what I am sure is a very basic concept: passing values (as variables) between different functions.

class BinSearch:
    def __init__(self,length,leng,r,obj_function,middle):
        self.length = length
        self.leng = leng
        self.r = r
        self.obj_function = obj_function
        self.middle = middle
        self.objtobin(obj_function)

    def BinarySearch(length,leng,r):
        mid = np.arange(0,len(length),1)
        middle = min(mid) + (max(mid)-min(mid))//2
        L_size = []
        L = length[middle]
        L_size.append(L)
        return L

    def objtobin(self,obj_function):
        # length,leng,middle = BinSearch.BinarySearch()
        if (obj_function>=0.98):
            return BinSearch.BinarySearch(self.length,min(leng),self.middle-1)
        else:
            return BinSearch.BinarySearch(self.length,self.middle+1,max(leng))
BinSearch.objtobin(obj_function=max(objectivelist))

When I run the above code, BinSearch.objtobin code gives "objtobin() missing 1 required positional argument: 'self'" What should I do for this error? Thanks for help!

Firstly, thank you all for your help. But I do not understand how should I change this code

I have started modifying your code so that it would run without errors, but there are a few other mistakes in there as well, and I have not tried to make sense of all your parameters.

It would look something like this, but I will explain below.

# --- OP's attempt that fails ---
# BinSearch.objtobin(obj_function=max(objectivelist))
# -- -- -- -- -- -- -- -- -- -- --

# --- Using an instance ---
figure_this_out_yourself = 100
# this variable is a placeholder for any parameters I had to supply
myBinSearchInstance = BinSearch(
        length = figure_this_out_yourself,
        leng = [figure_this_out_yourself],
        r = figure_this_out_yourself,
        obj_function = figure_this_out_yourself,
        middle = figure_this_out_yourself)
myBinSearchInstance.objtobin(obj_function = max(objectivelist))

There is one important concept to be grasped here: self .

Let us consider this simple example function here, which shall always output a number one larger than last time.

counter = 0
def our_function ():
    global counter
    counter = counter + 1
    return counter

print(our_function())

It is okay as it is, but it uses a global variable to keep track of its state. Imagine using it for two different purposes at the same time. That would be chaos! So instead, we package this inside a class.

# unfinished apprach
counter = 0
class OurClass:
    # This is called a static method
    def our_function ():
        global counter
        counter = counter + 1
        return counter

print(our_function())

When we try to run this, we run into a problem.

NameError: name our_function is not defined

This happens because it is now accessible only within that class. So we need to call it as

print(OurClass.our_function())

That makes it okay to have functions with the same name around - as long as they are in different classes - but it does not solve our chaos for using our_function multiple times at once. What we want is basically to have two independent counter variables. This is where instances come into play: Of course we could manually create a second function that uses a second global variable, but that gets out of hand quickly when you use it more and more.

So let's move counter inside our class.

class OurClass:
    counter = 0
    def our_function ():
        global counter
        counter = counter + 1
        return counter

You guessed it - now counter is no longer defined:

NameError: name counter is not defined

So let us pass the instance variable that we want to use into the function as a parameter. And then use that instance to get its counter:

class OurClass:
    counter = 0

    def our_function (the_instance):  
        the_instance.counter = the_instance.counter + 1
        return the_instance.counter

myInstance = OurClass()
mySecondInstance = OurClass()
print(OurClass.our_function(myInstance))
print(OurClass.our_function(mySecondInstance))

And successfully, both print statements print 1 !

But that is a bit annoying because this the_instance is something that is not like the other arguments. To make it distinct, python allows us to avoid the first parameter and instead provide it as the receiver. Both of these work:

print(myInstance.our_function())
print(OurClass.our_function(mySecondInstance))

Python uses a very strong convention for these parameters. Instead of the_instance , call it self . See Why is self only a convention? .

class OurClass:
    counter = 0
    def our_function (self):  
        self.counter = self.counter + 1
        return self.counter
myInstance = OurClass()
mySecondInstance = OurClass()
print(myInstance.our_function())
print(mySecondInstance.our_function())

Now we're almost done! Just one thing left to understand: Where do the parameters of __init__() come from?
They are passed to __init__() from the line where we construct it. So let me demonstrate by adding a starting value for our counter :

class OurClass:
    counter = 0

    def __init__ (self, starting_value):
        self.counter = starting_value

    def our_function (self):  
        self.counter = self.counter + 1
        return self.counter

myInstance = OurClass(5)
mySecondInstance = OurClass(10)
print(myInstance.our_function())
print(OurClass.our_function(mySecondInstance))

This prints 6 and 11 .


But what do those comments mean with @staticmethod ? For that, see Difference between staticmethod and classmethod and Do we really need @staticmethod decorator in python to declare static method .
In short: You can annotate any method in a class with either @staticmethod or @classmethod .

  • @staticmethod means that it can be called like myInstance.foo() when OurClass.foo() does not take self as a parameter. Without that decorator, you could only call it as OurClass.foo() but not as myInstance.foo() .
  • @classmethod means that it can be called like myInstance.foo() and it does not get myInstance as the first parameter, but instead the class of myInstance , which is OurClass . That allows you eg to define alternative constructors . Also, a class method is not inherited when you subclass it, so it won't be mistakenly called.

The comments are pointing out that you could also use a @staticmethod and avoid creating an instance. For that, you would have to not use any variables in the class itself - but you aren't using those for long anyways, so you could all pass them as parameter to the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM