Can you shortcut a python method like string replace? - python

In Python, you can say this:
s = 'fred loves mary'
r = s.replace
s = r('fred','ben')
print s
...and you get, very handily, sort of:
ben loves mary
However, because when you said r = s.replace you created an object that always contains 'fred loves mary', this doesn't produce "ben loves deb"...
s = 'fred loves mary'
r = s.replace
s = r('fred','ben')
s = r('mary','deb')
print s
...instead, it produces:
fred loves deb
I understand what's happening. But the ability to actually write quick code like the latter set and have it work, that is, produce:
ben loves deb
...would be awesome. So my question is, is there a way to do that other than defining ObviousFunction(s,x,y) or a class, viz:
class xs:
def __init__(self,s):
self.s = s
def r(self,x,y):
self.s = self.s.replace(x,y)
def __str__(self):
return self.s
s = xs('fred loves mary')
s = s.r('mary','deb')
s = s.r('fred','ben')
print s
...which actually does produce:
ben loves deb
...but for further string ops, requires the following type of gymnastics:
print s.s.upper()
...
BEN LOVES DEB
I took a look for any ability to extend an existing class (str in this case), but came up dry. Weak google-fu?
Hmmm. Ok, I got this far:
class xs(str)
def r(self,x,y):
return xs(self.replace(x,y))
...which will do this:
s = xs('fred loves mary')
s = s.r('fred','ben')
s = s.r('mary','deb')
# so far, so good; s is still class xs and you can go on forever
# but if you do this:
s = s.replace('ben','meezer')
# now s is an object of class str
...so is there any way to coerce a return value generally to the original class, as I've coerced the value .r() is returning? Other than just saying...
s = xs(s)
...afterwards?
I can see that one could extend this class until one had managed to wrap every type of string call that returns a string and then toss the (largish) result in one's toolbox, but that's a lot of work for something that seems like it ought to be easy. Still, it might be the only solution, and if so... I'm definitely going to end up with such a class. The number of things class str could gain are legion, quite aside from the benefits of shortening all that wordiness so the work/character factor increases.
Thanks for any insight.

Ok, after all the assistance here and some further trolling about the net, I have something that is very close to what I wanted. I've written a much more complete class, but the following snippets exercise the issues directly associated with my original inquiry:
class xs(str):
def __add__(self,a): # OPERATORS
return xs(str(self) + a) # +
def __mod__(self,tup):
return xs(str(self) % tup) # %
def __getslice__(self,b,c):
return xs(str(self)[b:c]) # [:]
def r(self,x,y): # replace, as 'r'
return xs(self.replace(x,y))
Using the above, class identity is maintained, the ability to code up replacements for every class str function that returns a string is there, and everything else works just the way it does with strings. so...
a = xs('fred loves mary')
a = a.r('fred','ben')
a = a.r('mary','deb')
print a
...results in...
ben loves deb
...and...
b = a[:3] # get 'ben'
c = a[-3:] # get 'deb'
d = xs('%s adores %s') # format string
e = d % (b,c) # do the formatting
e = e.r('ben','charlie')
f = e + ' (so I hear)'
print f,str(type(f))
...yields...
charlie adores deb (so I hear) <class '__main__.xs'>
So as we can see, class xs is maintained throughout, standard operations apply as per usual. Anything that's in class str that doesn't return a string can remain unmolested; anything that does should be taken care of as .replace() is here. Objects of class xs can be used pretty much anywhere a string can, and in many cases, strings can be used with objects of class xs without causing problems; notable exception is the first operand of + and %, as these must be of class xs in order for the operator overrides to get hold of them in the first place.
What would have been best would have been the ability to extend class str. But subclassing it provides most of the benefits.
If anyone is actually interested, I'll post the full class (mostly complete as of now) somewhere you can grab it. Includes dotted quad string handiness, class exceptions, yadda yadda. Running under Python 2.6.1, would require additional work for Python 3.
Thanks to everyone for the help!

You just need to do a little more hard-coding:
s = 'fred loves mary'
s = s.replace('fred','ben')
s = s.replace('mary','deb')
print s
Output:
ben loves deb

