“сам” в простой функции?

У меня есть набор функций (за пределами любого класса), где я установил атрибуты на них, как funcname.fields = 'xxx'. Я надеялся, что мог затем получить доступ к этим переменным из функции с self.fields, но конечно это говорит мне:

глобальное имя 'сам' не определяется

Так..., что я могу сделать? Действительно ли там некоторое волшебство является переменным, я могу получить доступ? Как __this__.fields?


Несколько человек спросили "почему?". Вы, вероятно, не согласитесь с моим обоснованием, но у меня есть ряд функций, что все должны совместно использовать ту же подпись (примите только один аргумент). По большей части этого аргумента достаточно, чтобы сделать необходимое вычисление. Однако в нескольких ограниченных случаях, некоторая дополнительная информация необходима. Вместо того, чтобы вынуждать каждую функцию принять длинный список главным образом неиспользуемых переменных, я решил просто установить их на функции так, чтобы они могли легко быть проигнорированы.

Хотя, это происходит со мной теперь, когда Вы могли просто использовать **kwargs как последний аргумент, если Вы не заботитесь о дополнительном args. О, хорошо...

Править: На самом деле некоторые функции я не записал и скорее не изменю для принятия дополнительного args. Путем "передачи в" дополнительном args как атрибуты, мой код может работать и с моими пользовательскими функциями, которые используют в своих интересах дополнительный args, и со сторонним кодом, которые не требуют дополнительного args.

Спасибо за быстрые ответы :)

7
задан mpen 8 July 2010 в 20:59
поделиться

11 ответов

Вы не можете сделать эту «функцию, обращающуюся к своим собственным атрибутам» правильно для всех ситуаций - подробности см. Здесь как функция python может получить доступ к своим собственным атрибутам? - но вот краткая демонстрация:

>>> 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

В основном большинство методов прямо или косвенно полагаются на доступ к объекту функции через поиск по имени в глобальных переменных; и если исходное имя функции удалено, это перестает работать. Есть и другие беспорядочные способы сделать это, например, определить класс или фабрику, но благодаря вашему объяснению становится ясно, что вам это на самом деле не нужно.

Просто введите упомянутый аргумент для всех ключевых слов, например:

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 :)

2
ответ дан 6 December 2019 в 07:24
поделиться

если вы хотите глобально установить параметры для вызываемой "вещи", вы всегда можете создать класс и реализовать метод __call__?

1
ответ дан 6 December 2019 в 07:24
поделиться

Вы можете использовать следующий (ужасно уродливый) код:

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

... как вы можете видеть, это позволит вам использовать "self", как вы описали. Вы не можете использовать "object()" напрямую, потому что вы не можете "monkey patch(*)" значения в object() экземпляр. Однако обычные подклассы object (такие как Generic_Object(), который я показал здесь) могут быть "обезьяньими патчами"

Если вы хотите всегда вызывать свою функцию со ссылкой на некоторый объект в качестве первого аргумента, это возможно. Вы могли бы поместить дефолтный аргумент первым, а затем *args и необязательные параметры **kwargs (через которые можно было бы передавать любые другие аргументы или словари опций при вызове этой функции).

Это, как я уже сказал ужасно уродливо. Пожалуйста, никогда не публикуйте такой код и не делитесь им ни с кем в сообществе Python. Я показываю его здесь только как некое странное учебное упражнение.

Метод экземпляра подобен функции в Python. Однако он существует в пространстве имен класса (поэтому доступ к нему должен осуществляться через экземпляр ... myobject.foo(), например) и вызывается со ссылкой на "self" (аналог указателя "this" в C++) в качестве первого аргумента. Также существует процесс разрешения метода, который заставляет интерпретатор искать пространство имен экземпляра, затем его класс, затем каждый из родительских классов и так далее ... вверх по дереву наследования.

Несвязанная функция вызывается с любыми аргументами, которые вы ей передаете. В списке аргументов не может быть никакой автоматически предопределенной ссылки на объект/экземпляр. Таким образом, писать функцию с начальным аргументом "self" бессмысленно. (Это законно, потому что Python не придает никакого особого значения имени "self". Но бессмысленно, потому что вызывающим вашу функцию придется вручную добавлять в список аргументов какую-то объектную ссылку, и совершенно неясно, что это должно быть. Просто какой-то причудливый "Generic_Object", который затем плавает в пространстве глобальных переменных?).

Надеюсь, это немного прояснило ситуацию. Похоже, что вы страдаете от некоторых фундаментальных заблуждений о том, как работает Python и другие объектно-ориентированные системы.

  • ("Monkey patching" - это термин, используемый для описания прямого манипулирования атрибутами объекта - или "переменными экземпляра" - кодом, который не является частью иерархии классов, экземпляром которых является объект).
1
ответ дан 6 December 2019 в 07:24
поделиться

self не является ключевым словом в python, это обычное имя переменной. При создании методов экземпляра вы можете называть первый параметр как угодно, self - это просто соглашение.

Вы почти всегда должны предпочитать передачу аргументов функциям, а не установку свойств для ввода, но если вы должны, вы можете сделать это, используя фактическое имя функции для доступа к переменным внутри нее:

def a:
    if a.foo:
        #blah

a.foo = false
a()

см. python function attributes - uses and abuses, когда это может пригодиться. :D

.
11
ответ дан 6 December 2019 в 07:24
поделиться

Это не то, что вы должны делать. Я не могу придумать, как сделать то, о чем вы просите, за исключением некоторого блуждания по стеку вызовов и странной интроспекции - а это не то, что должно происходить в производственном коде.

Тем не менее, я думаю, что это действительно делает то, что вы просили:

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()
1
ответ дан 6 December 2019 в 07:24
поделиться

Пример:

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

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

Плюс. self - это не ключевое слово, а просто другое имя переменной, которое является конкретным экземпляром класса. self передается неявно, но принимается явно.

2
ответ дан 6 December 2019 в 07:24
поделиться

В качестве другой альтернативы, вы можете сделать функции связанными методами класса, например, так:

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 "

Если вы хотите, чтобы функции разделяли имена атрибутов, вы просто делаете их частью одного класса. Если нет, дайте каждой из них свой собственный класс.

1
ответ дан 6 December 2019 в 07:24
поделиться

На что именно вы надеетесь, что "self" будет указывать, если функция определена вне какого-либо класса? Если вашей функции нужна какая-то глобальная информация для правильного выполнения, вам нужно послать эту информацию в функцию в виде аргумента.

Если вы хотите, чтобы ваша функция была контекстно-ориентированной, вам нужно объявить ее в области видимости объекта.

0
ответ дан 6 December 2019 в 07:24
поделиться

Хотя я согласен с остальными, что это, вероятно, плохой дизайн, этот вопрос меня заинтриговал. Вот мое первое решение, которое я могу обновить, когда заработаю декораторы. В его нынешнем виде он в значительной степени полагается на возможность чтения стека, что может быть невозможно во всех реализациях (что-то о 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

1
ответ дан 6 December 2019 в 07:24
поделиться
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
3
ответ дан 6 December 2019 в 07:24
поделиться

Не существует специального способа в теле функции ссылаться на функциональный объект, код которого выполняется. Самый простой - просто использовать funcname.field (где funcname - это имя функции в пространстве имен, в котором она находится, что, как вы указываете, так и есть - в противном случае было бы сложнее).

1
ответ дан 6 December 2019 в 07:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: