Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 函数如何访问自己的属性?_Python_Function_Scope_Closures_Attributes - Fatal编程技术网

Python 函数如何访问自己的属性?

Python 函数如何访问自己的属性?,python,function,scope,closures,attributes,Python,Function,Scope,Closures,Attributes,是否可以从函数范围内访问python函数对象属性? e、 让我们吃点东西吧 def f(): return SOMETHING f._x = "foo" f() # -> "foo" 现在,如果我们想要返回x属性内容“foo”,那么必须是什么?如果可能的话(简单地说) 谢谢 更新: 我还想做以下工作: g = f del f g() # -> "foo" 更新2: 声明这是不可能的(如果是这种情况)以及为什么,比提供一种方法来伪造它

是否可以从函数范围内访问python函数对象属性?

e、 让我们吃点东西吧

def f():
    return SOMETHING

f._x = "foo"
f()           # -> "foo"
现在,如果我们想要返回x属性内容“foo”,那么必须是什么?如果可能的话(简单地说)

谢谢

更新:

我还想做以下工作:

g = f
del f
g()          # -> "foo"
更新2:

声明这是不可能的(如果是这种情况)以及为什么,比提供一种方法来伪造它更令人满意,例如,使用不同的对象而不是函数

我怀疑这是实现这一点的最佳方法,但您可以通过在方法中使用方法的名称来访问属性:

>>> def foo():
...   print foo.x
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
AttributeError: 'function' object has no attribute 'x'
>>> foo.x = 5
>>> foo()
5
>>def foo():
...   打印foo.x
... 
>>>foo()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第2行,在foo中
AttributeError:“函数”对象没有属性“x”
>>>foo.x=5
>>>foo()
5.

答案很简单。只需使用在执行时而不是编译时查找的事实名称:

def f():
    return f._x

f._x = "foo"
f()           # -> "foo"

您可以使用一个类来完成此操作

>>> class F(object):
...     def __call__(self, *args, **kw):
...         return self._x
... 
>>> f=F()
>>> f._x = "foo"
>>> f()
'foo'
>>> g=f
>>> del f
>>> g()
'foo'

如果希望它完全独立于函数名,则需要一些框架魔法。例如:

def f2():
    import inspect
    frame = inspect.currentframe()
    fname = frame.f_code.co_name
    fobj = frame.f_globals[fname]
    print fobj._x


f2._x = 2
f2() 

那么,让我们看看什么是函数:

>>> def foo():
...     return x
... 
>>> foo.x = 777
>>> foo.x
777
>>> foo()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<interactive input>", line 2, in foo
NameError: global name 'x' is not defined
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 
'func_globals', 'func_name', 'x']
>>> getattr(foo, 'x')
777
啊哈!也许我们可以从代码块的名称中得到函数的名称,然后再四处寻找属性?果不其然:

>>> getattr(fr.f_globals[fr.f_code.co_name], 'x')
777
>>> fr.f_globals[fr.f_code.co_name].x
777
>>> def foo():
...     import sys
...     frm = sys._getframe()
...     return frm.f_globals[frm.f_code.co_name].x
... 
>>> foo.x=777
>>> foo()
777
太好了!但是,它能经受住对原有功能的重命名和删除吗

>>> g = foo
>>> g.func_name
'foo'
>>> g.func_code.co_name
'foo'
啊,很可疑。函数对象及其代码对象仍然坚持称它们为
foo
。果不其然,这就是它的断裂之处:

>>> g.x
777
>>> g.x=888
>>> foo.x
888
>>> g()
888
>>> del foo
>>> g()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<interactive input>", line 4, in foo
KeyError: 'foo'

当然,还有其他诡计,你可以这样做,它似乎是功能-特别是与类定义的把戏。。。但这本身并不是一种功能。这完全取决于您真正需要做什么。

作为一种解决方法,您可以使用factory函数来修复您的范围:

def factory():
    def inner():
        print inner.x
    return inner


>>> foo=factory()
>>> foo.x=11
>>> foo()
11
>>> bar = foo
>>> del foo
>>> bar()
11
解决方案 使函数的一个默认参数成为对函数本身的引用

def f(self):
    return self.x
f.func_defaults = (f,)
用法示例:

>>> f.x = 17
>>> b = f
>>> del f
>>> b()
17
解释 最初的海报想要一个不需要全局名称查找的解决方案。简单的解决方案

def f():
    return f.x
对不符合要求的每次调用执行全局变量
f
的查找。如果删除
f
,则该功能失败。更复杂的
inspect
提案也会以同样的方式失败

我们想要的是执行早期绑定,并将绑定引用存储在对象本身中。以下是我们在概念上所做的工作:

def f(self=f):
    return self.x
在上面的示例中,
self
是一个局部变量,因此不执行全局查找。但是,我们不能按原样编写代码,因为当我们尝试将
self
的默认值绑定到它时,
f
尚未定义。相反,我们在定义
f
后设置默认值

