Вызовите функцию Python, как если бы она была встроенной - PullRequest
2 голосов
/ 25 июня 2010

Я хочу иметь функцию в другом модуле, который при вызове имеет доступ ко всем переменным, к которым имеет доступ его вызывающий объект, и функционирует так же, как если бы его тело было вставлено в вызывающий объект, а не имел свой собственный контекст,в основном, как макрос C вместо обычной функции.Я знаю, что могу передать locals () в функцию, а затем она может обращаться к локальным переменным как к диктовке, но я хочу иметь возможность обращаться к ним нормально (например, xy, не x ["y"], и я хочу, чтобы все именавызывающий имеет доступ не только к местным жителям, но и к тем вещам, которые были «импортированы» в файл вызывающего, но не к модулю, который содержит функцию.

Возможно ли это осуществить?

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

def getObj(expression)
  ofs = expression.rfind(".")
  obj = eval(expression[:ofs])  
  print "The part of the expression Left of the period is of type ", type(obj), 

Проблема в том, что для «выражения» требуются импорт и локальные переменныевызывающего для того, чтобы вывести без ошибки. На самом деле есть гораздо больше, чем просто eval, поэтому я пытаюсь избежать решения просто передать localals () в и через eval (), так как это не исправитмоя общая проблема со случаем.

Ответы [ 4 ]

3 голосов
/ 25 июня 2010

И еще один, еще более уродливый способ сделать это - пожалуйста, не делайте этого, даже если это возможно -

import sys

def insp():
    l = sys._getframe(1).f_locals
    expression = l["expression"]
    ofs = expression.rfind(".")
    expofs = expression[:ofs]
    obj = eval(expofs, globals(), l)
    print "The part of the expression %r Left of the period (%r) is of type %r" % (expression, expofs, type(obj)), 

def foo():
    derp = 5
    expression = "derp.durr"
    insp()

foo()

выходы

Часть выражения 'derp.durr' слева от точки ('derp') имеет тип (тип 'int')

2 голосов
/ 25 июня 2010

Я не предполагаю, что это ответ, который вы хотели услышать, но попытка получить доступ к локальным переменным из области видимости вызывающего модуля не является хорошей идеей.Если вы обычно программируете на PHP или C, вы могли бы привыкнуть к таким вещам?

Если вы все еще хотите это сделать, вы можете рассмотреть возможность создания класса и передачи экземпляра этого класса вместо locals():

#other_module.py
def some_func(lcls):
    print(lcls.x)

Затем

>>> import other_module
>>> 
>>> 
>>> x = 'Hello World'
>>> 
>>> class MyLocals(object):
...     def __init__(self, lcls):
...             self.lcls = lcls
...     def __getattr__(self, name):
...             return self.lcls[name]
... 
>>> # Call your function with an instance of this instead.
>>> other_module.some_func(MyLocals(locals()))
'Hello World'

Дайте ему вихрь.

2 голосов
/ 25 июня 2010

Из Zen of Python :

2) Явное лучше, чем неявное.

Другими словами, передайте параметр и не пытайтесь стать по-настоящему модным только потому, что думаете, что вам будет проще. Написание кода касается не только вас.

2 голосов
/ 25 июня 2010

Возможно ли это осуществить?

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

Рассмотрим:

myfile.py

def func_in_caller():
    print "in caller"

import otherfile
globals()["imported_func"] = otherfile.remote_func

imported_func(123, globals())  

otherfile.py

def remote_func(x1, extra):
    for k,v in extra.iteritems(): 
        globals()[k] = v
    print x1
    func_in_caller()

Это дает (как и ожидалось):

123
in caller

То, что мы здесь делаем, - это обман: мы просто копируем каждый элемент в другое пространство имен, чтобы сделать эту работу. Это может (и ) сломаться очень легко и / или привести к трудностям поиска ошибок.

Почти наверняка есть лучший способ решения вашей проблемы / структурирования кода (в общем, нам нужно больше информации о том, чего вы пытаетесь достичь).

...