python 记录

好的,下面我将介绍一些 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

~~~






©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容