python: how do I call a function without changing

2019-08-04 00:54发布

If I have a function:

def foo(self, a, b):
    c = a + b
    return c

How can I call foo without changing c in the function? So let's say I call foo in another function:

def bar(self):
    z = self.foo(2, 4)
    return (z)

and then I want to call foo again in a separate function, but I want c from the time 'bar' was called.

def baz(self):
    self.foo(?, ?) # trying to just get c, without any changes.

Basically, i'm trying to keep an account in class such that other classes can have access to the same account; just a simple balance, adding and subtracting money.

Thanks.

6条回答
老娘就宠你
2楼-- · 2019-08-04 01:34

why not store the result in self, and have optional arguments to see if it should to any calculations?

Something like:

def foo(self, *args):
    if args:
        self.c = 0
        for value in args:
            self.c += value

    # In case `self.c` is not set yet, then use default of `0`
    return getattr(self, 'c', 0)

Now if you call foo with arguments, it will add all arguments and store it. If called with no arguments it will return the last stored value.

查看更多
ら.Afraid
3楼-- · 2019-08-04 01:35

I've taken what Rohan provided for an answer and come up with the following. It seems to work, although there may be a better/preferred way to accomplish this.

The following code allows me to keep track an account balance across multiple classes and methods.

import os

class Foo():
    def __init__(self):
        self.stored_end = 0

    def account(self, a, b):
        c = float(a) + b
        print a
        print b
        print c
        self.stored_end = c
        print self.stored_end

    def testy(self, q, v):
        print "\n"
        print " _ " * 10
        z = float(q) + v
        print self.stored_end   
        self.stored_end = self.stored_end + z
        print " _ " * 10
        print self.stored_end

class Bar():
    def __init__(self):
        pass

    def zippy(self, a, b):
        print " _ " * 10
        print "this is zippy"
        foo.testy(a, b)

class Baz():
    def __init__(self):
        pass

    def cracky(self, g, m):
        y = g + m
        print " _ " * 10
        print "calling stored_end"
        foo.stored_end = foo.stored_end + y
        print " _ " * 10
        print "this is cracky"
        print "y = %r" % y
        print foo.stored_end    

os.system("clear")      
foo = Foo()
foo.account(5, 11)
foo.testy(100, 100)
bar = Bar()
bar.zippy(10, 100)
baz = Baz()
baz.cracky(1000, 1)
查看更多
我只想做你的唯一
4楼-- · 2019-08-04 01:45

c is local to the function and not static. That means that every time the function exits, c gets garbage collected. Why don't you just store the value of c as computed the first time? It seems like the obvious answer.

查看更多
forever°为你锁心
5楼-- · 2019-08-04 01:47

Store c as class variable or global and override the function to return old value.

e.g.

class SomeClass:
     def foo(self, a=None, b=None):
        if a and b:
            c = a + b
            self.stored_c = c
            return c
        return self.stored_c

Note: you will have to handle when to update stored_c and any concurrency issues.

Update: WRT glglgl's comment, updated for method overloading.

查看更多
Juvenile、少年°
6楼-- · 2019-08-04 01:48

You'll need to have some construct to save the last result. E.g., you can do some wrapper to the function which does

def keep_result(func):
    from functools import wraps
    @wraps(func)
    def wrapper(*a, **k):
        res = func(*a, **k)
        wrapper.last_result = res
        return res
    wrapper.func = func # makes it easy to bypass
    return wrapper

This is a so-called "decorator function".

Now if you do

@keep_result
def foo(self, a, b)
    c = a + b
    return c

the function foo (itself, not its result!) is used as an argument for keep_result() which creates a new function wrapper() which calls the original function, saves its result into an attribute and returns the result. This new function is returned in place of the original function foo().

So you can say

normal_result = foo(whatever)

and then do

saved_result = foo.last_result

and you get the same.

查看更多
何必那么认真
7楼-- · 2019-08-04 01:55

It seems like the thing you want is a cached property. You can make a decorator implementing descriptor that does that for you as a generic thing to use in future:

def cachedproperty(f):
    """Cached property.

    Calculated once - serves forever.
    """

    def get(self):
        try:
            return self._properties[f]
        except AttributeError:
            self._properties = {}
            self._properties[f] = f(self)
            x = self._properties[f]
            return x
        except KeyError:
            x = self._properties[f] = f(self)
            return x

    return property(get)

Let's look at the example:

 class X(object):
     x = 0

     def __init__(self, x):
         self.x = x

     @cachedproperty
     def y(self):
         return self.x + 6

Here are some tests.

 >>> ob = X(5)
 >>> ob.y
 11
 >>> ob.x = 10
 >>> ob.y
 11
查看更多
登录 后发表回答