I hope the following code will help you and I am using python 2.7
class xs(object):
def __init__(self,s):
self.s = s
def r(self,x,y):
self.s = self.s.replace(x,y)
return self
def __getattr__(self, name ):
return getattr(self.s, name)
def __str__(self):
return self.s
s = xs('fred loves mary')
s = s.r('mary','deb')
s = s.r('fred','ben')
print s
print s.upper()

Related

Why the Python scope seems to behave differently for list variable and string variable?

Say that I have the following Python code:
import sys
class DogStr:
tricks = ''
def add_trick(self, trick):
self.tricks = trick
class DogList:
tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
# Dealing with DogStr
d = DogStr()
e = DogStr()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)
# Dealing with DogList
d = DogList()
e = DogList()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)
Running this code with Python 3.6.5, I get the following output:
trick d
trick e
['trick d', 'trick e']
['trick d', 'trick e']
The difference between DogStr and DogList is that I treat tricks as a string on former and as a list on the latter.
When dealing with DogStr, tricks is behaving as an instance variable. BUT with DogList tricks is behaving as a class variable.
I was expecting to see the same behaviour on both calls, i.e.: if the two last lines of the output are identical, so should be the first two.
So I wonder. What is the explanation for that?
The difference is not int the type of the object, but in what your code does to it.
There is a big difference between these two:
self.tricks = trick
and:
self.tricks.append(trick)
The first one self.tricks = trick assigns a value to attribute tricks of self.
The second one self.tricks.append(trick) retrieves self.tricks and calls a method on it (which here modifies its values).
The problem, in your case, is that there is no tricks defined on self instance, so self.tricks.append gets the tricks attribute of the class and modifies it, but self.tricks = ... creates a new attribute on self instead.
The fact that one of them is a string and the other is a list is not really relevant. It would be the same if both were lists.
Note that they could not both be strings because strings are immutable and thus have no append method
How to fix it?
This is wrong:
def add_trick(self, trick):
self.tricks = trick
If tricks is a class attribute, add_trick should be a class method:
#classmethod
def add_trick(cls, trick):
cls.tricks = trick
If there are reasons for add_trick to be an instance method, then simply do this:
def add_trick(self, trick):
DogStr.tricks = trick

Using Python classes for encapsulation, not instantiation

