UrlSplitResult: невозможно _замещать поля

#python #urllib #namedtuple

#python #urllib #namedtuple

Вопрос:

Я пытаюсь ввести базовую аутентификацию в URL-адрес с помощью split-inject-join:

     url = urllib.parse.urlsplit(url)
    new_url = url._replace(username=user, password=password)
 

Но я удивлен поведением SplitResult , которое я получаю от urllib.parse.urlsplit метода:

 >>> v = urlsplit('http://a.b/c/d')
>>> v.username is None and v.password is None  # None, but accessible
True
>>> v._replace(scheme='ftp')  # beautiful!  Just like expected.
SplitResult(scheme='ftp', netloc='a.b', path='/c/d', query='', fragment='')

# however...
>>> v._replace(scheme='ftp', username='u', password='p')
...ValueError: Got unexpected field names: ['username', 'password']
 

Кажется, что None поля в этом SplitResult не могут быть заменены. Это странно, поскольку в документации утверждается, что это именованный кортеж.

Когда я делаю эквивалент с помощью самостоятельно созданного именованного кортежа, оказывается, что поля ‘None’ могут быть заменены без проблем.

 >>> T = namedtuple("T", ("a", "b", "c"))
>>> t = T(a=1, b=2, c=None)
>>> t
T(a=1, b=2, c=None)
>>> t._replace(c=3)
T(a=1, b=2, c=3)
 

Но то же исключение может быть вызвано заменой несуществующего поля.

 >>> t._replace(d=4)  # should raise, please
...ValueError: Got unexpected field names: ['d']
# I was expecting an AttributeError, but hey...
 

Однако в этом случае неожиданное поле действительно недоступно:

 >>> t.d is None
...AttributeError: 'T' object has no attribute 'd'
 

Есть идеи SplitResult , что отличает?

Ответ №1:

В документации не указаны индексы для полей username , password , hostname , или port . Это говорит о том, что они на самом деле не являются частью namedtuple , а вместо этого являются просто атрибутами SplitResult объекта. Глядя на реализацию CPython, кажется SplitResult , что она наследуется как от namedtuple, содержащего первые несколько полей с индексами, так и от mixin, который добавляет другие поля в качестве свойств.