In Python, if you have a dictionary
d = {'foo': 1, 'bar': False}
You can apply this onto a function that accept foo and bar keyword arguments by
def func(foo, bar):
# Do something complicated here
pass
func(**d)
But if instead, I wanted to call func with the namedtuple defined below:
from collections import namedtuple
Record = namedtuple('Record', 'foo bar')
r = Record(foo=1, bar=False)
func(r) # !!! this will not work
What's the syntax for this?
A namedtuple instance has a ._asdict() method:
func(**r._asdict())
but if the namedtuple attributes are in the same order as the arguments of the function, you could just apply it as a sequence instead:
func(*r)
Here the two values of the namedtuple are applied, in order, to the keyword arguments in the function. Those two arguments can be addressed as positional arguments still, after all!
For your sample function, both work:
>>> def func(foo, bar):
... print foo, bar
...
>>> from collections import namedtuple
>>> Record = namedtuple('Record', 'foo bar')
>>> r = Record(foo=1, bar=False)
>>> func(**r._asdict())
1 False
>>> func(*r)
1 False
Related
In a Python interactive console (IDLE, IPython, etc), if I enter a variable name by itself, I will get back the equivalent of printing that variable.
In [1]: foo = {'a':1, 'b':2}
In [2]: foo
Out [2]: {'a':1, 'b':2}
In [3]: print(foo)
Out [3]: {'a':1, 'b':2}
I'd like to incorporate this functionality into a container class, like:
class Foo():
def __init__(self, bar):
self.bar = bar
def __mysteryfunction__(self)
print(self.bar)
I'd like the class to print as before, but instead I get:
In [1]: foo = Foo({'a':1, 'b':2})
In [2]: foo
Out [2]: <__main__.foo at 0x1835c093128>
I've searched for nearly every permutation I can think of for what this might be called, and haven't found the same question. Is this a class method like I'm hoping, or something built into the console interpreter? If the latter, can it be modified?
For print x, x.__str__ is called.
For output in a REPL when an object is returned, x.__repr__ is called.
Read about str and repr functions.
This is the __str__ method of a class.
From the documentation:
object.__str__(self)
Called by str(object) and the built-in functions format() and print() to compute the “informal” or nicely printable string representation of an object. The return value must be a string object.
For example:
class Foo:
def __init__(self, bar):
self.bar = bar
def __str__(self):
return 'My name is foo and my bar is ' + self.bar
foobar = Foo('high')
print(foobar) # My name is foo and my bar is high
I can use inspect.getargspec to get the parameter names of any function, including bound methods:
>>> import inspect
>>> class C(object):
... def f(self, a, b):
... pass
...
>>> c = C()
>>> inspect.getargspec(c.f)
ArgSpec(args=['self', 'a', 'b'], varargs=None, keywords=None, defaults=None)
>>>
However, getargspec includes self in the argument list.
Is there a universal way to get the parameter list of any function (and preferably, any callable at all), excluding self if it's a method?
EDIT: Please note, I would like a solution which would on both Python 2 and 3.
inspect.signature excludes the first argument of methods:
>>> from inspect import signature
>>> list(signature(c.f).parameters)
['a', 'b']
You could also delete the first element of args manually:
from inspect import ismethod, getargspec
def exclude_self(func):
args = getargspec(func)
if ismethod(func):
args[0].pop(0)
return args
exclude_self(c.f) # ArgSpec(args=['a', 'b'], ...)
from collections import namedtuple
FooT = namedtuple('Foo', 'foo bar')
def Foo(foo=None, bar=None):
return FooT(foo,bar)
foo = Foo()
foo.foo = 29
throws attribute error
So, my use case is a datastructure which have optional fields.. but should be able to modify it if desired..
A defaultdict should be appropriate for what you want. It works by providing it a function on construction which it calls every time an unset element is accessed. Here's a demo:
>>> from collections import defaultdict
>>> d = defaultdict(lambda:None)
>>> d['foo'] = 10
>>> d['bar'] = 5
>>> print d['baz']
None
>>> d['baz'] = 15
>>> print d['baz']
15
Tuples are, by definition, immutable. Namedtuples follow this pattern as well.
In python3 it appears there is a SimpleNamespace [1] that you can use. If you want to simply use a read/write datastructure though you could create a class and put constraints on its members.
[1] - Why Python does not support record type i.e. mutable namedtuple
A namedtuple, like a tuple is not modifiable. Since the question is about namedtuple, in some case you may find ok (or sometimes even preferable) to create a new object with the _replace method. Of course the other references to the same object will be unchanged.
from collections import namedtuple
FooT = namedtuple('Foo', 'foo bar')
def Foo(foo=None, bar=None):
return FooT(foo,bar)
foo = Foo()
foo = foo._replace(foo=29)
For a slight variation on the above answers, why not extend the advice in the tutorial and have a class that returns None for any undefined attribute? For example:
class Foo(object):
def __getattr__(self, name):
return None
This is much the same as a defaultdict, but accessible via direct attributes much like a named tuple.
Why not just use a class?
class Foo(object):
def __init__(foo=None, bar=None):
self.foo = foo
self.bar = bar
foo = Foo()
foo.foo = 29
To create a property in a class you simply do self.property = value. I want to be able to have the properties in this class completely dependent on a parameter. Let us call this class Foo.
instances of the Foo class would take a list of tuples:
l = [("first","foo"),("second","bar"),("anything","you get the point")]
bar = Foo(l)
now the instance of the Foo class we assigned to bar would have the following properties:
bar.first
#foo
bar.second
#bar
bar.anything
#you get the point
Is this even remotely possible? How?
I thought of another answer you could use using type(). It's completely different to my current answer so I've added a different answer:
>>> bar = type('Foo', (), dict(l))()
>>> bar.first
'foo'
>>> bar.second
'bar'
>>> bar.anything
'you get the point'
type() returns a class, not an instance, hence the extra () at the end.
These are called attributes, rather than properties. With that in mind, the method setattr() becomes more obvious:
class Foo(object):
def __init__(self, l):
for k, v in l:
setattr(self, k, v)
This takes each key-value pair in l and sets the attribute k on the new instance of Foo (self) to v.
Using your example:
l = [("first","foo"),("second","bar"),("anything","you get the point")]
bar = Foo(l)
print bar.first
#foo
print bar.second
#bar
print bar.anything
#you get the point
There are two ways to do this:
Use setattr like this. This approach is feasible if you only need to process the initial list once, when the object is constructed.
class Foo:
def __init__(self, l):
for (a, b) in l:
setattr(self, a, b)
Define a custom __getattr__ method. Preferably, you would store the properties in a dict for faster lookup, but you can also search the original list. This is better if you want to later modify the list and want this to be reflected in the attributes of the object.
class Foo:
def __init__(self, l):
self.l = l
def __getattr__(self, name):
for a in self.l:
if a[0] == name:
return a[1]
return None
Something like this?
>>> class Foo:
... def __init__(self, mylist):
... for k, v in mylist:
... setattr(self, k, v)
...
>>> l = [("first","foo"),("second","bar"),("anything","you get the point")]
>>> bar = Foo(l)
>>> bar.first
'foo'
>>> bar.second
'bar'
>>> bar.anything
'you get the point'
Using setattr you can do this by passing in the list and just iterating through it.
setattr works.
>>> class Foo:
... def __init__(self,yahoo):
... for k,v in yahoo:
... setattr(self,k,v)
...
>>> l = [("first","foo"),("second","bar"),("anything","you get the point")]
>>> bar = Foo(l)
>>> print bar.first
foo
>>> print bar.second
bar
>>> print bar.anything
you get the point
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does *args and **kwargs mean?
I' just reading Mining the social web and encountered a python syntax that I can't figure out:
transforms = [(', Inc.', ''), (', Inc', ''), (', LLC', ''), (', LLP', '')]
"google, Inc.".replace(*transforms[0])
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax. I googled it, but the python docu really is not up for the job.
So what does the asterisk means here please? Thank you all.
The *argument format in python means: use all elements in the sequence argument and pass them as arguments to the function.
In this specific case, that translates to:
"google, Inc.".replace(', Inc.', '')
This is easiest demonstrated:
>>> def foo(arg1, arg2):
... print arg1, arg2
...
>>> arguments = ('spam', 'eggs')
>>> foo(*arguments)
spam, eggs
You can also use the **kw double star format to pass in keyword arguments:
>>> def foo(arg1='ham', arg2='spam'):
... print arg1, arg2
...
>>> arguments = dict(arg2='foo', arg1='bar')
>>> foo(**arguments)
bar, foo
and you can use the same spelling in a function definition to capture arbitrary positional and keyword arguments:
>>> def foo(*args, **kw):
... print args, kw
...
>>> foo('arg1', 'arg2', foo='bar', spam='eggs')
('arg1', 'arg2'), {'foo': 'bar', 'spam': 'eggs'}
The asterisk unpacks an iterable. I think it is best explained with an example:
>>> def exampleFunction (paramA, paramB, paramC):
print('A:', paramA)
print('B:', paramB)
print('C:', paramC)
>>> myTuple = ('foo', 'bar', 'baz')
>>> myTuple
('foo', 'bar', 'baz')
>>> exampleFunction(myTuple)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
exampleFunction(myTuple)
TypeError: exampleFunction() takes exactly 3 arguments (1 given)
>>> exampleFunction(myTuple[0], myTuple[1], myTuple[2])
A: foo
B: bar
C: baz
>>> exampleFunction(*myTuple)
A: foo
B: bar
C: baz
As you can see, we defined a function that takes three arguments and a tuple with three elements. Now if we want to use the values from the tuple directly, we cannot just pass the tuple and have it working. We could pass each element separately but that is just very verbose. What we do instead is use the asterisk to unpack the tuple and essentially use the elements from the tuple as arguments.
There is a second usage for the unpacking functionality when working with a unknown number of parameters:
>>> def example2 (*params):
for param in params:
print(param)
>>> example2('foo')
foo
>>> example2('foo', 'bar')
foo
bar
>>> example2(*myTuple)
foo
bar
baz
The asterisk allows us here to define a parameter that takes all the remaining values that were passed and packs it into an iterable, so we can iterate it.
It turns the tuple passed into a list of arguments. So
"google, Inc.".replace(*transforms[0])
becomes
"google, Inc.".replace(', Inc.', '')
This way you can programatically construct the list of arguments that are being passed (with variable length being a key advantage).
Check section 4.7.4 of the Python tutorial: http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax.
The * in front of transforms[0] only has meaning in a function call.
An alternative way of making this call with the data in the first tuple in the list is:
"Google, Inc.".replace(transforms[0][0],transforms[0][1])