This is my first post here. I'm getting my feet wet with Python and I
need to know how can I check whether a variable is of type dictionary.
Something like this:
if isdict(a) then print "a is a dictionary"
Regards,
Guillermo
if type(a) is dict:
print "a is a dictionnary!"
++
Sam
> This is my first post here. I'm getting my feet wet with Python and I
> need to know how can I check whether a variable is of type dictionary.
>
> Something like this:
>
> if isdict(a) then print "a is a dictionary"
if isinstance(a, dict): ...
But note that it's more common in Python to try to use it in the intended
way, and catch the possible errors.
Look for "duck typing" in this group, and the difference between "easier
to ask forgiveness
than permission" and "look before you leap".
--
Gabriel Genellina
What makes you say you "need" to know this ? Except for a couple corner
cases, you usually don't need to care about this. If you told us more
about the actual problem (instead of asking about what you think is the
solution), we might be of more help...
> Something like this:
>
> if isdict(a) then print "a is a dictionary"
Should this work for subclasses of dicts ? Should this work for
non-subclasses of dict implementing the dict protocol ?
class MyDict(dict):
pass
a = MyDict()
type(a) is dict
=> False
>What makes you say you "need" to know this ? Except for a couple corner
>cases, you usually don't need to care about this. If you told us more
>about the actual problem (instead of asking about what you think is the
>solution), we might be of more help...
Good point.
I want to iterate recursively a dictionary whose elements might be
strings or nested tuples or dictionaries and then convert values to a
tagged format according to some rules.
d = {'a':"i'm a", 'b':(1,2,3),'c':{'a':"i'm a",'x':"something",'y':
('a','b','c')}}
I'm just designing the algorithm, but I think Python dictionaries can
hold any kind of sequence?
Regards,
Guillermo
> I'm just designing the algorithm, but I think Python dictionaries
> can hold any kind of sequence?
(Watch out, dicts are no sequence types.)
I recommend relying duck typing as long as it's feasible. I. e. if
it can be subscripted like a dict, it is a dict. If this makes
problems, use the type({}) approach.
Regards,
Björn
--
BOFH excuse #56:
Electricians made popcorn in the power supply
just do so, if it's not a dict you can always catch the exception,
then handle tuples (or the exception), then strings which should work
always (of course also error handling here according to your needs)
> I'm just designing the algorithm, but I think Python dictionaries can
> hold any kind of sequence?
python dicts can hold any kind of object (as a value). What you can't
do is have a list as the key, but that is easily circumvented by using
a tuple (or any other immutable type).
hth
martin
--
http://tumblr.marcher.name
https://twitter.com/MartinMarcher
http://www.xing.com/profile/Martin_Marcher
http://www.linkedin.com/in/martinmarcher
You are not free to read this message,
by doing so, you have violated my licence
and are required to urinate publicly. Thank you.
Welcome onboard !-)
>> What makes you say you "need" to know this ? Except for a couple corner
>> cases, you usually don't need to care about this. If you told us more
>> about the actual problem (instead of asking about what you think is the
>> solution), we might be of more help...
>
> Good point.
>
> I want to iterate recursively a dictionary whose elements might be
> strings or nested tuples or dictionaries and then convert values to a
> tagged format according to some rules.
If you're absolutely definitively 101% sure that you'll never have
anything else in your dict - IOW : this dict is an internal part of your
module, produced by the module and consumed by the module -, then it
*might* be one of the corner cases where testing type (either directly
or - preferably - via isinstance) is the right thing to do.
> d = {'a':"i'm a", 'b':(1,2,3),'c':{'a':"i'm a",'x':"something",'y':
> ('a','b','c')}}
>
> I'm just designing the algorithm, but I think Python dictionaries can
> hold any kind of sequence?
Any Python object (which include classes, modules, functions etc) can be
used as value.
This instanciates a dict, call type() on it, and discard the dict -
which is useless since the dict type is a builtin. Also, when you want
to test identity, use an identity test.
if type(a) is dict:
print "blah blah blah"
This could be solved with dynamic polymorphism instead of
introspection, which might simplify things depending on how your
dictionary is constructed.
class Value(object):
def to_tagged_format(self):
raise NotImplementedError
class StringValue(Value):
def to_tagged_format(self):
...
class Tuplevalue(Value):
def to_tagged_format(self):
...
class DictValue(Value):
def to_tagged_format(self):
...
for k, v in d.iteritems():
d[k] = v.to_tagged_format()
You can also get the dynamic polymorphism without invoking inheritance
by specifying a protocol that the values in your dict must implement,
instead. Protocols are plentiful in Python, perhaps more popular than
type hierarchies.
--
Neil Cerutti <mr.cerut...@gmail.com>
I'm used to languages with stricter rules than Python. I've read a bit
about Python protocols, but where could I get some more info on
implementation details? Sounds very interesting.
Regards,
Guillermo
A protocol is just an interface that an object agrees to implement. In
your case, you would state that every object stored in your special
dict must implement the to_tagged_value method with certain agreeable
semantics.
Python implements sequence types, mapping types, iterators, file
streams, and other things with protocols.
For example, iterators must support the "next" and and "__iter__" methods.
Using a protocol instead instead of a type hierarchy requires less
boring boilerplate, and I suppose in Python will usuallly be
preferable except when you want to inherit implementation as well as
interface. In that case, inheritance often saves boilerplate cide
rather than increases it.
It's also misnomered as duck-typing (clearly it should be nomed quack-typing).
--
Neil Cerutti <mr.cerut...@gmail.com>
Hm... I've searched about the implementation of protocols and now (I
believe) I know how to implement the iterable protocol, for instance,
but have no clue about how to define my own... I'm surely not thinking
the right way, but I don't seem to be able to wrap my head around the
implementation details of "custom" protocols... Is it just a matter of
extending the different object classes (dict, list, tuple...)? Where
do you put the interface/protocol code? :-?
Regards,
Guillermo
A protocol is a convention that you insist other objects must follow, not
code. To implement that convention, naturally you need to write code, but
the convention makes the protocol, not the code.
Some examples:
To be considered a writable file, your object must include a write()
method and a close() method. It doesn't matter what those methods do
exactly, so long as they behave reasonably. For instance, the close()
method might do nothing, and the write() method might send an SMS.
To be a random-access writable file, it must also include a seek() method.
To be a sequence, your object must obey the sequence protocol, which says
it has a __getitem__ method which takes integer arguments starting at 0
and increasing, until it raises IndexError.
You don't have to write any code to create a protocol, you just have to
tell people what it is. Here's my parrot protocol:
To be a parrot, your object must have a method speak() which takes an
integer argument and returns the case-insensitive string "spam" repeated
that many times.
I'm done. I have a protocol. But if I want to actually use it, then I
need an object that obeys it, and if I can't wait for somebody else to
write it, I need to write one myself. So here it is:
class Viking(object):
def __init__(self, case='upper'):
if case == 'upper':
self.case = str.upper
else:
self.case = str.lower
def speak(self, n):
return self.case("spam"*n)
And now Viking instances are also parrots, or rather, they obey the
parrot protocol:
>>> v = Viking()
>>> v.speak(3)
'SPAMSPAMSPAM'
I hope this helps.
--
Steven
So you only need to ·want· to have a protocol? That's amazing... Far
beyond the claim that Python is easy. You define protocols in writing
basically! Even my grandma could have her own Python protocol.
Okay, so I think I know where's the catch now -- you must rely on the
fact that the protocol is implemented, there's no way to enforce it if
you're expecting a parrot-like object. You'd try to call the speak()
method and deal with the error if there's no such method?
Thanks a lot!
Guillermo
> Okay, so I think I know where's the catch now -- you must rely on the
> fact that the protocol is implemented, there's no way to enforce it if
> you're expecting a parrot-like object. You'd try to call the speak()
> method and deal with the error if there's no such method?
That's right. That's called "duck typing" -- if all you want is something
that quacks like a duck, then it doesn't matter if it actually is a duck
or not.
Or if you prefer: if it quacks like a duck and swims like a duck, then
it's close enough to a duck as to make no difference.
Sometimes though, you need to check for a parrot up front. So I'd so this:
try:
something.speak
except AttributeError:
# No speak() method, so it can't be a parrot.
do_something_else()
else:
# It seems to follow the parrot protocol.
yummy_goodness = something.speak(5)
assert "spam" in yummy_goodness.lower()
--
Steven
The syntax checker over here raised a warning on this one. "So close
to a duck as." (I'm using the so...as construct in my Propositional
Calculus program.)
> try:
> something.speak
> except AttributeError:
> # No speak() method, so it can't be a parrot.
> do_something_else()
It might be a dead parrot. HAR!
> else:
> # It seems to follow the parrot protocol.
> yummy_goodness = something.speak(5)
> assert "spam" in yummy_goodness.lower()
P.S. Is 'resemblant' a word? So resemblant of a duck as.
In addition to duck typing, in some cases an explicit declaration may
be useful: "I implement the Parrot protocol". The zope.interface
package does that: there is a way to define interfaces (a set of
methods any implementation must provide), and classes can assert "I
implement this interface", and one can determine whether a class
implements or not certain interface. See http://pypi.python.org/pypi/zope.interface
Abstract Base Classes (ABC, for Python 3.0) provide a similar concept
(but they're not the same thing). See http://www.python.org/dev/peps/pep-3119/
Of course there is some overlapping between all of these techniques -
one should choose the best method in each case.
--
Gabriel Genellina
Indeed. But even with static declarative typing ŕ la Java, you must rely
on the fact that the protocol is *correctly* implemented (what about
having file.close sending mails to all your contacts and then rebooting
the computer ?-). IOW, at some point, you have to trust the coder anyway.
> there's no way to enforce it if
> you're expecting a parrot-like object.
Yes there is:
> You'd try to call the speak()
> method
That's it.
> and deal with the error if there's no such method?
Either catch the AttributeError and raise a TypeError or ValueError (or
some more specific one) instead, or just let the AttributeError
propagate - whichever makes more sens given the context. I'd say the
default would be to catch the AttributeError and raise a TypeError
instead (that's at least what len() does when passed an unsized object).
> class MyDict(dict):
> pass
> a = MyDict()
> type(a) is dict
> => False
isinstance(a, dict)
=> True
So the question you need to answer is whether you want to determine whether
an object is exactly of type dict, or whether it you are willing to accept
types derived from dict also.
> So the question you need to answer is whether you want to determine
> whether an object is exactly of type dict, or whether it you are willing
> to accept types derived from dict also.
Or other mappings that don't inherit from dict but behave just like
dicts, such as UserDict.
--
Steven