室内装修设计师 这里有一个简单的装饰为您做这件事。请注意,
self
参数必须排在最后,与方法不同,
self
必须排在第一位。这也意味着,如果任何其他参数采用默认值,则必须提供默认值

def self_reference(f):
    f.func_defaults = f.func_defaults[:-1] + (f,)
    return f

@self_reference
def foo(verb, adverb='swiftly', self=None):
    return '%s %s %s' % (self.subject, verb, adverb)
例如:

>>> foo.subject = 'Fred'
>>> bar = foo
>>> del foo
>>> bar('runs')
'Fred runs swiftly'

这是一个在执行函数之前将当前乐趣注入函数全局的装饰器。这是一个相当不错的技巧,但也相当有效

from functools import wraps


def introspective(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        exists = 'current_fun' in f.func_globals
        old = f.func_globals.get('current_fun',None)
        f.func_globals['current_fun'] = wrapper
        try:
            return f(*args, **kwargs)
        finally:
            if exists:
                f.func_globals['current_fun'] = old
            else:
                del f.func_globals['current_fun']
    return wrapper

@introspective
def f():
    print 'func_dict is ',current_fun.func_dict
    print '__dict__ is ',current_fun.__dict__
    print 'x is ',current_fun.x
下面是一个用法示例

In [41]: f.x = 'x'

In [42]: f()
func_dict is  {'x': 'x'}
__dict__ is  {'x': 'x'}
x is  x

In [43]: g = f

In [44]: del f

In [45]: g()
func_dict is  {'x': 'x'}
__dict__ is  {'x': 'x'}
x is  x

这使用了一种有点粗俗的方法,但考虑到它也适用于
g()
调用,这可能是迄今为止最正确的方法。它之所以有效,是因为它依赖于模块执行的任何字节码检查,作为一种快捷方式

它看起来比实际的更黑客,部分原因是
dis.disassemble()
调用打印到stdout,所以我将其重定向到StringIO。我使用
反汇编()
突出显示最后一条指令的功能(在其中添加
打印文本
行以查看它的外观),这使得更容易获取之前的
加载\u NAME
及其使用的变量

可以使用更干净的字节码检查库来执行此操作,而无需使用
dis
模块,但这证明了这是可能的。这可能不是最稳健的方法,但在大多数情况下,它也可能有效。我还没有花足够的时间深入研究Python内部或字节码,以了解大多数
CALL\u函数
字节码之前是否立即有regex技巧能够识别的指令

import inspect
import dis
import re
import sys
import StringIO

def f():
    caller = inspect.stack()[1][0]
    sys.stdout = StringIO.StringIO()
    dis.disassemble(caller.f_code, caller.f_lasti)
    text = sys.stdout.getvalue()
    sys.stdout = sys.__stdout__
    match = re.search(r'LOAD_NAME.*\((.*?)\)\s+-->', text)
    name = match.group(1)
    try:
        func = caller.f_locals[name]
    except KeyError:
        func = caller.f_globals[name]
    return func._x

f._x = 'foo'
print 'call f():', f()
g = f
del f
print 'call g():', g()
这将生成以下输出:

call f(): foo
call g(): foo

使用类而不是函数,并滥用
\uuuu new\uuu
方法使类作为函数可调用,怎么样?由于
\uuuu new\uuuu
方法将类名作为第一个参数,因此它可以访问所有类属性

喜欢

class f(object):
        def __new__(cls, x):
            print cls.myattribute
            return x
这与中的工作原理相同

f.myattribute = "foo"
f(3)
foo
3
那你就可以了

g=f
f=None
g(3)
foo
3

问题是,即使对象的行为类似于函数,它也不是。因此IDE无法向您提供签名。

实现这一点的另一种方法是在另一个函数中定义函数,并让外部函数返回内部函数。然后内部函数可以通过闭包访问自身。下面是一个简单的例子:

def makeFunc():
    def f():
        return f._x
    return f
然后:


如果只需要一个方法,但需要一个具有共享类状态和单个实例状态的轻量级类,则可以尝试以下闭包模式:

# closure example of light weight object having class state,
#    local state, and single method
# This is a singleton in the sense that there is a single class
#    state (see Borg singleton pattern notebook)
#    BUT combined with local state
# As long as only one method is needed, this one way to do it
# If a full class singleton object is needed with multiple 
#    methods, best look at one of the singleton patterns

def LW_Object_Factory(localState):

    # class state - doesn't change
    lwof_args = (1, 2, 3)
    lwof_kwargs =  {'a': 4, 'b': 5}

    # local instance - function object - unique per
    # instantiation sharing class state
    def theObj(doc, x):
        print doc, 'instance:'
        print '\tinstance class state:\n\t\targs -', \
              lwof_args, ' kwargs -', lwof_kwargs
        print '\tinstance locals().items():'
        for i in locals().items():
            print '\t\t', i
        print '\tinstance argument x:\n\t\t', '"{}"'.format(x)
        print '\tinstance local state theObj.foo:\n\t\t',\
              '"{}"'.format(theObj.foo)
        print ''

    # setting local state from argument
    theObj.foo = localState

    return(theObj)

lwo1 = LW_Object_Factory('foo in local state for first')
lwo2 = LW_Object_Factory('foo in local state for second')

# prove each instance is unique while sharing class state
print 'lwo1 {} distinct instance from lwo2\n'\
      .format(id(lwo1) <> id(lwo2) and "IS" or "IS NOT")

# run them
lwo1('lwo1', 'argument lwo1') 
lwo2('lwo2', 'argument lwo2')
#具有类状态的轻量级对象的闭包示例,
#局部状态和单一方法
#这是一个单例,因为只有一个类
#州(见博格单件模式笔记本)
#但与地方政府相结合
#只要只需要一种方法,这就是一种方法
#如果需要一个具有多个
#方法,最好查看其中一个单例模式
def LW_对象_工厂(本地状态):
#类状态-不会更改
lwof_args=(1,2,3)
lwof_kwargs={'a':
def makeFunc():
    def f():
        return f._x
    return f
>>> f = makeFunc()
>>> f._x = "foo"
>>> f()
'foo'
>>> g = f
>>> del f
>>> g()
'foo'
# closure example of light weight object having class state,
#    local state, and single method
# This is a singleton in the sense that there is a single class
#    state (see Borg singleton pattern notebook)
#    BUT combined with local state
# As long as only one method is needed, this one way to do it
# If a full class singleton object is needed with multiple 
#    methods, best look at one of the singleton patterns

def LW_Object_Factory(localState):

    # class state - doesn't change
    lwof_args = (1, 2, 3)
    lwof_kwargs =  {'a': 4, 'b': 5}

    # local instance - function object - unique per
    # instantiation sharing class state
    def theObj(doc, x):
        print doc, 'instance:'
        print '\tinstance class state:\n\t\targs -', \
              lwof_args, ' kwargs -', lwof_kwargs
        print '\tinstance locals().items():'
        for i in locals().items():
            print '\t\t', i
        print '\tinstance argument x:\n\t\t', '"{}"'.format(x)
        print '\tinstance local state theObj.foo:\n\t\t',\
              '"{}"'.format(theObj.foo)
        print ''

    # setting local state from argument
    theObj.foo = localState

    return(theObj)

lwo1 = LW_Object_Factory('foo in local state for first')
lwo2 = LW_Object_Factory('foo in local state for second')

# prove each instance is unique while sharing class state
print 'lwo1 {} distinct instance from lwo2\n'\
      .format(id(lwo1) <> id(lwo2) and "IS" or "IS NOT")

# run them
lwo1('lwo1', 'argument lwo1') 
lwo2('lwo2', 'argument lwo2')
class new:
    """Returns True the first time an argument is passed, else False."""
    seen = set()
    def __new__(cls, x):
        old = x in cls.seen
        cls.seen.add(x)
        return not old

def main():
    print(new(1))  # True
    print(new(2))  # True
    print(new(2))  # false
    is_new = new
    print(is_new(1))  # False
class log_once:
    """Log a message if it has not already been logged.

    Args:
        msg: message to be logged
        printer: function to log the message
        id_: the identifier of the msg determines whether the msg
          has already been logged. Defaults to the msg itself.

    This is useful to log a condition that occurs many times in a single
    execution. It may be relevant that the condition was true once, but
    you did not need to know that it was true 10000 times, nor do you
    desire evidence to that effect to fill your terminal screen.
    """
    seen = set()
    def __new__(cls, msg, printer=print, id_=None):
        id_ = id_ or msg
        if id_ not in cls.seen:
            cls.seen.add(id_)
            printer(id_)


if __name__ == '__main__':
    log_once(1)
    log_once(1)
    log_once(2)
def generate_f():
    def f():
        return f.x
    return f

f = generate_f()

f.x = 314
g = f

del f
print g()
# => 314
from functools import update_wrapper

def dictAsGlobals(f):
    nf = type(f)(f.__code__, f.__dict__, f.__name__, f.__defaults__, f.__closure__)
    try: nf.__kwdefaults__ = f.__kwdefaults__
    except AttributeError: pass
    nf.__dict__ = f.__dict__
    nf.__builtins__ = f.__globals__["__builtins__"]
    return update_wrapper(nf, f)

@dictAsGlobals
def f():
    global timesCalled
    timesCalled += 1
    print(len.__doc__.split("\n")[0])
    return factor0 * factor1

vars(f).update(timesCalled = 0, factor0 = 3, factor1 = 2)

print(f())
print(f())
print(f.timesCalled)
def f():
    print(f)
f, g = 42, f
g()  # prints 42
del f
g()  # raises an exception