普通功能中的“自我”?

时间:2010-07-08 20:12:54

标签: python

我有一堆函数(在任何类之外),我在其上设置了属性,如funcname.fields = 'xxx'。我希望我可以使用self.fields从函数内部访问这些变量,但当然它告诉我:

  

全局名称'self'未定义

那么......我该怎么办?我可以访问一些神奇的变量吗?喜欢__this__.fields


有些人问过“为什么?”。您可能不同意我的推理,但我有一组函数,所有函数都必须共享相同的签名(只接受一个参数)。在大多数情况下,这一个参数足以进行所需的计算。但是,在一些有限的情况下,需要一些额外的信息。我决定只在功能上设置它们,以便很容易被忽略,而不是强迫每个函数接受一长串未使用的变量。

尽管如此,如果您不关心其他参数,我现在可以使用**kwargs作为最后一个参数。哦,好吧......

编辑:实际上,我没有编写一些函数,宁可不修改以接受额外的args。通过“传入”额外的args作为属性,我的代码可以使用我的自定义函数,利用额外的args,以及第三方代码,不需要额外的args。

感谢您的快速回答:)

11 个答案:

答案 0 :(得分:11)

self不是python中的关键字,它只是一个普通的变量名。在创建实例方法时,您可以根据需要命名第一个参数,self只是一个约定。

您应该总是更喜欢将参数传递给函数而不是设置输入属性,但如果必须,您可以使用实际函数名来访问其中的变量:

def a:
    if a.foo:
        #blah

a.foo = false
a()

请参阅python function attributes - uses and abuses了解何时派上用场。 :d

答案 1 :(得分:3)

def foo():
    print(foo.fields)
foo.fields=[1,2,3]

foo()
# [1, 2, 3]

向函数添加属性没有任何问题。许多记忆器使用它来缓存函数本身的结果。

例如,请注意使用func.cache

from decorator import decorator
@decorator
def memoize(func, *args, **kw):
    # Author: Michele Simoniato
    # Source: http://pypi.python.org/pypi/decorator
    if not hasattr(func, 'cache'):
        func.cache = {}
    if kw: # frozenset is used to ensure hashability
        key = args, frozenset(kw.iteritems())
    else:
        key = args
    cache = func.cache # attribute added by memoize
    if key in cache:
        return cache[key]
    else:
        cache[key] = result = func(*args, **kw)
        return result

答案 2 :(得分:2)

示例:

>>> def x(): pass
>>> x
<function x at 0x100451050>
>>> x.hello = "World"
>>> x.hello
"World"

你可以在函数上设置属性,因为它们只是普通的对象,但实际上我从未在实际代码中看到类似的东西。

加。 self不是关键字,只是另一个变量名,恰好是该类的特定实例。隐式传递self,但明确接收。

答案 3 :(得分:2)

你无法在所有情况下正确地“访问自己的属性” - 请参阅此处how can python function access its own attributes? - 但这里有一个快速演示:

>>> def f(): return f.x
... 
>>> f.x = 7
>>> f()
7
>>> g = f
>>> g()
7
>>> del f
>>> g()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<interactive input>", line 1, in f
NameError: global name 'f' is not defined

基本上大多数方法直接或间接依赖于通过在globals中按名称查找来访问函数对象;如果删除原始功能名称,则停止工作。还有其他方法可以实现这一目标,比如定义班级或工厂 - 但是由于你的解释,很明显你并不需要这样做。

只需执行提到的关键字catch-all参数,如下所示:

def fn1(oneArg):
    // do the due

def fn2(oneArg, **kw):
    if 'option1' in kw:
        print 'called with option1=', kw['option1']
    //do the rest

fn2(42)
fn2(42, option1='something')

不确定您在处理TypeError的注释中的意思 - 使用** kw时不会出现这种情况。这种方法适用于某些python系统函数 - 检查min(),max(),sort()。最近sorted(dct,key=dct.get,reverse=True)在CodeGolf挑战中对我非常方便:)

答案 4 :(得分:1)

如果你想为可调用的“东西”设置全局参数,你总是可以创建一个类并实现__call__方法吗?

答案 5 :(得分:1)

