我正在维护一个有用的功能库,用于与我公司的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”之类的东西!是我正在寻找的。 p>
答案 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]