Створювати константи за допомогою модуля “настройки”?


78

Я відносно новачок у Python. Я прагну створити модуль "налаштувань", де зберігатимуться різні константи для конкретних додатків.

Ось як я хочу встановити свій код:

settings.py

CONSTANT = 'value'

script.py

import settings

def func():
    var = CONSTANT
    # do some more coding
    return var

Я отримую помилку Python із зазначенням:

global name 'CONSTANT' is not defined.

Я помітив у вихідному коді Django, що їхній settings.pyфайл має константи, названі так само, як і я. Мене бентежить, як їх можна імпортувати в скрипт і на них посилатись через додаток.

РЕДАГУВАТИ

Дякую за всі ваші відповіді! Я спробував наступне:

import settings

print settings.CONSTANT

Я отримую ту ж помилку

ImportError: cannot import name CONSTANT


5
Це не має сенсу. ви повинні отримувати AttributeErrorif, settingsщо не визначає, CONSTANTі ImportErrorякщо він не може імпортувати налаштування, і в цьому випадку це навіть не буде дивитисьCONSTANT
aaronasterling

Тоді я щось роблю не так?
Ларк

1
Помістіть два рядки, які ви опублікували останніми, у файл самостійно точно так само, як ви їх опублікували, і перевірте, чи це працює.
aaronasterling

1
Дякую всім за всю вашу допомогу. Я зрозумів це. Це було пов’язано з розміщенням файлу init .py. Я намагався імпортувати налаштування, тому python шукав, не міг їх знайти, тому, коли я посилався на налаштування каталогу "модулі", все працювало належним чином. Отже, в основному моя заява про імпорт виглядає так: з параметрів імпорту модулів. Я думаю, що є кращий спосіб зробити це, більш пітонічний, тому я збираюся спробувати різні комбінації. Ще раз дякую за всі ваші відповіді.
Жаворонок

Відповіді:


140

Найпростіший спосіб зробити це - просто налаштування бути модулем.

(settings.py)

CONSTANT1 = "value1"
CONSTANT2 = "value2"

(consumer.py)

import settings

print settings.CONSTANT1
print settings.CONSTANT2

Коли ви імпортуєте модуль python, вам слід додати до змінних, які ви витягуєте з нього, іменем модуля. Якщо ви точно знаєте, які значення ви хочете використовувати з нього у даному файлі, і вас не турбує їх зміна під час виконання, тоді ви можете зробити

from settings import CONSTANT1, CONSTANT2

print CONSTANT1
print CONSTANT2

але я не захоплювався би тим останнім. Людям, які читають ваш код, важко визначити, звідки беруться цінності. і виключає оновлення цих значень, якщо інший клієнтський модуль їх змінює. Останній спосіб це зробити

import settings as s

print s.CONSTANT1
print s.CONSTANT2

Це заощаджує набір тексту, поширюватиме оновлення і лише вимагає від читачів пам’ятати, що все, що після цього, sє з модуля налаштувань.


@delnan Я спеціально уникав згадування механіки, щоб не зробити застарілою вашу відповідь;)
aaronasterling

Ну, практично застаріле;) Знання точної семантики є корисним і бажаним, але для того, щоб це працювало, це не потрібно - хоча необхідно знати наслідки цього, які в значній мірі узагальнені у вашій відповіді.

3
Я хоч ідея константи полягає в тому, що її не можна змінювати під час виконання?
Lie Ryan

1
@Lie Ryan, у Python немає констант. Про багатопрограмні проекти ніколи не знаєш.
aaronasterling

1
@AaronMcSmoot: так, але якщо ви навіть маєте намір змінити константу після виконання, це дуже підозріло, що ви неправильно розробили дизайн.
Lie Ryan

17

Крок 1: Створіть новий файл settings.py в тому ж каталозі для зручності доступу.

#database configuration settings

database = dict(
    DATABASE = "mysql",
    USER     = "Lark",
    PASS     = ""
)

#application predefined constants

app = dict(
    VERSION   = 1.0,
    GITHUB    = "{url}"
)

Крок 2: Імпорт модуля налаштувань у файл програми.

import settings as s            # s is aliasing settings & settings is the actual file you do not have to add .py 

print(s.database['DATABASE'])   # should output mysql