在函数体内没有特殊的方法来引用其代码正在执行的函数对象。最简单的方法是使用funcname.fieldfuncname是其所在命名空间中的函数名称,您指明的情况就是这样 - 否则会更难。)

答案 6 :(得分:1)

这不是你应该做的事情。除了一些在调用堆栈上走来走去以及一些奇怪的内省之外,我想不出有什么方法可以做你要问的事情 - 这不是生产代码中应该发生的事情。

那就是说,我认为这实际上就是你所要求的:

import inspect

_code_to_func = dict()
def enable_function_self(f):
    _code_to_func[f.func_code] = f
    return f

def get_function_self():
    f = inspect.currentframe()
    code_obj = f.f_back.f_code
    return _code_to_func[code_obj]

@enable_function_self
def foo():
    me = get_function_self()
    print me

foo()

答案 7 :(得分:1)

虽然我同意其他人认为这可能不是一个好的设计,但问题确实引起了我的兴趣。这是我的第一个解决方案,一旦我让装饰工作,我就可以更新。就目前而言,它非常依赖于能够读取堆栈,这在所有实现中都是不可能的(关于sys._getframe()的东西不一定存在......)

import sys, inspect

def cute():
    this = sys.modules[__name__].__dict__.get(inspect.stack()[0][3])
    print "My face is..." + this.face

cute.face = "very cute"
cute()
你怎么看? :3

答案 8 :(得分:1)

您可以使用以下(可怕的丑陋)代码:

class Generic_Object(object):
    pass

def foo(a1, a2, self=Generic_Object()): 
    self.args=(a1,a2)
    print "len(self.args):", len(self.args)
    return None

...正如您所看到的那样,它可以让您按照自己的描述使用“自我”。您不能直接使用“object()”,因为您不能将{patch(*)“值”加入object()实例。但是,对象的正常子类(例如我在此处显示的Generic_Object())可以“猴子修补”

如果您希望始终使用对某个对象的引用来调用您的函数作为可能的第一个参数。您可以先将默认参数放在后面,然后输入* args和可选的** kwargs参数(在调用此函数期间,可以通过该参数传递任何其他参数或字典)。

就像我说 丑陋 一样。请不要发布任何这样的代码或与Python社区中的任何人共享。我只是在这里展示它是一种奇怪的教育活动。

实例方法就像Python中的函数一样。但是,它存在于类的名称空间内(因此必须通过实例... myobject.foo()进行访问)并且通过引用“self”调用它(与“this”指针相似) C ++)作为第一个参数。还有一个方法解析过程,它使得解释器搜索实例的命名空间,然后是它的类,然后是每个父类,依此类推......通过继承树。

使用传递给它的任何参数调用未绑定的函数。不能对参数列表进行任何自动预先设置的对象/实例引用。因此,用名为“self”的初始参数编写函数是没有意义的。 (这是合法的,因为Python没有对名称“self”赋予任何特殊含义。但是没有意义,因为函数的调用者必须手动提供对参数列表的某种对象引用,并且它根本不清楚应该是什么只是一些离奇的“Generic_Object”然后在全局变量空间中浮动?)。

我希望稍微澄清一下。听起来你对Python和其他面向对象系统的工作原理有一些非常根本的误解。

  • (“Monkey patching”是一个术语,用于描述对象属性的直接操作 - 或“实例变量”,代码不是对象为实例的类层次结构的一部分)。

答案 9 :(得分:1)

作为另一种选择,您可以将函数转换为绑定类方法,如下所示:

class _FooImpl(object):
    a = "Hello "
    @classmethod
    def foo(cls, param):
        return cls.a + param
foo = _FooImpl.foo

# later...
print foo("World") # yes, Hello World

# and if you have to change an attribute:
foo.im_self.a = "Goodbye "

如果您希望函数共享属性namespaecs,您只需将它们作为同一个类的一部分即可。如果没有,请给每个人自己的班级。

答案 10 :(得分:0)

如果函数是在任何类之外定义的,那么你究竟希望“自我”指向什么?如果您的函数需要一些全局信息才能正确执行,您需要以参数的形式将此信息发送到函数。

如果希望函数能够识别上下文,则需要在对象范围内声明它。

相关问题