Как функция может получить доступ к своим собственным атрибутам? - PullRequest
38 голосов
/ 24 июня 2010

возможно ли получить доступ к атрибутам объекта функции python из области действия функции?

например. давай

def f():
    return SOMETHING

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

Теперь, что ЧТО-ТО должно быть, если мы хотим, чтобы содержимое атрибута _x возвращало "foo"? если это возможно (просто)

спасибо

UPDATE:

Мне бы тоже хотелось получить следующую работу:

g = f
del f
g()          # -> "foo"

ОБНОВЛЕНИЕ 2:

Заявление о том, что это невозможно (если это так) и почему, является более удовлетворительным, чем предоставление способа, как подделать его, например. с объектом, отличным от функции

Ответы [ 15 ]

0 голосов
/ 25 августа 2016

Просто определите свою функцию внутри замыкания:

def generate_f():
    def f():
        return f.x
    return f

f = generate_f()

f.x = 314
g = f

del f
print g()
# => 314
0 голосов
/ 30 января 2016

Вот стратегия, которая, вероятно, хуже, чем идея func_defaults, но тем не менее интересна. Это глупо, но я не могу думать о чем-то практически не так с этим.

Мы можем реализовать функцию, которая может ссылаться на себя как на класс с помощью одного __new__ метода (метод, который обычно создает новый объект этого класса).

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)
0 голосов
/ 08 августа 2015

Если нужен только один метод, но вы хотите легкий класс с общим состоянием класса плюс состояние отдельного экземпляра, вы можете попробовать шаблон замыкания следующим образом:

# 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')
0 голосов
/ 14 января 2015

Еще один способ сделать это - определить функцию внутри другой функции и вернуть внешней функции внутреннюю функцию.Тогда внутренняя функция может получить доступ к себе через замыкание.Вот простой пример:

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

Тогда:

>>> f = makeFunc()
>>> f._x = "foo"
>>> f()
'foo'
>>> g = f
>>> del f
>>> g()
'foo'
0 голосов
/ 10 декабря 2014

Как насчет использования класса вместо функции и использования метода __new__, чтобы сделать класс вызываемым как функция? Поскольку метод __new__ получает имя класса в качестве первого параметра, он может получить доступ ко всем атрибутам класса

как в

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 не могут предоставить вам подпись.

...