print(s.app['VERSION'])         # should output 1.0

якщо вам не подобається використовувати псевдонім типу s, ви можете використовувати інший синтаксис

from settings import database, app

print(database['DATABASE'])   # should output mysql

print(app['VERSION'])         # should output 1.0

повідомлення про другий спосіб імпорту ви можете використовувати імена dict безпосередньо

Маленька порада: ви можете імпортувати весь код у файл налаштувань за допомогою *, якщо у вас великий файл, і ви будете використовувати більшість налаштувань у ньому у своїй програмі.

from settings import *      # * represent all the code on the file, it will work like step 2


print(database['USER'])       # should output lark

print(app['VERSION'])         # should output 1.0

я сподіваюся, що це допоможе.


5

Коли ви import settings, moduleвикликаний об'єкт settingsпоміщається в глобальний простір імен - і цей об'єкт несе settings.pyв собі атрибути. Тобто зовні settings.py, ви дивитеся , CONSTANTяк settings.CONSTANT.


4

Залиште settings.py точно таким, яким він є, тоді ви зможете використовувати його так само, як це робить Django:

import settings

def func():
    var = settings.CONSTANT

3

... Або, якщо ви дійсно хочете, щоб усі константи з settings.py були імпортовані у глобальний простір імен, ви можете запустити

from settings import *

... але в іншому випадку використання settings.CONSTANT, як усі інші згадували тут, є цілком правильним.


Дивіться мою відповідь на всі три можливі способи використання importвисловлювання.
aaronasterling

2
Насправді це недоцільно. Див., Наприклад, docs.python.org/howto/doanddont.html#from-module-import . Хоча в цьому випадку це має бажаний побічний ефект, що зміни констант не вплинуть на інші модулі.

2
Приємно сказано, @AaronMcSmooth. І технічно я не сказав, що доцільно імпортувати *, лише що це можливо: P
ewall

@delnan. Я не настільки впевнений, що це бажано. Це залежить від програми, але не менш можливим може бути поширення змін (якщо вони взагалі відбудуться)
aaronasterling


2

Я новачок у python, але якщо ми визначимо константу, як функцію на setings.py

def CONST1():
    return "some value"

main.py

import setings

print setings.CONST1() ##take an constant value

тут я бачу лише одне, значення не можна змінювати, але воно працює як функція ..


2

Цей спосіб є більш ефективним, оскільки завантажує / оцінює змінні налаштувань лише один раз. Це добре працює для всіх моїх проектів на Python.

pip install python-settings

Документи тут: https://github.com/charlsagente/python-settings

Вам потрібен файл settings.py з усіма визначеними константами, наприклад:

# settings.py

DATABASE_HOST = '10.0.0.1'

Потім потрібно або встановити змінну env (експортувати SETTINGS_MODULE = настройки), або вручну викликати метод налаштування:

# something_else.py

from python_settings import settings
from . import settings as my_local_settings

settings.configure(my_local_settings) # configure() receives a python module

Утиліта також підтримує «Ледачу» ініціалізацію для важких для завантаження об’єктів, тому при запуску проекту python він завантажується швидше, оскільки обчислює змінну налаштувань лише тоді, коли це потрібно

# settings.py

from python_settings import LazySetting
from my_awesome_library import HeavyInitializationClass # Heavy to initialize object

LAZY_INITIALIZATION = LazySetting(HeavyInitializationClass, "127.0.0.1:4222") 
# LazySetting(Class, *args, **kwargs)

Просто налаштуйте один раз і тепер викликайте свої змінні там, де це потрібно:

# my_awesome_file.py

from python_settings import settings 

print(settings.DATABASE_HOST) # Will print '10.0.0.1'

1

Спробуйте це:

У settings.py:

CONSTANT = 5

У головному файлі:

from settings import CONSTANT

class A:
    b = CONSTANT

    def printb(self):
         print self.b

Я думаю, що ваша вищевказана помилка виникає із файлу налаштувань, який імпортується занадто пізно. Переконайтеся, що він знаходиться у верхній частині файлу.


1

Також варто перевірити проект простих налаштувань, який дозволяє подавати налаштування у ваш скрипт на runtim, що дозволяє налаштування для певного середовища (думаю, розробник, тест, продукт, ...)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.