• 10
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

First time user on stack overflow and I'm excited to be here.

INTRO: I recently began the magical adventure into the world of Python programming - I love it. Now everything has gone smoothly in my awkward transition from C, but I'm having trouble creating something which would be synonymous to a HEADER file (.h).

PROBLEM: I have medium sized dictionaries and lists (about 1,000 elements), lengthy enums, and '#defines' (well not really), but I can't find a CLEAN way to organize them all. In C, I would throw them all in a header file and never think again about it, however, in Python that's not possible or so I think.

CURRENT DIRTY SOLUTION: I'm initializing all CONSTANT variables at the top of either the MODULE or FUNCTION (module if multiple functions need it).

CONCLUSION: I would be forever grateful if someone had come up with a way to CLEANLY organize constant variable's.

THANK YOU SO MUCH!

Put your constants into their own module:

# constants.py

RED = 1
BLUE = 2
GREEN = 3

Then import that module and use the constants:

import constants

print "RED is", constants.RED

The constants can be any value you like, I've shown integers here, but lists and dicts would work just the same.

  • 22
Reply Report
      • 2
    • Great idea. Do you know what the latency or efficiency loss is like? Because technically you're importing it and doesn't that require a look-up every time you reference the value?
      • 2
    • You're doing an attribute lookup each time, which is the kind of operation that happens all the time anyway, it really isn't something to worry about.
      • 1
    • @TSmith: And if you are super concerned with shaving off that little bit of time, you can always do from constants import RED, or assign it to a variable just before a super long loop: red = constants.RED
    • Thank you Ned and jdi! I really appreciate it and yeah jdi that's more of what I wanted to hear, but will a local variable get a copy or a reference to the globally imported constant? Just out of curiosity.

Usually I do this:

File: constants.py

CONSTANT1 = 'asd'
CONSTANT_FOO = 123
CONSTANT_BAR = [1, 2, 5]

File: your_script.py

from constants import CONSTANT1, CONSTANT_FOO
# or if you want *all* of them
# from constants import *

...

Now your constants are in one file and you can nicely import and use them.

  • 9
Reply Report
    • @jdi: Yeah I learned about mutable and immutable types the hard way haha. Thank you so much for the help, I seriously appreciate it.
      • 1
    • If you import all of them, the constants become global variables and won't require a lookup. Do note that Python is about 200 times slower than C so you won't notice much of a speed boost if you try to micro optimize.
      • 2
    • Thank you blender. Quick curiosity question, if I assign a local variable (within a function) to that imported global variable, will that local var have a copy or a reference to the global?
    • @TSmith: It will have a reference, but take note that the behavior will depend on whether its a mutable or immutable type. If its a string, any changes you make to that local will simply shadow the global constant. If the constant is say a list object, you can append to the local var and it will reflect in the constant because its still the same reference

Make a separate file constants.py, and put all globally-relevant constants in there. Then you can import constants to refer to them as constants.SPAM or do the (questionable) from constants import * to refer to them simply as SPAM or EGGS.

While we're here, note that Python doesn't support constant constants. The convention is just to name them in ALL_CAPS and promise not to mutate them.

  • 3
Reply Report
      • 2
    • Haha yeah I promise :), but what about run time efficiency? When you import a module is that like "__inline" in C?
    • @TSmith: I wouldn't compare it to an inline because its really just importing into a namespace module object, and it does it only once, and shares it in memory for subsequent imports.

If you want to mess with nested constants and don't like dicts, I came up with this fun solution:

# Recursively transform a dict to instances of the desired class

import json
from collections import namedtuple

class DictTransformer():
    @classmethod
    def constantize(self, d):
        return self.transform(d, klass=namedtuple, klassname='namedtuple')

    @classmethod
    def transform(self, d, klass, klassname):
        return self._from_json(self._to_json(d), klass=klass, klassname=klassname)

    @classmethod
    def _to_json(self, d, access_method='__dict__'):
        return json.dumps(d, default=lambda o: getattr(o, access_method, str(o)))

    @classmethod
    def _from_json(self, jsonstr, klass, klassname):
        return json.loads(jsonstr, object_hook=lambda d: klass(klassname, d.keys())(*d.values()))

Ex:

constants = {
  'A': {
    'B': {
      'C': 'D'
    }
  }
}
CONSTANTS = DictTransformer.transform(d, klass=namedtuple, klassname='namedtuple')
CONSTANTS.A.B.C == 'D'

Pros:

  • handles nested dicts
  • can potentially generate other types of dicts/classes
  • namedtuples provide immutability for constants

Cons:

  • may not respond to .keys and .values if those are not provided on your klass (though you can sometimes mimic with ._fields and list(A.B.C))

Thoughts?

h/t to @hlzr and you guys for the original class idea

  • 0
Reply Report

Trending Tags