I have run across a few examples of Python code that looks something like this:
class GiveNext :
list = ''
def __init__(self, list) :
GiveNext.list = list
def giveNext(self, i) :
retval = GiveNext.list[i]
return retval
class GiveABCs(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
GiveABCs.i += 1
return GiveNext.giveNext(self, GiveABCs.i)
class Give123s(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
Give123s.i += 1
return GiveNext.giveNext(self, Give123s.i)
for i in range(3):
print(GiveABCs('ABCDEFG').giveNext())
print(Give123s('12345').giveNext())
the output is: A 1 B 2 C 3
If I were more clever, I could figure out how to put the string literals inside the constructor...but that is not crucial right now.
My question is on the use of classes this way. Yes, an instance of the class gets created each time that that the call within the print() gets made. Yet the i's are 'permanent' in each class.
This strikes me as less of an object-oriented approach, and more of a way of using classes to accomplish encapsulation and/or a functional programming paradigm, since the instances are entirely transitory. In other words, an instance of the class is never instantiated for its own purposes; it is there only to allow access to the class-wide methods and variables within to do their thing, and then it is tossed away. In many cases, it seems like the class mechanism is used in a back-handed way, in order to leverage inheritance and name resolution/spacing: an instance of the class is never really required to be built or used, conceptually.
Is this standard Python form?
Bonus question: how would I put the string literals inside each class declaration? Right now, even if I change the _init__ for GiveABCs to
GiveNext.__init__(self, 'wxyz')
it completely ignores the 'wxyz' literal, and uses the 'ABCDEF' one - even though it is never mentioned...
Please don't learn Python with this code. As mentioned by others, this code goes against many Python principles.
One example: list is a Python builtin type. Don't overwrite it, especially not with a string instance!
The code also mixes class and instance variables and doesn't use super() in subclasses.
This code tries to simulate an iterator. So simply use an iterator:
give_abcs = iter('ABCDEFG')
give_123s = iter('12345')
for _ in range(3):
print(next(give_abcs))
print(next(give_123s))
# A
# 1
# B
# 2
# C
# 3
If you really want to fix the above code, you could use:
class GiveNext :
def __init__(self, iterable) :
self.i = - 1
self.iterable = iterable
def giveNext(self) :
self.i += 1
return self.iterable[self.i]
giveABCs = GiveNext('ABCDEFG')
give123s = GiveNext('12345')
for _ in range(3):
print(giveABCs.giveNext())
print(give123s.giveNext())
It outputs:
A
1
B
2
C
3
This code in the OP is an incredible amount of crap. Not only it is long, unreadable, misuses OO features, and does not use Python features at all (an iterator being a standard Python feature). Here is a suggestion for a more Pythonist approach:
giveABCs = iter('ABCDEFG')
give123s = iter('12345')
for i in range(3):
print(next(giveABCs))
print(next(give123s))
About your bonus question: I guess you are modifing the _init__() method of GiveABCs and Give123s. It is normal that whatever code you put in there has no effect, because the Python constructor is __init__() (with 2 leading underscores, not 1). So The constructor from GiveNext is not overloaded.

What do I do when I need a self referential dictionary?

I'm new to Python, and am sort of surprised I cannot do this.
dictionary = {
'a' : '123',
'b' : dictionary['a'] + '456'
}
I'm wondering what the Pythonic way to correctly do this in my script, because I feel like I'm not the only one that has tried to do this.
EDIT: Enough people were wondering what I'm doing with this, so here are more details for my use cases. Lets say I want to keep dictionary objects to hold file system paths. The paths are relative to other values in the dictionary. For example, this is what one of my dictionaries may look like.
dictionary = {
'user': 'sholsapp',
'home': '/home/' + dictionary['user']
}
It is important that at any point in time I may change dictionary['user'] and have all of the dictionaries values reflect the change. Again, this is an example of what I'm using it for, so I hope that it conveys my goal.
From my own research I think I will need to implement a class to do this.
No fear of creating new classes -
You can take advantage of Python's string formating capabilities
and simply do:
class MyDict(dict):
def __getitem__(self, item):
return dict.__getitem__(self, item) % self
dictionary = MyDict({
'user' : 'gnucom',
'home' : '/home/%(user)s',
'bin' : '%(home)s/bin'
})
print dictionary["home"]
print dictionary["bin"]
Nearest I came up without doing object:
dictionary = {
'user' : 'gnucom',
'home' : lambda:'/home/'+dictionary['user']
}
print dictionary['home']()
dictionary['user']='tony'
print dictionary['home']()
>>> dictionary = {
... 'a':'123'
... }
>>> dictionary['b'] = dictionary['a'] + '456'
>>> dictionary
{'a': '123', 'b': '123456'}
It works fine but when you're trying to use dictionary it hasn't been defined yet (because it has to evaluate that literal dictionary first).
But be careful because this assigns to the key of 'b' the value referenced by the key of 'a' at the time of assignment and is not going to do the lookup every time. If that is what you are looking for, it's possible but with more work.
What you're describing in your edit is how an INI config file works. Python does have a built in library called ConfigParser which should work for what you're describing.
This is an interesting problem. It seems like Greg has a good solution. But that's no fun ;)
jsbueno as a very elegant solution but that only applies to strings (as you requested).
The trick to a 'general' self referential dictionary is to use a surrogate object. It takes a few (understatement) lines of code to pull off, but the usage is about what you want:
S = SurrogateDict(AdditionSurrogateDictEntry)
d = S.resolve({'user': 'gnucom',
'home': '/home/' + S['user'],
'config': [S['home'] + '/.emacs', S['home'] + '/.bashrc']})
The code to make that happen is not nearly so short. It lives in three classes:
import abc
class SurrogateDictEntry(object):
__metaclass__ = abc.ABCMeta
def __init__(self, key):
"""record the key on the real dictionary that this will resolve to a
value for
"""
self.key = key
def resolve(self, d):
""" return the actual value"""
if hasattr(self, 'op'):
# any operation done on self will store it's name in self.op.
# if this is set, resolve it by calling the appropriate method
# now that we can get self.value out of d
self.value = d[self.key]
return getattr(self, self.op + 'resolve__')()
else:
return d[self.key]
#staticmethod
def make_op(opname):
"""A convience class. This will be the form of all op hooks for subclasses
The actual logic for the op is in __op__resolve__ (e.g. __add__resolve__)
"""
def op(self, other):
self.stored_value = other
self.op = opname
return self
op.__name__ = opname
return op
Next, comes the concrete class. simple enough.
class AdditionSurrogateDictEntry(SurrogateDictEntry):
__add__ = SurrogateDictEntry.make_op('__add__')
__radd__ = SurrogateDictEntry.make_op('__radd__')
def __add__resolve__(self):
return self.value + self.stored_value
def __radd__resolve__(self):
return self.stored_value + self.value
Here's the final class
class SurrogateDict(object):
def __init__(self, EntryClass):
self.EntryClass = EntryClass
def __getitem__(self, key):
"""record the key and return"""
return self.EntryClass(key)
#staticmethod
def resolve(d):
"""I eat generators resolve self references"""
stack = [d]
while stack:
cur = stack.pop()
# This just tries to set it to an appropriate iterable
it = xrange(len(cur)) if not hasattr(cur, 'keys') else cur.keys()
for key in it:
# sorry for being a duche. Just register your class with
# SurrogateDictEntry and you can pass whatever.
while isinstance(cur[key], SurrogateDictEntry):
cur[key] = cur[key].resolve(d)
# I'm just going to check for iter but you can add other
# checks here for items that we should loop over.
if hasattr(cur[key], '__iter__'):
stack.append(cur[key])
return d
In response to gnucoms's question about why I named the classes the way that I did.
The word surrogate is generally associated with standing in for something else so it seemed appropriate because that's what the SurrogateDict class does: an instance replaces the 'self' references in a dictionary literal. That being said, (other than just being straight up stupid sometimes) naming is probably one of the hardest things for me about coding. If you (or anyone else) can suggest a better name, I'm all ears.
I'll provide a brief explanation. Throughout S refers to an instance of SurrogateDict and d is the real dictionary.
A reference S[key] triggers S.__getitem__ and SurrogateDictEntry(key) to be placed in the d.
When S[key] = SurrogateDictEntry(key) is constructed, it stores key. This will be the key into d for the value that this entry of SurrogateDictEntry is acting as a surrogate for.
After S[key] is returned, it is either entered into the d, or has some operation(s) performed on it. If an operation is performed on it, it triggers the relative __op__ method which simple stores the value that the operation is performed on and the name of the operation and then returns itself. We can't actually resolve the operation because d hasn't been constructed yet.
After d is constructed, it is passed to S.resolve. This method loops through d finding any instances of SurrogateDictEntry and replacing them with the result of calling the resolve method on the instance.
The SurrogateDictEntry.resolve method receives the now constructed d as an argument and can use the value of key that it stored at construction time to get the value that it is acting as a surrogate for. If an operation was performed on it after creation, the op attribute will have been set with the name of the operation that was performed. If the class has a __op__ method, then it has a __op__resolve__ method with the actual logic that would normally be in the __op__ method. So now we have the logic (self.op__resolve) and all necessary values (self.value, self.stored_value) to finally get the real value of d[key]. So we return that which step 4 places in the dictionary.
finally the SurrogateDict.resolve method returns d with all references resolved.
That'a a rough sketch. If you have any more questions, feel free to ask.
If you, just like me wandering how to make #jsbueno snippet work with {} style substitutions, below is the example code (which is probably not much efficient though):
import string
class MyDict(dict):
def __init__(self, *args, **kw):
super(MyDict,self).__init__(*args, **kw)
self.itemlist = super(MyDict,self).keys()
self.fmt = string.Formatter()
def __getitem__(self, item):
return self.fmt.vformat(dict.__getitem__(self, item), {}, self)
xs = MyDict({
'user' : 'gnucom',
'home' : '/home/{user}',
'bin' : '{home}/bin'
})
>>> xs["home"]
'/home/gnucom'
>>> xs["bin"]
'/home/gnucom/bin'
I tried to make it work with the simple replacement of % self with .format(**self) but it turns out it wouldn't work for nested expressions (like 'bin' in above listing, which references 'home', which has it's own reference to 'user') because of the evaluation order (** expansion is done before actual format call and it's not delayed like in original % version).
Write a class, maybe something with properties:
class PathInfo(object):
def __init__(self, user):
self.user = user
#property
def home(self):
return '/home/' + self.user
p = PathInfo('thc')
print p.home # /home/thc
As sort of an extended version of #Tony's answer, you could build a dictionary subclass that calls its values if they are callables:
class CallingDict(dict):
"""Returns the result rather than the value of referenced callables.
>>> cd = CallingDict({1: "One", 2: "Two", 'fsh': "Fish",
... "rhyme": lambda d: ' '.join((d[1], d['fsh'],
... d[2], d['fsh']))})
>>> cd["rhyme"]
'One Fish Two Fish'
>>> cd[1] = 'Red'
>>> cd[2] = 'Blue'
>>> cd["rhyme"]
'Red Fish Blue Fish'
"""
def __getitem__(self, item):
it = super(CallingDict, self).__getitem__(item)
if callable(it):
return it(self)
else:
return it
Of course this would only be usable if you're not actually going to store callables as values. If you need to be able to do that, you could wrap the lambda declaration in a function that adds some attribute to the resulting lambda, and check for it in CallingDict.__getitem__, but at that point it's getting complex, and long-winded, enough that it might just be easier to use a class for your data in the first place.
This is very easy in a lazily evaluated language (haskell).
Since Python is strictly evaluated, we can do a little trick to turn things lazy:
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
d1 = lambda self: lambda: {
'a': lambda: 3,
'b': lambda: self()['a']()
}
# fix the d1, and evaluate it
d2 = Y(d1)()
# to get a
d2['a']() # 3
# to get b
d2['b']() # 3
Syntax wise this is not very nice. That's because of us needing to explicitly construct lazy expressions with lambda: ... and explicitly evaluate lazy expression with ...(). It's the opposite problem in lazy languages needing strictness annotations, here in Python we end up needing lazy annotations.
I think with some more meta-programmming and some more tricks, the above could be made more easy to use.
Note that this is basically how let-rec works in some functional languages.
The jsbueno answer in Python 3 :
class MyDict(dict):
def __getitem__(self, item):
return dict.__getitem__(self, item).format(self)
dictionary = MyDict({
'user' : 'gnucom',
'home' : '/home/{0[user]}',
'bin' : '{0[home]}/bin'
})
print(dictionary["home"])
print(dictionary["bin"])
Her ewe use the python 3 string formatting with curly braces {} and the .format() method.
Documentation : https://docs.python.org/3/library/string.html

Accessing the name of an instance in Python for printing

So as part of problem 17.6 in "Think Like a Computer Scientist", I've written a class called Kangaroo:
class Kangaroo(object):
def __init__(self, pouch_contents = []):
self.pouch_contents = pouch_contents
def __str__(self):
'''
>>> kanga = Kangaroo()
>>> kanga.put_in_pouch('olfactory')
>>> kanga.put_in_pouch(7)
>>> kanga.put_in_pouch(8)
>>> kanga.put_in_pouch(9)
>>> print kanga
"In kanga's pouch there is: ['olfactory', 7, 8, 9]"
'''
return "In %s's pouch there is: %s" % (object.__str__(self), self.pouch_contents)
def put_in_pouch(self, other):
'''
>>> kanga = Kangaroo()
>>> kanga.put_in_pouch('olfactory')
>>> kanga.put_in_pouch(7)
>>> kanga.put_in_pouch(8)
>>> kanga.put_in_pouch(9)
>>> kanga.pouch_contents
['olfactory', 7, 8, 9]
'''
self.pouch_contents.append(other)
What's driving me nuts is that I'd like to be able to write a string method that would pass the unit test underneath __str__ as written. What I'm getting now instead is:
In <__main__.Kangaroo object at 0x4dd870>'s pouch there is: ['olfactory', 7, 8, 9]
Bascially, what I'm wondering if there is some function that I can perform on kanga = Kangaroo such that the output of the function is those 5 characters, i.e. function(kanga) -> "kanga".
Any ideas?
Edit:
Reading the first answer has made me realize that there is a more concise way to ask my original question. Is there a way to rewrite __init__ such that the following code is valid as written?
>>> somename = Kangaroo()
>>> somename.name
'somename'
To put your request into perspective, please explain what name you would like attached to the object created by this code:
marsupials = []
marsupials.append(Kangaroo())
This classic essay by the effbot gives an excellent explanation.
To answer the revised question in your edit: No.
Now that you've come clean in a comment and said that the whole purpose of this naming exercise was to distinguish between objects for debugging purposes associated with your mutable default argument:
In CPython implementations of Python at least, at any given time, all existing objects have a unique ID, which may be obtained by id(obj). This may be sufficient for your debugging purposes. Note that if an object is deleted, that ID (which is a memory address) can be re-used by a subsequently created object.
I wasn't going to post this but if you only want this for debugging then here you go:
import sys
class Kangaroo(object):
def __str__(self):
flocals = sys._getframe(1).f_locals
for ident in flocals:
if flocals[ident] is self:
name = ident
break
else:
name = 'roo'
return "in {0}'s pouch, there is {1}".format(name, self.pouch_contents)
kang = Kangaroo()
print kang
This is dependent on CPython (AFAIK) and isn't suitable for production code. It wont work if the instance is in any sort of container and may fail for any reason at any time. It should do the trick for you though.
It works by getting the f_locals dictionary out of the stack frame that represents the namespace where print kang is called. The keys of f_locals are the names of the variables in the frame so we just loop through it and test if each entry is self. If so, we break. If break is not executed, then we didn't find an entry and the loops else clause assigns the value 'roo' as requested.
If you want to get it out of a container of some sort, you need to extend this to look through any containers in f_locals. You could either return the key if it's a dictlike container or the index if it's something like a tuple or list.
class Kangaroo(object):
def __init__(self, pouch_contents=None, name='roo'):
if pouch_contents is None:
self.pouch_contents = [] # this isn't shared with all other instances
else:
self.pouch_contents = pouch_contents
self.name = name
...
kanga = Kangaroo(name='kanga')
Note that it's good style not to put spaces around = in the arguments
What you want is basically impossible in Python, even with the suggested "hacks". For example,
what would the following code print?
>>> kanga1 = kanga2 = kanga3 = Kangaroo()
>>> kanga2.name
???
>>> kanga3.name
???
or
>>> l = [Kangaroo()]
>>> l[0].name
???
If you want "named" objects, just supply a name to your object
def __init__(self, name):
self.name = name
More explicit (which we like with Python) and consistent in all cases. Sure you can do something like
>>> foo = Kangaroo("bar")
>>> foo.name
'bar'
but foo will be just one of the possibly many labels the instance has. The name is explicit and permanent. You can even enforce unique naming if you want (while you can reuse a variable as much as you want for different objects)
I hadn't seen aaronasterling's hackish answer when I started working on this, but in any case here's a hackish answer of my own:
class Kangaroo(object):
def __init__(self, pouch_contents = ()):
self.pouch_contents = list(pouch_contents)
def __str__(self):
if not hasattr(self, 'name'):
for k, v in globals().iteritems():
if id(v) == id(self):
self.name = k
break
else:
self.name = 'roo'
return "In %s's pouch there is: %s" % (self.name, self.pouch_contents)
kanga = Kangaroo()
print kanga
You can break this by looking at it funny (it works as written, but it will fail as part of a doctest), but it works. I'm more concerned with what's possible than with what's practical at this point in my learning experience, so I'm glad to see that there are at least two different ways to do a thing I figured should be possible to do. Even if they're bad ways.

Are object literals Pythonic?

JavaScript has object literals, e.g.
var p = {
name: "John Smith",
age: 23
}
and .NET has anonymous types, e.g.
var p = new { Name = "John Smith", Age = 23}; // C#
Something similar can be emulated in Python by (ab)using named arguments:
class literal(object):
def __init__(self, **kwargs):
for (k,v) in kwargs.iteritems():
self.__setattr__(k, v)
def __repr__(self):
return 'literal(%s)' % ', '.join('%s = %r' % i for i in sorted(self.__dict__.iteritems()))
def __str__(self):
return repr(self)
Usage:
p = literal(name = "John Smith", age = 23)
print p # prints: literal(age = 23, name = 'John Smith')
print p.name # prints: John Smith
But is this kind of code considered to be Pythonic?
Why not just use a dictionary?
p = {'name': 'John Smith', 'age': 23}
print p
print p['name']
print p['age']
Have you considered using a named tuple?
Using your dict notation
>>> from collections import namedtuple
>>> L = namedtuple('literal', 'name age')(**{'name': 'John Smith', 'age': 23})
or keyword arguments
>>> L = namedtuple('literal', 'name age')(name='John Smith', age=23)
>>> L
literal(name='John Smith', age=23)
>>> L.name
'John Smith'
>>> L.age
23
It is possible to wrap this behaviour into a function easily enough
def literal(**kw):
return namedtuple('literal', kw)(**kw)
the lambda equivalent would be
literal = lambda **kw: namedtuple('literal', kw)(**kw)
but personally I think it's silly giving names to "anonymous" functions
From ActiveState:
class Bunch:
def __init__(self, **kwds):
self.__dict__.update(kwds)
# that's it! Now, you can create a Bunch
# whenever you want to group a few variables:
point = Bunch(datum=y, squared=y*y, coord=x)
# and of course you can read/write the named
# attributes you just created, add others, del
# some of them, etc, etc:
if point.squared > threshold:
point.isok = 1
I don't see anything wrong with creating "anonymous" classes/instances. It's often very convienient to create one with simple function call in one line of code. I personally use something like this:
def make_class( *args, **attributes ):
"""With fixed inability of using 'name' and 'bases' attributes ;)"""
if len(args) == 2:
name, bases = args
elif len(args) == 1:
name, bases = args[0], (object, )
elif not args:
name, bases = "AnonymousClass", (object, )
return type( name, bases, attributes )
obj = make_class( something = "some value" )()
print obj.something
For creating dummy objects it works just fine. Namedtuple is ok, but is immutable, which can be inconvenient at times. And dictionary is... well, a dictionary, but there are situations when you have to pass something with __getattr__ defined, instead of __getitem__.
I don't know whether it's pythonic or not, but it sometimes speeds things up and for me it's good enough reason to use it (sometimes).
I'd say that the solution you implemented looks pretty Pythonic; that being said, types.SimpleNamespace (documented here) already wraps this functionality:
from types import SimpleNamespace
p = SimpleNamespace(name = "John Smith", age = 23)
print(p)
From the Python IAQ:
As of Python 2.3 you can use the syntax
dict(a=1, b=2, c=3, dee=4)
which is good enough as far as I'm concerned. Before Python 2.3 I used the one-line function
def Dict(**dict): return dict
I think object literals make sense in JavaScript for two reasons:
In JavaScript, objects are only way to create a “thing” with string-index properties. In Python, as noted in another answer, the dictionary type does that.
JavaScript‘s object system is prototype-based. There’s no such thing as a class in JavaScript (although it‘s coming in a future version) — objects have prototype objects instead of classes. Thus it’s natural to create an object “from nothing”, via a literal, because all objects only require the built-in root object as a prototype. In Python, every object has a class — you’re sort of expected to use objects for things where you’d have multiple instances, rather than just for one-offs.
Thus no, object literals aren’t Pythonic, but they are JavaScripthonic.
A simple dictionary should be enough for most cases.
If you are looking for a similar API to the one you indicated for the literal case, you can still use dictionaries and simply override the special __getattr__ function:
class CustomDict(dict):
def __getattr__(self, name):
return self[name]
p = CustomDict(user='James', location='Earth')
print p.user
print p.location
Note: Keep in mind though that contrary to namedtuples, fields are not validated and you are in charge of making sure your arguments are sane. Arguments such as p['def'] = 'something' are tolerated inside a dictionary but you will not be able to access them via p.def.

Categories

Resources