2015-06-19 2 views
1

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

# hardcoded_values.py 
foo = 'abc' 
bar = 1234 

# usage somewhere else in another module 
from hardcoded_values import * 
print foo 
print bar 

То, что я хочу сделать, это изменить только hardcoded_values.py, так что print foo прозрачно вызывает функцию.

# hardcoded_values.py 
import config 
foo = SomeWrapper(config.get_value, 'foo') # or whatever you can think of to call config.get_value('foo') 
... 

config.get_value будет функция, которая вызывается с параметром 'foo' при использовании переменной foo (как в print foo).

+0

Я не получил то, что было бы в модуле 'config'. Я бы рекомендовал поместить функции в файл 'harcoded_values.py', например' def foo(): return SomeWrapper (config.get_value ('foo')) '. Затем из другого модуля вы будете делать 'from harcoded_values ​​import foo' (не рекомендуется импортировать все с *), а затем' my_var = foo() '. – tomasyany

+0

См. Мой обновленный вопрос. Это всего лишь пример, поэтому не беспокойтесь о * -импортах и ​​т. Д. – orange

+0

Хорошо. Я бы сделал это, как я сказал в своем комментарии раньше. Вместо того, чтобы импортировать переменную в другой модуль (который я не уверен, что вы можете это сделать), я бы импортировал функцию, которая возвращает значение. – tomasyany

ответ

2

Я уверен, что вы не можете делать то, что вы хотите делать, если вы импортировать как from hardcoded_values import * ,

То, что вы хотите сделать, это установить foo к некоторой функции, а затем применить property декоратора (или эквивалент), так что вы можете позвонить Foo, как foo, а не foo(). Вы не можете использовать свойство декоратора модули по причинам, подробно здесь: Why Is The property Decorator Only Defined For Classes?

Теперь, если вы были import hardcoded_values, то я думаю, что есть способ сделать то, что вы хотите hardcoded_values.foo. У меня довольно хорошее ощущение, что я собираюсь описать BAD IDEA, который никогда не должен использоваться, но я думаю, что это интересно.


BAD IDEA ????

Так что вы хотели заменить постоянную как os.EX_USAGE, который на моей системе является 64 с некоторой функцией, а затем вызвать его как os.EX_USAGE, а не os.EX_USAGE().Мы должны иметь возможность использовать декоратор property, но для этого нам нужен тип, отличный от module.

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

def module_class_factory(module): 
    ModuleClass = type('ModuleClass' + module.__name__, 
         (object,), module.__dict__) 
    return ModuleClass 

Теперь я буду импортировать ОС:

>>> import os 
>>> os.EX_USAGE 
64 
>>> os.getcwd() 
'/Users/Eric' 

Теперь я сделать класс OsClass и связать имя os к экземпляру этого класса:

>>> OsClass = module_class_factory(os) 
>>> os = OsClass() 
>>> os.EX_USAGE 
64 
>>> os.getcwd() 
'/Users/Eric' 

Все по-прежнему работает. Теперь определим функцию, чтобы заменить os.EX_USAGE, отметив, что нужно будет принимать фиктивный self аргумент:

>>> def foo(self): 
...  return 42 
... 

... и связать атрибут класса OsClass.EX_USAGE функции:

>>> OsClass.EX_USAGE = foo 
>>> os.EX_USAGE() 
42 

Он работает, когда вызванный объектом os! Теперь примените декоратор свойств:

>>> OsClass.EX_USAGE = property(OsClass.EX_USAGE) 
>>> os.EX_USAGE 
42 

Теперь константа, определенная в модуле, была прозрачно заменена вызовом функции.

+0

Отлично - вот что я искал. Спасибо за справочную информацию. – orange

0

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

я бы, наверное, hardcoded_variables в документе и пользовательские функции обёртку (например JSON?):

import json 
def getSettings(var): 
    with open('path/to/variables.json') as infl: 
     data = json.load(infl) 
    return infl[var] 
+0

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

2

Вы, безусловно, не может это сделать, если клиент код модуля использует from hardcoded_variables import *. Это делает ссылки на содержимое hardcoded_variables в пространстве имен другого модуля, и после этого вы ничего не можете с ними поделать.

Если код клиента можно изменить, чтобы просто импортировать модуль (например, import hardcoded_variables), а затем получить доступ к его атрибутам (с hardcoded_variables.foo), у вас есть шанс, но это немного неудобно.

Python кэширует модули, которые были импортированы в sys.modules (это словарь). Вы можете заменить модуль в этом словаре некоторым другим объектом, например экземпляром настраиваемого класса, и использовать объекты property или другие дескрипторы для реализации специального поведения при доступе к атрибутам объекта.

Попробуйте сделать свой новый hardcoded_variables.py выглядеть следующим образом (и рассмотреть вопрос о переименовании его тоже!):

import sys 

class DummyModule(object): 
    def __init__(self): 
     self._bar = 1233 

    @property 
    def foo(self): 
     print("foo called!") 
     return "abc" 

    @property 
    def bar(self): 
     self._bar += 1 
     return self._bar 

if __name__ != "__main__": # Note, this is the opposite of the usual boilerplate 
    sys.modules[__name__] = DummyModule() 
+0

Интересный подход. – orange

Смежные вопросы