好的,下面我将介绍一些 Python 的基础语法,并提供相应的代码实例。
1. 变量和数据类型
- 变量:Python 中变量不需要声明类型,直接赋值即可。
name = "Alice" # 字符串
age = 30 # 整数
height = 1.75 # 浮点数
is_student = True # 布尔值
-
数据类型:Python 中常见的数据类型包括:
- 整数 (int):例如:1, -10, 100
- 浮点数 (float):例如:3.14, -2.5, 0.0
- 字符串 (str):例如:"hello", 'world', "123"
- 布尔值 (bool):True 或 False
- 列表 (list):有序可变序列,例如:[1, 2, 3], ['a', 'b', 'c']
- 元组 (tuple):有序不可变序列,例如:(1, 2, 3), ('a', 'b', 'c')
- 字典 (dict):键值对的集合,例如:{'name': 'Alice', 'age': 30}
2. 运算符
- 算术运算符:+ (加), - (减), * (乘), / (除), // (整除), % (取余), ** (幂)
x = 10
y = 3
print(x + y) # 输出 13
print(x / y) # 输出 3.333...
print(x // y) # 输出 3
print(x % y) # 输出 1
print(x ** y) # 输出 1000
- 比较运算符:== (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于)
a = 5
b = 8
print(a > b) # 输出 False
print(a != b) # 输出 True
- 逻辑运算符:and (与), or (或), not (非)
age = 25
is_adult = age >= 18 and age <= 60
print(is_adult) # 输出 True
is_weekend = "Saturday" == "Saturday" or "Sunday" == "Sunday"
print(is_weekend) # Output True
3. 控制流
- if 语句:条件判断
age = 15
if age >= 18:
print("成年人")
else:
print("未成年人")
- for 循环:遍历序列
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
- while 循环:满足条件时重复执行
count = 0
while count < 5:
print(count)
count += 1
4. 函数
-
定义函数:使用
def
关键字
def greet(name):
print("Hello, " + name + "!")
greet("Bob") # 调用函数,输出 Hello, Bob!
5. 字符串操作
-
字符串拼接:使用
+
或join()
first_name = "John"
last_name = "Doe"
full_name = first_name + " " + last_name
print(full_name) # John Doe
words = ["Hello", "world", "!"]
sentence = " ".join(words) # 效率更高
print(sentence) # Hello world !
- 字符串格式化:使用 f-string (Python 3.6+)
name = "Alice"
age = 30
message = f"My name is {name} and I am {age} years old."
print(message) # My name is Alice and I am 30 years old.
6. 列表操作
-
添加元素:
append()
,insert()
numbers = [1, 2, 3]
numbers.append(4) # 在末尾添加
numbers.insert(0, 0) # 在指定位置插入
print(numbers) # [0, 1, 2, 3, 4]
-
删除元素:
remove()
,pop()
numbers = [1, 2, 3]
numbers.remove(2) # 删除指定元素
removed_number = numbers.pop(0) # 删除指定索引的元素并返回
print(numbers) # [3]
print(removed_number) # 1
- 切片:获取子列表
numbers = [0, 1, 2, 3, 4]
sub_list = numbers[1:4] # 索引1到3的元素(不包括4)
print(sub_list) # [1, 2, 3]
这些只是 Python 的一些基础语法。通过学习和实践这些内容,你就可以开始编写简单的 Python 程序了。建议你多查阅相关资料,并进行大量的练习,以加深理解和掌握。 网上有很多优质的 Python 教程和资源,例如 Python 官方文档、菜鸟教程、廖雪峰的 Python 教程等等,可以帮助你更好地学习 Python。
好的,在掌握了 Python 基础语法之后,我们可以进一步学习一些高级语法,以编写更高效、更简洁、更强大的代码。下面我将介绍一些常用的 Python 高级语法,并提供相应的代码实例。
1. 列表推导式 (List Comprehensions)
列表推导式提供了一种简洁的方式来创建列表。
# 传统方法
squares = []
for x in range(10):
squares.append(x**2)
# 列表推导式
squares = [x**2 for x in range(10)]
print(squares) # 输出 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的列表推导式
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # 输出 [0, 4, 16, 36, 64]
2. 生成器 (Generators)
生成器是一种特殊的迭代器,可以按需生成值,而不是一次性生成所有值,从而节省内存。
# 生成器函数
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 使用生成器
for num in fibonacci(10):
print(num) # 依次输出斐波那契数列的前10个数
# 生成器表达式
squares = (x**2 for x in range(10))
for num in squares:
print(num)
#将生成器转化为list
squares_list = list(x**2 for x in range(10))
print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
3. 装饰器 (Decorators)
装饰器用于在不修改原函数代码的情况下,为函数添加额外的功能,例如日志记录、性能测试等。
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间:{end_time - start_time} 秒")
return result
return wrapper
@timer # 使用装饰器
def slow_function():
time.sleep(2)
return "Done!"
result = slow_function()
print(result) # 输出 "Done!" 和函数执行时间
4. 上下文管理器 (Context Managers)
上下文管理器用于管理资源的分配和释放,例如文件操作、数据库连接等,确保资源在使用完毕后能够正确关闭。
# 使用 with 语句打开文件,自动关闭文件
with open("my_file.txt", "w") as f:
f.write("Hello, world!")
# 自定义上下文管理器
class MyContext:
def __enter__(self):
print("进入上下文")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文")
def do_something(self):
print("在上下文中执行操作")
with MyContext() as context:
context.do_something()
5. 迭代器 (Iterators) 和 可迭代对象 (Iterables)
-
可迭代对象:可以使用
for
循环遍历的对象,例如列表、元组、字符串、字典等。 -
迭代器:实现了
__iter__()
和__next__()
方法的对象。__iter__()
返回迭代器自身,__next__()
返回序列中的下一个元素,如果没有元素则抛出StopIteration
异常。
my_list = [1, 2, 3]
my_iter = iter(my_list) # 获取迭代器
print(next(my_iter)) # 输出 1
print(next(my_iter)) # 输出 2
print(next(my_iter)) # 输出 3
# print(next(my_iter)) # 抛出 StopIteration 异常
for i in my_list: # for 循环实际上是调用了 iter() 和 next()
print(i)
6. 闭包 (Closures)
闭包是指函数及其周围状态(词法环境)的捆绑。即使外部函数已经执行完毕,闭包仍然可以访问外部函数的变量。
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
add_5 = outer_function(5)
result = add_5(3) # 输出 8
7. *args
和 **kwargs
-
*args
用于传递可变数量的位置参数。 -
**kwargs
用于传递可变数量的关键字参数。
def my_function(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print(f"{key}: {value}")
my_function(1, 2, 3, name="Alice", age=30)
8. 元类 (Metaclasses)
元类是创建类的类。它们控制类的创建过程,可以用于修改类的行为。这部分内容较为高级,一般情况下不需要用到。
这些高级语法可以帮助你编写更加 Pythonic (符合 Python 风格) 的代码,提高代码的效率和可读性。建议结合实际项目进行练习,逐步掌握这些高级特性。
好的,在掌握了 Python 基础语法之后,我们可以进一步学习一些高级语法,以编写更高效、更简洁、更强大的代码。下面我将介绍一些常用的 Python 高级语法,并提供相应的代码实例。
1. 列表推导式 (List Comprehensions)
列表推导式提供了一种简洁的方式来创建列表。
# 传统方法
squares = []
for x in range(10):
squares.append(x**2)
# 列表推导式
squares = [x**2 for x in range(10)]
print(squares) # 输出 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的列表推导式
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # 输出 [0, 4, 16, 36, 64]
2. 生成器 (Generators)
生成器是一种特殊的迭代器,可以按需生成值,而不是一次性生成所有值,从而节省内存。
# 生成器函数
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 使用生成器
for num in fibonacci(10):
print(num) # 依次输出斐波那契数列的前10个数
# 生成器表达式
squares = (x**2 for x in range(10))
for num in squares:
print(num)
#将生成器转化为list
squares_list = list(x**2 for x in range(10))
print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
3. 装饰器 (Decorators)
装饰器用于在不修改原函数代码的情况下,为函数添加额外的功能,例如日志记录、性能测试等。
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间:{end_time - start_time} 秒")
return result
return wrapper
@timer # 使用装饰器
def slow_function():
time.sleep(2)
return "Done!"
result = slow_function()
print(result) # 输出 "Done!" 和函数执行时间
4. 上下文管理器 (Context Managers)
上下文管理器用于管理资源的分配和释放,例如文件操作、数据库连接等,确保资源在使用完毕后能够正确关闭。
# 使用 with 语句打开文件,自动关闭文件
with open("my_file.txt", "w") as f:
f.write("Hello, world!")
# 自定义上下文管理器
class MyContext:
def __enter__(self):
print("进入上下文")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文")
def do_something(self):
print("在上下文中执行操作")
with MyContext() as context:
context.do_something()
5. 迭代器 (Iterators) 和 可迭代对象 (Iterables)
-
可迭代对象:可以使用
for
循环遍历的对象,例如列表、元组、字符串、字典等。 -
迭代器:实现了
__iter__()
和__next__()
方法的对象。__iter__()
返回迭代器自身,__next__()
返回序列中的下一个元素,如果没有元素则抛出StopIteration
异常。
my_list = [1, 2, 3]
my_iter = iter(my_list) # 获取迭代器
print(next(my_iter)) # 输出 1
print(next(my_iter)) # 输出 2
print(next(my_iter)) # 输出 3
# print(next(my_iter)) # 抛出 StopIteration 异常
for i in my_list: # for 循环实际上是调用了 iter() 和 next()
print(i)
6. 闭包 (Closures)
闭包是指函数及其周围状态(词法环境)的捆绑。即使外部函数已经执行完毕,闭包仍然可以访问外部函数的变量。
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
add_5 = outer_function(5)
result = add_5(3) # 输出 8
7. *args
和 **kwargs
-
*args
用于传递可变数量的位置参数。 -
**kwargs
用于传递可变数量的关键字参数。
def my_function(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print(f"{key}: {value}")
my_function(1, 2, 3, name="Alice", age=30)
8. 元类 (Metaclasses)
元类是创建类的类。它们控制类的创建过程,可以用于修改类的行为。这部分内容较为高级,一般情况下不需要用到。
这些高级语法可以帮助你编写更加 Pythonic (符合 Python 风格) 的代码,提高代码的效率和可读性。建议结合实际项目进行练习,逐步掌握这些高级特性。
好的,下面我将讲解一些 Python 的高级使用方法,并提供相应的实现代码。这些技巧可以帮助你编写更简洁、高效和可维护的代码。
1. 列表推导式与生成器表达式
- 列表推导式:快速创建列表。
# 生成 0 到 9 的平方列表
squares = [x**2 for x in range(10)]
print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 生成 0 到 9 中偶数的平方列表
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # 输出: [0, 4, 16, 36, 64]
# 嵌套列表推导式
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
- 生成器表达式:类似列表推导式,但不立即生成所有元素,而是按需生成,节省内存。
# 生成 0 到 9 的平方的生成器
squares_generator = (x**2 for x in range(10))
for num in squares_generator:
print(num) # 依次输出 0 到 81
# 注意:生成器只能迭代一次
# list(squares_generator) # 再次调用会返回空列表
2. 装饰器
在不修改原函数代码的情况下,为函数添加额外的功能,例如日志记录、性能测试、权限验证等。
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间: {end_time - start_time:.4f} 秒")
return result
return wrapper
@timer # 使用装饰器
def slow_function(n):
time.sleep(n)
return "Done!"
slow_function(2) # 输出 "函数 slow_function 执行时间: 2.0000 秒" 和 "Done!"
@timer
def add(a,b):
return a + b
print(add(1,2)) # 输出 "函数 add 执行时间: 0.0000 秒" 和 3
3. 上下文管理器
使用 with
语句管理资源,例如文件操作、网络连接等,确保资源在使用完毕后正确释放。
# 文件操作
with open("my_file.txt", "w") as f:
f.write("Hello, world!") # 文件会被自动关闭
# 自定义上下文管理器
import contextlib
@contextlib.contextmanager
def my_context():
print("进入上下文")
yield "context value" # yield 语句返回上下文对象
print("退出上下文")
with my_context() as value:
print(f"在上下文中: {value}")
# 输出:
# 进入上下文
# 在上下文中: context value
# 退出上下文
4. 迭代器与生成器
-
迭代器:实现了
__iter__()
和__next__()
方法的对象。
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
my_list = [1, 2, 3]
my_iter = MyIterator(my_list)
for item in my_iter:
print(item)
-
生成器:一种特殊的迭代器,使用
yield
关键字。
def my_generator(n):
for i in range(n):
yield i
for item in my_generator(3):
print(item)
5. *args
和 **kwargs
-
*args
:接收任意数量的位置参数,以元组形式传递。 -
**kwargs
:接收任意数量的关键字参数,以字典形式传递。
def my_function(*args, **kwargs):
print("位置参数:", args)
print("关键字参数:", kwargs)
my_function(1, 2, 3, name="Alice", age=30)
# 输出:
# 位置参数: (1, 2, 3)
# 关键字参数: {'name': 'Alice', 'age': 30}
6. 闭包
函数及其周围状态(词法环境)的捆绑。内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
add_5 = outer_function(5) # add_5 是一个闭包
result = add_5(3) # 输出 8
print(result)
add_10 = outer_function(10)
result2 = add_10(5) # 输出 15
print(result2)
7. 元类 (Metaclasses)
控制类的创建过程。这部分比较高级,一般情况下不需要用到。
class MyMeta(type):
def __new__(cls, name, bases, attrs):
attrs['custom_attribute'] = 'Hello from metaclass'
return type.__new__(cls, name, bases, attrs)
class MyClass(metaclass=MyMeta):
pass
print(MyClass.custom_attribute) # 输出 'Hello from metaclass'
8. 描述器 (Descriptors)
控制属性的访问、设置和删除。
class MyDescriptor:
def __get__(self, instance, owner):
print("Getting attribute")
return instance._value
def __set__(self, instance, value):
print("Setting attribute")
instance._value = value
def __delete__(self, instance):
print("Deleting attribute")
del instance._value
class MyClass:
my_attribute = MyDescriptor()
obj = MyClass()
obj.my_attribute = 10 # 输出 "Setting attribute"
print(obj.my_attribute) # 输出 "Getting attribute" 和 10
del obj.my_attribute # 输出 "Deleting attribute"
这些高级技巧可以提高你的 Python 编程水平,编写更高效、更优雅的代码。建议结合实际项目进行练习,才能更好地掌握它们。
nHN4r0EPATDNodfohBuCNkGIAEQcAXbET+qgZhJJ8VQvADIDB+rYUWyvJGHJwDW5xY/fqOW8AVTaSEjrfKUXcfeNZ4TXq4+p8qgTeXV+zNnGQ8baeCO700S+zw4PST3BBbuipc8iMh2PovgZU5vG+1M9/X32Eb3CsqlMBy4vC/23h0xfeMK6BFZJQKXoEWTLGcUQtyYJTnZ/lmQS/+r9tdqTiHQPJau7si6azAKgeUJ9xEKX3whX74z5cJQ9CjdyTfsIZmgyKvToHbFhaIv0GmJV2l2XjCpHQtpeVFYWUefebdLltVLr1a8HIayMk8EOknYPs9AYdcP3R+GGsCcsaA==
"""
requests.auth
This module contains the authentication handlers for Requests.
"""
import hashlib
import os
import re
import threading
import time
import warnings
from base64 import b64encode
from ._internal_utils import to_native_string
from .compat import basestring, str, urlparse
from .cookies import extract_cookies_to_jar
from .utils import parse_dict_header
CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"
CONTENT_TYPE_MULTI_PART = "multipart/form-data"
def _basic_auth_str(username, password):
"""Returns a Basic Auth string."""
# "I want us to put a big-ol' comment on top of it that
# says that this behaviour is dumb but we need to preserve
# it because people are relying on it."
# - Lukasa
#
# These are here solely to maintain backwards compatibility
# for things like ints. This will be removed in 3.0.0.
if not isinstance(username, basestring):
warnings.warn(
"Non-string usernames will no longer be supported in Requests "
"3.0.0. Please convert the object you've passed in ({!r}) to "
"a string or bytes object in the near future to avoid "
"problems.".format(username),
category=DeprecationWarning,
)
username = str(username)
if not isinstance(password, basestring):
warnings.warn(
"Non-string passwords will no longer be supported in Requests "
"3.0.0. Please convert the object you've passed in ({!r}) to "
"a string or bytes object in the near future to avoid "
"problems.".format(type(password)),
category=DeprecationWarning,
)
password = str(password)
# -- End Removal --
if isinstance(username, str):
username = username.encode("latin1")
if isinstance(password, str):
password = password.encode("latin1")
authstr = "Basic " + to_native_string(
b64encode(b":".join((username, password))).strip()
)
return authstr
class AuthBase:
"""Base class that all auth implementations derive from"""
def __call__(self, r):
raise NotImplementedError("Auth hooks must be callable.")
class HTTPBasicAuth(AuthBase):
"""Attaches HTTP Basic Authentication to the given Request object."""
def __init__(self, username, password):
self.username = username
self.password = password
def __eq__(self, other):
return all(
[
self.username == getattr(other, "username", None),
self.password == getattr(other, "password", None),
]
)
def __ne__(self, other):
return not self == other
def __call__(self, r):
r.headers["Authorization"] = _basic_auth_str(self.username, self.password)
return r
class HTTPProxyAuth(HTTPBasicAuth):
"""Attaches HTTP Proxy Authentication to a given Request object."""
def __call__(self, r):
r.headers["Proxy-Authorization"] = _basic_auth_str(self.username, self.password)
return r
class HTTPDigestAuth(AuthBase):
"""Attaches HTTP Digest Authentication to the given Request object."""
def __init__(self, username, password):
self.username = username
self.password = password
# Keep state in per-thread local storage
self._thread_local = threading.local()
def init_per_thread_state(self):
# Ensure state is initialized just once per-thread
if not hasattr(self._thread_local, "init"):
self._thread_local.init = True
self._thread_local.last_nonce = ""
self._thread_local.nonce_count = 0
self._thread_local.chal = {}
self._thread_local.pos = None
self._thread_local.num_401_calls = None
def build_digest_header(self, method, url):
"""
:rtype: str
"""
realm = self._thread_local.chal["realm"]
nonce = self._thread_local.chal["nonce"]
qop = self._thread_local.chal.get("qop")
algorithm = self._thread_local.chal.get("algorithm")
opaque = self._thread_local.chal.get("opaque")
hash_utf8 = None
if algorithm is None:
_algorithm = "MD5"
else:
_algorithm = algorithm.upper()
# lambdas assume digest modules are imported at the top level
if _algorithm == "MD5" or _algorithm == "MD5-SESS":
def md5_utf8(x):
if isinstance(x, str):
x = x.encode("utf-8")
return hashlib.md5(x).hexdigest()
hash_utf8 = md5_utf8
elif _algorithm == "SHA":
def sha_utf8(x):
if isinstance(x, str):
x = x.encode("utf-8")
return hashlib.sha1(x).hexdigest()
hash_utf8 = sha_utf8
elif _algorithm == "SHA-256":
def sha256_utf8(x):
if isinstance(x, str):
x = x.encode("utf-8")
return hashlib.sha256(x).hexdigest()
hash_utf8 = sha256_utf8
elif _algorithm == "SHA-512":
def sha512_utf8(x):
if isinstance(x, str):
x = x.encode("utf-8")
return hashlib.sha512(x).hexdigest()
hash_utf8 = sha512_utf8
KD = lambda s, d: hash_utf8(f"{s}:{d}") # noqa:E731
if hash_utf8 is None:
return None
# XXX not implemented yet
entdig = None
p_parsed = urlparse(url)
#: path is request-uri defined in RFC 2616 which should not be empty
path = p_parsed.path or "/"
if p_parsed.query:
path += f"?{p_parsed.query}"
A1 = f"{self.username}:{realm}:{self.password}"
A2 = f"{method}:{path}"
HA1 = hash_utf8(A1)
HA2 = hash_utf8(A2)
if nonce == self._thread_local.last_nonce:
self._thread_local.nonce_count += 1
else:
self._thread_local.nonce_count = 1
ncvalue = f"{self._thread_local.nonce_count:08x}"
s = str(self._thread_local.nonce_count).encode("utf-8")
s += nonce.encode("utf-8")
s += time.ctime().encode("utf-8")
s += os.urandom(8)
cnonce = hashlib.sha1(s).hexdigest()[:16]
if _algorithm == "MD5-SESS":
HA1 = hash_utf8(f"{HA1}:{nonce}:{cnonce}")
if not qop:
respdig = KD(HA1, f"{nonce}:{HA2}")
elif qop == "auth" or "auth" in qop.split(","):
noncebit = f"{nonce}:{ncvalue}:{cnonce}:auth:{HA2}"
respdig = KD(HA1, noncebit)
else:
# XXX handle auth-int.
return None
self._thread_local.last_nonce = nonce
# XXX should the partial digests be encoded too?
base = (
f'username="{self.username}", realm="{realm}", nonce="{nonce}", '
f'uri="{path}", response="{respdig}"'
)
if opaque:
base += f', opaque="{opaque}"'
if algorithm:
base += f', algorithm="{algorithm}"'
if entdig:
base += f', digest="{entdig}"'
if qop:
base += f', qop="auth", nc={ncvalue}, cnonce="{cnonce}"'
return f"Digest {base}"
def handle_redirect(self, r, **kwargs):
"""Reset num_401_calls counter on redirects."""
if r.is_redirect:
self._thread_local.num_401_calls = 1
def handle_401(self, r, **kwargs):
"""
Takes the given response and tries digest-auth, if needed.
:rtype: requests.Response
"""
# If response is not 4xx, do not auth
# See https://github.com/psf/requests/issues/3772
if not 400 <= r.status_code < 500:
self._thread_local.num_401_calls = 1
return r
if self._thread_local.pos is not None:
# Rewind the file position indicator of the body to where
# it was to resend the request.
r.request.body.seek(self._thread_local.pos)
s_auth = r.headers.get("www-authenticate", "")
if "digest" in s_auth.lower() and self._thread_local.num_401_calls < 2:
self._thread_local.num_401_calls += 1
pat = re.compile(r"digest ", flags=re.IGNORECASE)
self._thread_local.chal = parse_dict_header(pat.sub("", s_auth, count=1))
# Consume content and release the original connection
# to allow our new request to reuse the same one.
r.content
r.close()
prep = r.request.copy()
extract_cookies_to_jar(prep._cookies, r.request, r.raw)
prep.prepare_cookies(prep._cookies)
prep.headers["Authorization"] = self.build_digest_header(
prep.method, prep.url
)
_r = r.connection.send(prep, **kwargs)
_r.history.append(r)
_r.request = prep
return _r
self._thread_local.num_401_calls = 1
return r
def __call__(self, r):
# Initialize per-thread state, if needed
self.init_per_thread_state()
# If we have a saved nonce, skip the 401
if self._thread_local.last_nonce:
r.headers["Authorization"] = self.build_digest_header(r.method, r.url)
try:
self._thread_local.pos = r.body.tell()
except AttributeError:
# In the case of HTTPDigestAuth being reused and the body of
# the previous request was a file-like object, pos has the
# file position of the previous body. Ensure it's set to
# None.
self._thread_local.pos = None
r.register_hook("response", self.handle_401)
r.register_hook("response", self.handle_redirect)
self._thread_local.num_401_calls = 1
return r
def __eq__(self, other):
return all(
[
self.username == getattr(other, "username", None),
self.password == getattr(other, "password", None),
]
)
def __ne__(self, other):
return not self == other
~~~