如何在python的定义中引用一个不是按名称的函数?

时间:2012-03-28 17:32:34

标签: python oop functional-programming

我正在维护一个有用的功能库,用于与我公司的API交互,我遇到过(我认为是)一个我无法找到答案的简洁问题。

我经常不得不从API请求大量数据,所以我做了类似的事情:

class Client(object):
    def __init__(self):
        self.data = []

    def get_data(self, offset = 0):
        done = False
        while not done:
            data = get_more_starting_at(offset)
            self.data.extend(data)
            offset += 1
            if not data:
                done = True

这很好用,如果出现可怕的错误,我可以重新启动我停止的检索。但是,由于python函数只是常规对象,我们可以执行以下操作:

def yo():
    yo.hi = "yo!"
    return None

然后我们可以稍后询问你的属性,例如:

yo.hi => "yo!"

我的问题是:我是否可以重写基于类的示例以将数据固定到函数本身,而无需按名称引用函数。我知道我可以这样做:

def get_data(offset=0):
    done = False
    get_data.data = []
    while not done:
        data = get_more_starting_from(offset)
        get_data.data.extend(data)
        offset += 1
        if not data:
            done = True
    return get_data.data

但是我想做点什么:

def get_data(offset=0):
    done = False
    self.data = [] # <===== this is the bit I can't figure out
    while not done:
        data = get_more_starting_from(offset)
        self.data.extend(data) # <====== also this!
        offset += 1
        if not data:
            done = True
    return self.data # <======== want to refer to the "current" object

是否可以通过名称之外的任何内容来引用“当前”对象? 像“这个”,“自我”或“memememe”之类的东西!是我正在寻找的。

3 个答案:

答案 0 :(得分:3)

我不明白为什么你想要这样做,但这是fixed point combinator允许你做的事情:

import functools

def Y(f):
    @functools.wraps(f)
    def Yf(*args):
        return inner(*args)
    inner = f(Yf)
    return Yf

@Y
def get_data(f):
    def inner_get_data(*args):
        # This is your real get data function
        # define it as normal
        # but just refer to it as 'f' inside itself
        print 'setting get_data.foo to', args
        f.foo = args
    return inner_get_data

get_data(1, 2, 3)

print get_data.foo

所以你正常呼叫get_data,它“神奇地”知道f意味着自己。

答案 1 :(得分:2)

你可以这样做,但是(a)数据不是每个函数调用,但是根据函数(b),用类来实现这类事情要容易得多。

如果你必须这样做,你可能会这样做:

def ybother(a,b,c,yrselflambda = lambda: ybother):
    yrself = yrselflambda()
    #other stuff

lambda是必要的,因为你需要延迟对术语ybother的评估,直到某些东西被绑定到它。

或者,也越来越无意义:

from functools import partial
def ybother(a,b,c,yrself=None):
    #whatever
    yrself.data = [] # this will blow up if the default argument is used
    #more stuff

bothered = partial(ybother, yrself=ybother)

或者:

def unbothered(a,b,c):
    def inbothered(yrself):
        #whatever
        yrself.data = []

    return inbothered, inbothered(inbothered)

最后一个版本每次都会为您提供一个不同的功能对象,您可能会喜欢它。

这几乎肯定会有内省的技巧,但它们更不值得。

答案 2 :(得分:1)

不确定这样做是什么让你获益,但是如何使用装饰器。

import functools

def add_self(f):
    @functools.wraps(f)
    def wrapper(*args,**kwargs):
        if not getattr(f, 'content', None):
            f.content = []
        return f(f, *args, **kwargs)
    return wrapper

@add_self
def example(self, arg1):
    self.content.append(arg1)
    print self.content


example(1)
example(2)
example(3)

输出

[1]
[1, 2]
[1, 2, 3]