Survey: improving the Python std lib docs

justin walters walters.justin01 at gmail.com
Thu May 18 11:10:50 EDT 2017


On Thu, May 18, 2017 at 8:08 AM, justin walters <walters.justin01 at gmail.com>
wrote:

>
>
> On Thu, May 18, 2017 at 12:09 AM, Deborah Swanson <
> python at deborahswanson.net> wrote:
>
>> Michael Torrie wrote, on Wednesday, May 17, 2017 3:11 PM
>> >
>> > On 05/17/2017 02:31 PM, Ned Batchelder wrote:
>> > > Can you give an example of such a method? Often, that signature is
>> > > used because there is no pre-conception of what the arguments might
>> > > be.
>> >
>> > I'm not sure if this afflicts the standard library, but in my
>> > own code, since Python doesn't support constructors with
>> > different signatures, you pretty much have to rely on kwargs
>> > with __init__() to handle different permutations of
>> > construction arguments.  Not that we don't know what the
>> > arguments might be, we just don't know which of them we'll
>> > have to deal with.  Maybe the standard library is better
>> > designed than my own code, but I find I have to implement
>> > __init__(self, **kwargs) all the time.
>>
>>
>> While I can respect and appreciate your specialized interest in specific
>> kwargs, and I read in other's posts that help()'s display of kwargs is
>> conditional on several things, I really want to reiterate and clarify my
>> beginner's request.
>>
>> I know of several functions I've used without any *args or **kwargs
>> because I had no clue from the docs what they might be. And, I know of
>> one function now, from posts in this list, which takes kwargs, but I
>> only know one application of one possible kwarg in this function because
>> one member of this list, Peter Otten, used it in a suggestion he gave
>> me.
>>
>> This is all there is in the docs for that function:
>>
>>
>> somenamedtuple._replace(kwargs)
>>
>>     Return a new instance of the named tuple replacing specified fields
>> with new values:
>> (Examples
>> box)---------------------------------------------------------------|
>> |    >>>
>> |
>> |
>> |
>> |    >>> p = Point(x=11, y=22)
>> |
>> |    >>> p._replace(x=33)
>> |
>> |    Point(x=33, y=22)
>> |
>> |
>> |
>> |    >>> for partnum, record in inventory.items():
>> |
>> |    ...     inventory[partnum] =
>> record._replace(price=newprices[partnum], |
>> |  timestamp=time.now())
>> |
>> |-----------------------------------------------------------------------
>> ----|
>>
>> From this doc entry's example, I (sort of) get that x is a keyword arg
>> that is to be equal to 33 for any use of p._replace() in the code
>> following, until
>> p._replace(kwarg) is respecified, or the code ends. So the response from
>> Python shows me that p has transformed to the Point(x=33, y=22). A
>> trivial example that doesn't begin to hint at the poential powers of
>> this kwarg.
>>
>> The inventory[partnum] example is also quite trivial compared to the
>> kwarg use that Peter showed me.
>>
>> When I asked him for an explanation, this is what I and he he said:
>>
>> Deborah Swanson wrote:
>>
>> > I know it's your "ugly" answer, but can I ask what the '**' in
>> >
>> > fix = {label: max(values, key=len)}
>> > group[:] = [record._replace(**fix) for record in group]
>> >
>> > means?
>>
>> (Peter wrote)
>> d = {"a": 1, "b": 2}
>> f(**d)
>>
>> is equivalent to
>>
>> f(a=1, b=2)
>>
>> so ** is a means to call a function with keyword arguments when you want
>> to
>> decide about the *names* at runtime. Example:
>>
>> >>> def f(a=1, b=2):
>> ...     print("a =", a)
>> ...     print("b =", b)
>> ...     print()
>> ...
>> >>> for d in [{"a": 10}, {"b": 42}, {"a": 100, "b": 200}]:
>> ...     f(**d)
>> ...
>> a = 10
>> b = 2
>>
>> a = 1
>> b = 42
>>
>> a = 100
>> b = 200
>>
>> Starting from a namedtuple `record`
>>
>> record._replace(Location="elswhere")
>>
>> creates a new namedtuple with the Location attribute changed to
>> "elsewhere",
>> and the slice [:] on the left causes all items in the `groups` list to
>> be
>> replaced with new namedtuples,
>>
>> group[:] = [record._replace(Location="elsewhere") for record in group]
>>
>> is basically the same as
>>
>> tmp = group.copy()
>> group.clear()
>> for record in tmp:
>>     group.append(record_replace(Location="elsewhere"))
>>
>> To support not just Location, but also Kind and Notes we need the double
>>
>> asterisk.
>>
>>
>>
>> Now, I understood what he meant from the context of the problem he was
>> helping me with, but, how in the world would I have gotten that possible
>> use of somenamedtuple._replace(kwargs) from the blurb and examples in
>> the docs? Or any other possible kwarg and how they're used, including
>> special operators like "**" ?
>>
>> If there's a tutorial somewhere on kwargs in general, what specific
>> types of kwargs there are, what special operators can be specifed for
>> them and how the kwargs are used, it would be very helpful to have that
>> tutorial referenced in a footnote-link next to kwargs whenever kwargs is
>> part of a function specification.
>>
>> Or, if no such tutorial exists, the footnote-link could point to any
>> more detailed information that might explain what this creature "kwargs"
>> might be.
>>
>> I have an item on my todo list to google "python kwargs", but it keeps
>> getting pushed deeper and deeper down my list because I have so little
>> hope that it will turn up anything useful.
>>
>> Deborah
>>
>> --
>> https://mail.python.org/mailman/listinfo/python-list
>>
>
>
> I agree that in a lot of situations `**kwargs` can be confusing.
>
> I usually operate under the assumption that a Python function takes two
> kinds of values:
>
> `*args`: A (named)? tuple of values. For example:
>
> ```
> def foo(*args):
>     for arg in args:
>         print(arg)
>
> foo(1, 2 ,3)
> >>> 1
> >>> 2
> >>> 3
> ```
>
> However, when naming position arguments:
>
> ```
> def foo(a, b, *args):
>     for arg in args:
>         print(arg)
>
> foo(1, 2, 3)
> >>> 3
> ```
>
> Therefore, I find that `*args* can generally be considered as an index in
> a (named)? tuple of
> function arguments.
>
> `**kwargs`: An unpacked dictionary. Shares most of it's behavior with
> `*args` except that
> values must have keys.
>
> I find `**kwargs` to be especially useful working with Django's ORM:
>
> Suppose we have the following model class:
> ```
> class Thing(models.Model):
>     name = models.CharField(max_length=255)
>     is_thing = models.BooleanField(blank=True, default=True)
> ```
>
> And we want to create a new instance of it from some json data our server
> received
> from the client:
> ```
> data = json.loads(str(request.body, encoding="utf8"))
> new_thing = Thing(**data).save()
> ```
>
> As long as the keys in the dictionary match the argument names for the
> method, they will be passed
> to the function as keyword arguments. Any keys that don't match argument
> names and aren't explicitly
> pulled of of the dict do not get used. in the above case, Django's Model
> class does some behind
> the scenes work with `hasattr` and `setattr` because it doesn't know until
> runtime which Model has
> which attributes.
>
> A simple example would be this class:
>
> ```
> class Bar(object):
>
>     def __init__(self, **kwargs):
>         for key, value in kwargs.items():
>             if hasattr(self, key):
>                 setattr(self, key, value)
> ```
>
> We can then inherit from this class and create our own with some
> attributes:
> ```
> class MyBar(Bar):
>
>     foo = ""
>     baz = ""
> ```
>
> We can populate an instance of our class with the following expressions:
> ```
> data = {"foo": "hello", "baz": "world"}
> my_instance = MyBar(**data)
>
> my_instance.foo
> >>> "hello"
>
> my_instance.baz
> >>> "world"
> ```
>
> So, args can be treated as a simple (named)? tuple or a simple dictionary.
> `*` unpacks a list or tuple
> and `**` unpacks a dictionary. I'm sure it's a lot more nuanced than this,
> but for practical reasons, the
> above explanation has never failed me.
>
> I hope I didn't miss the entire point of the thread. Someone needed help
> with `**kwargs` right?
>

Made a mistake at the end there, meant to type:

"So, args can be treated as a simple (named)? tuple or kwargs can be used
as a simple dictionary."



More information about the Python-list mailing list