[Libguestfs] Extending the nbdkit python plugin

Tomáš Golembiovský tgolembi at redhat.com
Thu Nov 21 15:49:00 UTC 2019


This may be confusing at first but is not that difficult once you wrap
your head around it.

There are two types of arguments in Python: positional(*) and
keyword(**). There is a rule that all positional arguments are defined
before the keyword arguments. Also once an argument has a default value
it is considered keyword (not positional). There are some nuances for
which is best to reach to some documentation.


> Another possibility is we could encourage existing Python plugins to
> add **kwargs to all functions where we might plausibly add extra
> parameters in future, ie. the above would become:
> 
>   def pwrite (h, buf, offset, **kwargs):
> 
> This still requires all Python plugins to change, but at least they
> would remain backwards compatible with old and new nbdkit.  However I
> couldn't actually work out how to make this work because:
> 
>   >>> def test(a, **kwargs):

Here you defined single positional argument 'a'.

>   ...   pass
>   ... 
>   >>> test(1)
>   >>> test(1,2)

You are passing two positional arguments. A keyword argument has to have
a name. E.g. this will work: test(1, foo=2)

>   Traceback (most recent call last):
>     File "<stdin>", line 1, in <module>
>   TypeError: test() takes 1 positional argument but 2 were given
> 

Check the attached script for some examples. Hopefully that will help
you get a better grasp.

    Tomas

-- 
Tomáš Golembiovský <tgolembi at redhat.com>
-------------- next part --------------
#!/usr/bin/env python3

def abc(*args, **kwargs):
    print(args)
    print(kwargs)

def with_positional(a, b, c, *args, **kwargs):
    print(a, b, c)
    print(args)
    print(kwargs)

# Wrong: cannot define keyword arguments before positional
#def with_keyword(a=None, b=None, c=None, *args, **kwargs):
#    pass

def with_keyword(*args, a=None, b=None, c=None, **kwargs):
    print(a, b, c)
    print(args)
    print(kwargs)

# This is also possible
def with_keyword2(*args, a, b, c, **kwargs):
    pass
    print(a, b, c)
    print(args)
    print(kwargs)

# (1, 'abc')
# {'foo': 2, 'bar': 3}
abc(1, 'abc', foo=2, bar=3)
# Wrong: cannot pass positional arguments after keyword arguments
#abc(1, 'abc', foo=2, bar=3, 4, 5)
print('---')

# 1 2 3
# (4, 5)
# {'foo': 10, 'bar': 11}
with_positional(1, 2, 3, 4, 5, foo=10, bar=11)
# Wrong: a,b,c are alrady bound to 4,5,6
#with_positional(4, 5, 6, foo=10, bar=11, a=1, b=2, c=3)

# This works as one would expect
with_positional(a=1, b=2, c=3, foo=10, bar=11)
# These two are wrong
#with_positional(4, a=1, b=2, c=3, foo=10, bar=11)
#with_positional(a=1, b=2, c=3, 4, foo=10, bar=11)

print('---')
with_keyword(4, 5, foo=10, bar=11)
with_keyword(4, 5, foo=10, bar=11, a=1, b=2, c=3)

# These two are equivalent
with_keyword2(foo=10, bar=11, a=1, b=2, c=3)
with_keyword2(a=1, b=2, c=3, foo=10, bar=11)


More information about the Libguestfs mailing list