Related
Do I have to formally define a function before I can use it as an element of a dictionary?
def my_func():
print 'my_func'
d = {
'function': my_func
}
I would rather define the function inline. I just tried to type out what I want to do, but the whitespace policies of python syntax make it very hard to define an inline func within a dict. Is there any way to do this?
The answer seems to be that there is no way to declare a function inline a dictionary definition in python. Thanks to everyone who took the time to contribute.
Do you really need a dictionary, or just getitem access?
If the latter, then use a class:
>>> class Dispatch(object):
... def funcA(self, *args):
... print('funcA%r' % (args,))
... def funcB(self, *args):
... print('funcB%r' % (args,))
... def __getitem__(self, name):
... return getattr(self, name)
...
>>> d = Dispatch()
>>>
>>> d['funcA'](1, 2, 3)
funcA(1, 2, 3)
You could use a decorator:
func_dict = {}
def register(func):
func_dict[func.__name__] = func
return func
#register
def a_func():
pass
#register
def b_func():
pass
The func_dict will end up mapping using the entire name of the function:
>>> func_dict
{'a_func': <function a_func at 0x000001F6117BC950>, 'b_func': <function b_func at 0x000001F6117BC8C8>}
You can modify the key used by register as desired. The trick is that we use the __name__ attribute of the function to get the appropriate string.
Consider using lambdas, but note that lambdas can only consist of one expression and cannot contain statements (see http://docs.python.org/reference/expressions.html#lambda).
e.g.
d = { 'func': lambda x: x + 1 }
# call d['func'](2) will return 3
Also, note that in Python 2, print is not a function. So you have to do either:
from __future__ import print_function
d = {
'function': print
}
or use sys.stdout.write instead
d = {
'function': sys.stdout.write
}
Some functions can be easily 'inlined' anonymously with lambda expressions, e.g.:
>>> d={'function': lambda x : x**2}
>>> d['function'](5)
25
But for anything semi-complex (or using statements) you probably just should define them beforehand.
There is no good reason to want to write this using a dictionary in Python. It's strange and is not a common way to namespace functions.
The the Python philosophies that apply here are:
There should be one-- and preferably only one --obvious way to do it.
Combined with
Readability counts.
Doing it this way also makes things hard to understand and read for the typical Python user.
The good things the dictionary does in this case is map strings to functions and namespace them within a dictionary, but this functionality is already provided by both modules and classes and it's much easier to understand by those familiar with Python.
Examples:
Module method:
#cool.py
def cool():
print 'cool'
Now use the module like you would be using your dict:
import cool
#cool.__dict__['cool']()
#update - to the more correct idiom vars
vars(cool)['cool']()
Class method:
class Cool():
def cool():
print 'cool'
#Cool.__dict__['cool']()
#update - to the more correct idiom vars
vars(Cool)['cool']()
Edit after comment below:
argparse seems like a good fit for this problem, so you don't have to reinvent the wheel. If you do decide to implement it completely yourself though argparse source should give you some good direction. Anyways the sections below seem to apply to this use case:
15.4.4.5. Beyond sys.argv
Sometimes it may be useful to have an ArgumentParser parse arguments
other than those of sys.argv. This can be accomplished by passing a
list of strings to parse_args(). This is useful for testing at the
interactive prompt:
15.4.5.1. Sub-commands¶
ArgumentParser.add_subparsers()
Many programs split up their functionality into a number of sub-commands, for example, the svn program can invoke sub-commands
like svn checkout, svn update, and svn commit.
15.4.4.6. The Namespace object
It may also be useful to have an ArgumentParser assign attributes to
an already existing object, rather than a new Namespace object. This
can be achieved by specifying the namespace= keyword argument:
Update, here's an example using argparse
strategizer = argparse.ArgumentParser()
strat_subs = strategizer.add_subparsers()
math = strat_subs.add_parser('math')
math_subs = math.add_subparsers()
math_max = math_subs.add_parser('max')
math_sum = math_subs.add_parser('sum')
math_max.set_defaults(strategy=max)
math_sum.set_defaults(strategy=sum)
strategizer.parse_args('math max'.split())
Out[46]: Namespace(strategy=<built-in function max>)
strategizer.parse_args('math sum'.split())
Out[47]: Namespace(strategy=<built-in function sum>)
I would like to note the reasons I would recommend argparse
Mainly the requirement to use strings that represent options and sub options to map to functions.
It's dead simple (after getting past the feature filled argparse module).
Uses a Python Standard Library Module. This let's others familiar with Python grok what your doing without getting into implementation details, and is very well documented for those who aren't.
Many extra features could be taken advantage of out of the box (not the best reason!).
Using argparse and Strategy Pattern together
For the plain and simple implementation of the Strategy Pattern, this has already been answered very well.
How to write Strategy Pattern in Python differently than example in Wikipedia?
#continuing from the above example
class MathStudent():
def do_math(self, numbers):
return self.strategy(numbers)
maximus = strategizer.parse_args('math max'.split(),
namespace=MathStudent())
sumera = strategizer.parse_args('math sum'.split(),
namespace=MathStudent())
maximus.do_math([1, 2, 3])
Out[71]: 3
sumera.do_math([1, 2, 3])
Out[72]: 6
The point of inlining functions is to blur the distinction between dictionaries and class instances. In javascript, for example, this techinque makes it very pleasant to write control classes that have little reusability. Also, and very helpfully the API then conforms to the well-known dictionary protocols, being self explanatory (pun intended).
You can do this in python - it just doesn't look like a dictionary! In fact, you can use the class keyword in ANY scope (i.e. a class def in a function, or a class def inside of a class def), and it's children can be the dictonary you are looking for; just inspect the attributes of a definition as if it was a javascript dictionary.
Example as if it was real:
somedict = {
"foo":5,
"one_function":your method here,
"two_function":your method here,
}
Is actually accomplished as
class somedict:
foo = 5
#classmethod
def one_method(self):
print self.foo
self.foo *= 2;
#classmethod
def two_method(self):
print self.foo
So that you can then say:
somedict.foo #(prints 5)
somedict.one_method() #(prints 5)
somedict.two_method() #(prints 10)
And in this way, you get the same logical groupings as you would with your "inlining".
I'm trying to create a function that chains results from multiple arguments.
def hi(string):
print(string)<p>
return hi
Calling hi("Hello")("World") works and becomes Hello \n World as expected.
the problem is when I want to append the result as a single string, but
return string + hi produces an error since hi is a function.
I've tried using __str__ and __repr__ to change how hi behaves when it has not input. But this only creates a different problem elsewhere.
hi("Hello")("World") = "Hello"("World") -> Naturally produces an error.
I understand why the program cannot solve it, but I cannot find a solution to it.
You're running into difficulty here because the result of each call to the function must itself be callable (so you can chain another function call), while at the same time also being a legitimate string (in case you don't chain another function call and just use the return value as-is).
Fortunately Python has you covered: any type can be made to be callable like a function by defining a __call__ method on it. Built-in types like str don't have such a method, but you can define a subclass of str that does.
class hi(str):
def __call__(self, string):
return hi(self + '\n' + string)
This isn't very pretty and is sorta fragile (i.e. you will end up with regular str objects when you do almost any operation with your special string, unless you override all methods of str to return hi instances instead) and so isn't considered very Pythonic.
In this particular case it wouldn't much matter if you end up with regular str instances when you start using the result, because at that point you're done chaining function calls, or should be in any sane world. However, this is often an issue in the general case where you're adding functionality to a built-in type via subclassing.
To a first approximation, the question in your title can be answered similarly:
class add(int): # could also subclass float
def __call__(self, value):
return add(self + value)
To really do add() right, though, you want to be able to return a callable subclass of the result type, whatever type it may be; it could be something besides int or float. Rather than trying to catalog these types and manually write the necessary subclasses, we can dynamically create them based on the result type. Here's a quick-and-dirty version:
class AddMixIn(object):
def __call__(self, value):
return add(self + value)
def add(value, _classes={}):
t = type(value)
if t not in _classes:
_classes[t] = type("add_" + t.__name__, (t, AddMixIn), {})
return _classes[t](value)
Happily, this implementation works fine for strings, since they can be concatenated using +.
Once you've started down this path, you'll probably want to do this for other operations too. It's a drag copying and pasting basically the same code for every operation, so let's write a function that writes the functions for you! Just specify a function that actually does the work, i.e., takes two values and does something to them, and it gives you back a function that does all the class munging for you. You can specify the operation with a lambda (anonymous function) or a predefined function, such as one from the operator module. Since it's a function that takes a function and returns a function (well, a callable object), it can also be used as a decorator!
def chainable(operation):
class CallMixIn(object):
def __call__(self, value):
return do(operation(self, value))
def do(value, _classes={}):
t = type(value)
if t not in _classes:
_classes[t] = type(t.__name__, (t, CallMixIn), {})
return _classes[t](value)
return do
add = chainable(lambda a, b: a + b)
# or...
import operator
add = chainable(operator.add)
# or as a decorator...
#chainable
def add(a, b): return a + b
In the end it's still not very pretty and is still sorta fragile and still wouldn't be considered very Pythonic.
If you're willing to use an additional (empty) call to signal the end of the chain, things get a lot simpler, because you just need to return functions until you're called with no argument:
def add(x):
return lambda y=None: x if y is None else add(x+y)
You call it like this:
add(3)(4)(5)() # 12
You are getting into some deep, Haskell-style, type-theoretical issues by having hi return a reference to itself. Instead, just accept multiple arguments and concatenate them in the function.
def hi(*args):
return "\n".join(args)
Some example usages:
print(hi("Hello", "World"))
print("Hello\n" + hi("World"))
i am working on a python client for the api of uwsgi.it and i found the necessity to write methods that accept lots of (optional) parameters that will be sent via http requests.
Initially i wanted to declare which parameters the user can insert, since they are so many i thought it was easier, and safer, for the user to have a list as parameters instead of leave him free to insert anything inside a dict and i ended up with something like this:
def alarms(self, container=None, _class=None, color=None,
vassal=None, level=None, line=None, filename=None,
func=None, with_total=None, range=None):
params = {k: v for k, v in locals().iteritems() if k != 'self' and v}
if '_class' in params:
params['class'] = params['_class']
del params['_class']
return self.get('alarms', params)
But it is pretty ugly and i really don't like this way to handle '_class' parameter. So the other possibility that comes to my mind is to accept a dictionary that can contain anything (or **kwargs), list the accepted keys in the docstring and then to sanitize the input. A possible way would be to declare a "private" method that accept only the allowed params. But then the same problems appears again! Any suggestion? Any best-practice for methods with so many parameters?
I agree that using **kwargs is a good idea, and you can easily sanitize its keys using a set. I'm using Python 2.6, so I don't have set comprehensions, but my code should be easy to translate to more modern versions.
FWIW, I actually posted a version of this program late last night, but then I decided it ought to do something about bad parameters, so I temporarily deleted it. Here's the revised version.
validate_params.py
#! /usr/bin/env python
''' Validate the keys in kwargs
Test keys against a container (set, tuple, list) of good keys,
supplying a value of None for missing keys
Also, if a key ends with an underscore, strip it.
Written by PM 2Ring 2014.11.15
From
http://stackoverflow.com/questions/26945235/best-practice-handle-functions-with-lots-of-parameters-and-reserved-names
'''
import sys
def test(**kwargs):
good_keys = ("container", "class_", "color",
"vassal", "level", "line", "filename",
"func", "with_total", "range")
new_kwargs = validate_keys(kwargs, good_keys)
for t in new_kwargs.items():
print "%-12s : %r" % t
#def alarms(**kwargs):
#good_keys = ("container", "class_", "color",
#"vassal", "level", "line", "filename",
#"func", "with_total", "range")
#return self.get('alarms', validate_keys(kwargs, good_keys))
def validate_keys(kwargs, good_keys):
good_keys = set(good_keys)
bad_keys = set(kwargs.keys()) - good_keys
if bad_keys:
bad_keys = ', '.join(bad_keys)
print >>sys.stderr, "Unknown parameters: %s\n" % bad_keys
raise KeyError, bad_keys
new_kwargs = {}
for k in good_keys:
new_kwargs[k.rstrip('_')] = kwargs.get(k, None)
return new_kwargs
test(color="red", class_="top",
#bar=1, foo=3, #Some bad keys
level=2, func="copy",filename="text.txt")
output
container : None
with_total : None
level : 2
color : 'red'
filename : 'text.txt'
vassal : None
range : None
func : 'copy'
line : None
class : 'top'
one thing you could do to tidy up the logic is change your dict comprehension to:
params = {k.strip("_"): v for k, v in locals().iteritems() if k != 'self' and v is not None}
# ^^^^^^^^^^^
Then you don't need to do anything about class; Also, I would probably use class_ in favor of _class, since the latter indicates that the argument is "private", but the former is often a hint that "i need to use a keyword as an identifier"
When a method begins to require many inputs, one software design practice to consider is to declare a special class which contains properties for each of those input values and then you can instantiate and populate it separately from it's use. That way you only need to pass a single reference into your method signature (to the encapsulating class) instead of references to each property. As your object model grows you can even add builder and validation methods to help you easily generate your new class and verify it's properties if needed.
How to define a class in Python
Also, consider design patterns and SOLID design principals as ways to improve your code's form, function and maintainability. Get intimately familiar with these patterns and you will have the knowledge you need to truly up your game and move from a software programmer to a lead or engineer.
http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29
http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29
http://en.wikipedia.org/wiki/Software_design_pattern
I just started building a text based game yesterday as an exercise in learning Python (I'm using 3.3). I say "text based game," but I mean more of a MUD than a choose-your-own adventure. Anyway, I was really excited when I figured out how to handle inheritance and multiple inheritance using super() yesterday, but I found that the argument-passing really cluttered up the code, and required juggling lots of little loose variables. Also, creating save files seemed pretty nightmarish.
So, I thought, "What if certain class hierarchies just took one argument, a dictionary, and just passed the dictionary back?" To give you an example, here are two classes trimmed down to their init methods:
class Actor:
def __init__(self, in_dict,**kwds):
super().__init__(**kwds)
self._everything = in_dict
self._name = in_dict["name"]
self._size = in_dict["size"]
self._location = in_dict["location"]
self._triggers = in_dict["triggers"]
self._effects = in_dict["effects"]
self._goals = in_dict["goals"]
self._action_list = in_dict["action list"]
self._last_action = ''
self._current_action = '' # both ._last_action and ._current_action get updated by .update_action()
class Item(Actor):
def __init__(self,in_dict,**kwds)
super().__init__(in_dict,**kwds)
self._can_contain = in_dict("can contain") #boolean entry
self._inventory = in_dict("can contain") #either a list or dict entry
class Player(Actor):
def __init__(self, in_dict,**kwds):
super().__init__(in_dict,**kwds)
self._inventory = in_dict["inventory"] #entry should be a Container object
self._stats = in_dict["stats"]
Example dict that would be passed:
playerdict = {'name' : '', 'size' : '0', 'location' : '', 'triggers' : None, 'effects' : None, 'goals' : None, 'action list' = None, 'inventory' : Container(), 'stats' : None,}
(The None's get replaced by {} once the dictionary has been passed.)
So, in_dict gets passed to the previous class instead of a huge payload of **kwds.
I like this because:
It makes my code a lot neater and more manageable.
As long as the dicts have at least some entry for the key called, it doesn't break the code. Also, it doesn't matter if a given argument never gets used.
It seems like file IO just got a lot easier (dictionaries of player data stored as dicts, dictionaries of item data stored as dicts, etc.)
I get the point of **kwds (EDIT: apparently I didn't), and it hasn't seemed cumbersome when passing fewer arguments. This just appears to be a comfortable way of dealing with a need for a large number of attributes at the the creation of each instance.
That said, I'm still a major python noob. So, my question is this: Is there an underlying reason why passing the same dict repeatedly through super() to the base class would be a worse idea than just toughing it out with nasty (big and cluttered) **kwds passes? (e.g. issues with the interpreter that someone at my level would be ignorant of.)
EDIT:
Previously, creating a new Player might have looked like this, with an argument passed for each attribute.
bob = Player('bob', Location = 'here', ... etc.)
The number of arguments needed blew up, and I only included the attributes that really needed to be present to not break method calls from the Engine object.
This is the impression I'm getting from the answers and comments thus far:
There's nothing "wrong" with sending the same dictionary along, as long as nothing has the opportunity to modify its contents (Kirk Strauser) and the dictionary always has what it's supposed to have (goncalopp). The real answer is that the question was amiss, and using in_dict instead of **kwds is redundant.
Would this be correct? (Also, thanks for the great and varied feedback!)
I'm not sure I understand your question exactly, because I don't see how the code looked before you made the change to use in_dict. It sounds like you have been listing out dozens of keywords in the call to super (which is understandably not what you want), but this is not necessary. If your child class has a dict with all of this information, it can be turned into kwargs when you make the call with **in_dict. So:
class Actor:
def __init__(self, **kwds):
class Item(Actor):
def __init__(self, **kwds)
self._everything = kwds
super().__init__(**kwds)
I don't see a reason to add another dict for this, since you can just manipulate and pass the dict created for kwds anyway
Edit:
As for the question of the efficiency of using the ** expansion of the dict versus listing the arguments explicitly, I did a very unscientific timing test with this code:
import time
def some_func(**kwargs):
for k,v in kwargs.items():
pass
def main():
name = 'felix'
location = 'here'
user_type = 'player'
kwds = {'name': name,
'location': location,
'user_type': user_type}
start = time.time()
for i in range(10000000):
some_func(**kwds)
end = time.time()
print 'Time using expansion:\t{0}s'.format(start - end)
start = time.time()
for i in range(10000000):
some_func(name=name, location=location, user_type=user_type)
end = time.time()
print 'Time without expansion:\t{0}s'.format(start - end)
if __name__ == '__main__':
main()
Running this 10,000,000 times gives a slight (and probably statistically meaningless) advantage passing around a dict and using **.
Time using expansion: -7.9877269268s
Time without expansion: -8.06108212471s
If we print the IDs of the dict objects (kwds outside and kwargs inside the function), you will see that python creates a new dict for the function to use in either case, but in fact the function only gets one dict forever. After the initial definition of the function (where the kwargs dict is created) all subsequent calls are just updating the values of that dict belonging to the function, no matter how you call it. (See also this enlightening SO question about how mutable default parameters are handled in python, which is somewhat related)
So from a performance perspective, you can pick whichever makes sense to you. It should not meaningfully impact how python operates behind the scenes.
I've done that myself where in_dict was a dict with lots of keys, or a settings object, or some other "blob" of something with lots of interesting attributes. That's perfectly OK if it makes your code cleaner, particularly if you name it clearly like settings_object or config_dict or similar.
That shouldn't be the usual case, though. Normally it's better to explicitly pass a small set of individual variables. It makes the code much cleaner and easier to reason about. It's possible that a client could pass in_dict = None by accident and you wouldn't know until some method tried to access it. Suppose Actor.__init__ didn't peel apart in_dict but just stored it like self.settings = in_dict. Sometime later, Actor.method comes along and tries to access it, then boom! Dead process. If you're calling Actor.__init__(var1, var2, ...), then the caller will raise an exception much earlier and provide you with more context about what actually went wrong.
So yes, by all means: feel free to do that when it's appropriate. Just be aware that it's not appropriate very often, and the desire to do it might be a smell telling you to restructure your code.
This is not python specific, but the greatest problem I can see with passing arguments like this is that it breaks encapsulation. Any class may modify the arguments, and it's much more difficult to tell which arguments are expected in each class - making your code difficult to understand, and harder to debug.
Consider explicitly consuming the arguments in each class, and calling the super's __init__ on the remaining. You don't need to make them explicit:
class ClassA( object ):
def __init__(self, arg1, arg2=""):
pass
class ClassB( ClassA ):
def __init__(self, arg3, arg4="", *args, **kwargs):
ClassA.__init__(self, *args, **kwargs)
ClassB(3,4,1,2)
You can also leave the variables uninitialized and use methods to set them. You can then use different methods in the different classes, and all subclasses will have access to the superclass methods.
Ok, I have a dictionary called food. food has two elements, both of which are dictionaries themselves, veg and dairy. veg has two elements root : Turnip, and stem : Asparagus. dairy has cheese : Cheddar and yogurt : Strawberry. I also have a new dictionary fruit which has red : Cherry and yellow : Banana.
food['veg']['root'] == 'Turnip'
food['dairy']['cheese'] == 'Cheddar'
etc and
fruit['red'] == 'Cherry'
Now I would like to add the "fruit" dictionary to the "food" dictionary in its entirety, so that I will have:
food['fruit']['red'] == 'Cherry'
I know that I could do something like this:
food['fruit'] = fruit
But that seems clumsy. I would like to do something like
food.Append(fruit)
But that doesn't do what I need.
(Edited to removed the initial capitals from variable names, since that seemed to be causing a distraction.)
Food['Fruit'] = Fruit is the right and proper way (apart from the capitalized names).
As #kindall wisely notes in the comment, there can be several names referencing the same dictionary, which is why one can't build a function that maps the object to its name and uses that as the new key in your food dict.
I know what you are trying to do. You are trying to avoid DRY in python. Sadly python, and many other languages, are very bad at this.
The main issue though is that You are mixing the names of your variables with the values in your program. It is a common faux pas in many programming languages.
If you really wanted to do this, the thing you have bound to the fruit=... variable would need to know its name.
You are trying to say, in python "graft this dict onto this other dict".
Python demands that you say it like "graft this dict onto this other dict, attaching it at "Fruit""
The only way around this is that the name "Fruit" already exist somewhere. But it doesn't: it only exists in a variable name, which is not in your program.
There are two solutions:
You could avoid ever creating a fruit=... variable, and instead directly graft it only the "Fruit" name. So you would only have to type "Fruit" once, but instead of not typing the somedict["Fruit"] like you want, we're avoiding typing the variable name. This is accomplished by programming in anonymous style:
somedict["Fruit"] = {'red':'apple', 'yellow':'banana'}
Sadly, python will not let you do this if your construction requires statements; you can only get away with this if you just have a literal. The other solution is:
You could create a function which does this for you:
graft(somedict, "Fruit", {'red':'apple', 'yellow':'banana'})
Sadly this too would not work if your construction required any kind of statement. You could create a variable x={'red':...} or something, but that defeats the whole purpose. The third way, which you shouldn't use, is locals(), but that still requires you to refer to the name.
In conclusion, IF you require significant for loops and functions and if statements, what you are trying to do is impossible in python, unless you change the entire way you construct your fruit=... dictionary. It would be possible with combinations of multiline lambdas, dictionary comprehensions (dict((k,v) for k,v in ...)), inline IFTRUE if EXPR else IFFALSE, etc. The danger of this style is that it very quickly becomes hard to read.
It is possible if you are able to express your dictionary as a literal dictionary, or a dictionary comprehension, or the output of a function which you have already written. In fact it's fairly easy (see other answers). Unfortunately the original question does not say how you are building these dictionaries.
Assuming those answers don't answer your question (that is, you are building these in a really complicated manner), you can write "meta" code: code that will make your dictionary for you, and abuse reflection. However the best solution in python is to just try to make your dictionary with iteration. For example:
foods = {
"Fruit": {...},
"Meats": makeMeats(),
}
for name,data in ...:
foods[name] = someProcessing(data)
foods.update(dataFromSomeFile) #almost same as last two lines
Is there any reason you're using the square brackets? Because you can represent this data structure with nested literal dictionaries:
food = {
'veg': {
'red': 'tomato',
'green': 'lettuce',
},
'fruit': {
'red': 'cherry',
'green': 'grape',
},
}
You can't do append because a dictionary is not a list: it has no order. What you want to do is update the dictionary with a new key/value pair. You need to use:
Food['Fruit'] = Fruit
or, alternatively:
Food.update({'Fruit': Fruit})
An unrelated note: it's not Python coding style to write variables with capitals. Fruit would be written as fruit instead.
The basic problem you have is that your dictionary does not know its own name. Which is normal; generally, any number of names can be bound to a Python object, and no single name is in any way privileged over any others. In other words, in a = {}; b = a, both a and b are names for the same dictionary, and a is not the "real" name of the dictionary just because it was assigned first. And in fact, a dictionary has no way to even know what name is on the left side of the variable.
So one alternative is to have the dictionary contain its own name as a key. For example:
fruit = {"_name": "fruit"}
fruit["red"] = "cherry"
food[fruit["_name"]] = fruit
Well, that didn't help much, did it? It did in a way, because fruit is now not a string any longer in the attachment to the food dictionary, so at least Python will give you an error message if you mistype it. But you're actually typing "fruit" even more than before: you now have to type it when you create the dictionary in addition to when you attach it to another dictionary. And there is a fair bit more typing in general.
Also, having the name as an item in the dictionary is kind of inconvenient; when you are iterating over the dictionary, you have to write code to skip it.
You could write a function to do the attachment for you:
def attach(main, other):
main[other["_name"]] = other
Then you don't have to repeat yourself when you attach the sub-dictionary to the main one:
fruit = {"_name": "fruit"}
fruit["red"] = "cherry"
attach(food, fruit)
And of course, now you can actually create a dictionary subclass that knows its own name and can attach a named subdictionary. As a bonus, we can make the name an attribute of the dictionary rather than storing it in the dictionary, which will keep the actual dictionary cleaner.
class NamedDict(dict):
def __init__(self, name="", seq=(), **kwargs):
dict.__init__(self, seq, **kwargs)
self.__name__ = name
def attach(self, other):
self[other.__name__] = other
food = NamedDict("food")
fruit = NamedDict("fruit")
fruit["red"] = "cherry"
food.attach(fruit)
But we still have one repeat, when the NamedDict is initially defined: food = NamedDict("food") for example. How do we dispense with that?
It is possible, though unwieldy and probably not worth the trouble. Python has two kinds of objects that have an "intrinsic" name: classes and functions. In other words:
class Foo:
pass
The above not only creates a variable named Foo in the current namespace, the class's name is also conveniently stored in the class's __name__ attribute. (Functions do something similar.) By abusing classes and metaclasses, we can exploit the underlying machinery to completely avoid repeating ourselves—with the minor drawback of having to write our dictionaries as though they were classes!
class NamedDict(dict):
class __metaclass__(type):
def __new__(meta, name, bases, attrs):
if "NamedDict" not in globals(): # we're defining the base class
return type.__new__(meta, name, bases, attrs)
else:
attrs.pop("__module__", None) # Python adds this; do not want!
return meta.NamedDict(name, **attrs)
class NamedDict(dict):
def __init__(self, name, seq=(), **kwargs):
dict.__init__(self, seq, **kwargs)
self.__name__ = name
def attach(self, other):
self[other.__name__] = other
__call__ = NamedDict
Now, instead of defining our dictionaries the usual way, we declare them as subclasses of NamedDict. Thanks to the metaclass, subclassing the outer NamedDict class actually creates instances of the inner NamedDict class (which is the same as before). The attributes of the subclass we define, if any, become items in the dictionary, like keyword arguments of dict().
class food(NamedDict): pass
class fruit(NamedDict): red = "cherry"
# or, defining each item separately:
class fruit(NamedDict): pass
fruit["red"] = "cherry"
food.attach(fruit)
As a bonus, you can still define a NamedDict the "regular" way, by instantiating it as a class:
fruit = NamedDict("fruit", red="cherry")
Be warned, though: the "class that's really a dictionary" is a pretty non-standard idiom for Python and I would suggest that you not ever actually do this, as other programmers will not find it at all clear. Still, this is how it can be done in Python.
You are probably looking for defaultdict. It works by adding a new empty dictionary whenever you ask for a new first level type.
Example shown below:
from collections import defaultdict
basic_foods = {'Veg' : {'Root' : 'Turnip'}, 'Dairy' : {'Cheese' : 'Cheddar'}}
foods = defaultdict(dict, basic_foods)
foods['Fruit']['Red'] = "Cherry"
print foods['Fruit']