builtins内建模块

第一章、概述

        在Python中,builtins是一个内置模块,它在Python解释器启动时自动加载,并包含了一组Python的内置函数、异常和常量。这意味着无需显式导入builtins,你就可以在任何Python脚本或交互式环境中直接使用其中定义的函数和对象。

一、builtins是虚拟模块

        在没有使用特定IDE的情况下,Python 的内置模块通常被编译到 Python 解释器中,并且不是以单独的文件形式存在。这些内置函数和异常类是在 Python 解释器中直接实现的一部分,因此不需要单独的文件来存储。当您使用 Python 解释器时,这些内置功能会直接可用,无需单独导入或引用任何外部文件。

        因此,builtins.py 并不是一个标准的 Python 文件,而是一些IDE或特定工具可能使用的文件,用于提供代码补全、类型提示等功能。在一般的 Python 安装中,您不会直接找到一个名为 builtins.py 的文件。如果您想了解 Python 内置函数和异常类的相关信息,可以查看 Python 的官方文档或相关教程。

第二章、builtins内建模块综述

builtins内建模块综述

一、Python自动导入的7个模块

版本:Python 3.6.7

Python自动加载的模块有如下7个:

C:\Users\yuliang>python
Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 13:35:33) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print(dir())
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>>

在Python交互式环境中,当您输入 dir() 命令时,它将返回当前命名空间中的所有变量、函数、类和模块的名称列表。这包括了全局变量、内置函数、以及您在当前会话中定义的任何变量。下面是对返回的内容的解释:

1、__annotations__

这是一个字典,包含了函数参数注解的信息。在函数定义时,您可以使用参数注解来指定参数的预期类型或值。

2、__builtins__

这是一个全局命名空间,包含了 Python 解释器运行时的内置函数、异常类以及一些默认变量。

3、__doc__

这是当前模块或对象的文档字符串(docstring),它包含了关于该模块或对象的说明性文字。

4、__loader__

这是一个加载当前模块的加载器对象。它提供了有关模块加载过程的一些信息。

5、__name__

这是当前模块的名称。如果您在交互式环境中执行这个命令,它会显示为 "__main__"

6、__package__

这是当前模块的包名称。如果模块位于包中,它将显示包的名称。否则,它将显示为 None

7、__spec__

这是一个描述模块规范的对象。它包含了有关模块位置、加载器和其他有关模块的信息。

通过查看这些特殊的内置属性,您可以了解有关当前 Python 环境和模块的一些基本信息。

二、builtins模块和__builtins__命名空间

在 Python 中,builtins 模块和 __builtins__ 模块是两个不同的概念:

1、builtins 模块

它是一个虚拟标准库模块,其中包含了 Python 的内置函数、异常类和一些全局变量。您可以在 Python 中直接导入并访问该模块,例如:

import builtins

# 访问内置函数
result = builtins.len([1, 2, 3])

2、__builtins__ 模块

它是一个全局命名空间,其中包含了 Python 解释器运行时的内置函数、异常类以及一些默认变量。您可以通过访问 __builtins__ 来获取或修改这些内置对象,但不建议直接修改它,除非您非常清楚自己在做什么。例如:

# 获取内置函数
result = __builtins__.len([1, 2, 3])

 总的来说,builtins 模块是 Python 中的一个虚拟标准库模块,包含了内置的函数和异常类,您可以直接导入和使用它。而 __builtins__ 是一个全局命名空间,包含了 Python 解释器运行时的内置对象,您可以通过它来访问这些内置对象。

导入builtins模块后,其实自动加载的__builtins__模块和手动导入的builtins模块是同一个模块。

>>> import builtins
>>> print(dir())
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'builtins']
>>>

使用help命令可以看到相同的输出内容,help(__builtins__) 和 help(builtins)。

三、builtins模块中的组成部分

内容主要有下面6各部分,分别是NAME,DESCRIPTION,CLASSES,FUNCTIONS,DATA,FILE

import builtins
print(len(dir(builtins))) #152

1、64个内置异常层级结构+3个异常

'''
BaseException                       所有内置异常的基类
 +-- SystemExit                     由 sys.exit() 函数引发此异常。如果不处理这个异常, Python 解释器退出
 +-- KeyboardInterrupt              当用户按下中断键(通常是 Ctrl-C 或 Delete )时引发
 +-- GeneratorExit                  当调用一个 generator 对象的 close() 方法时引发
 +-- Exception                      所有内建的、非系统退出的异常,都是从该类派生的。此外, 应该从该类派生所有用户定义的异常
      +-- StopIteration             当一个 iterator 的 next() 方法发出信号, 表示没有更多的值时引发
      +-- StopAsyncIteration        必须由一个 asynchronous iterator 对象的 __anext__() 方法来引发以停止迭代操作。
      +-- ArithmeticError           各种算术错误引发的内建异常的基类
      |    +-- FloatingPointError   当浮点数操作失败时引发
      |    +-- OverflowError        当要表示算术运算的结果太大时引发, 长整型不会引发该异常
      |    +-- ZeroDivisionError    当除法或取模运算的第 2 个参数为 0 时引发
      +-- AssertionError            当 assert 语句失败时引发
      +-- AttributeError            当属性引用或赋值失败时引发。当对象根本不支持属性引用或属性赋值时,将引发 TypeError
      +-- BufferError               当 buffer 相关的操作无法执行时引发
      +-- EOFError                  当内建函数 input() 或 raw_input() 的其中之一,在触及文件结尾 (EOF) 情形,而没有读取到任何数据时引发
      +-- ImportError               当 import 语句无法找到模块定义,或者当 from ... import 语句未能找到要导入的名称时引发
      |    +-- ModuleNotFoundError  导入的模块不存在
      +-- LookupError               当用于映射或序列的键或索引无效时引发的异常的基类
      |    +-- IndexError           当序列下标超出取值范围时引发。(切片索引会被静默地截取到允许范围内;如果索引不是一个普通整数,则引发 TypeError )
      |    +-- KeyError             当在现有键的集合中找不到映射的键时引发
      +-- MemoryError               当一个操作将内存耗尽,但情况仍可挽救时(通过删除某些对象)时引发
      +-- NameError                 当找不到本地或全局名称时引发
      |    +-- UnboundLocalError    当引用函数或方法局部变量,但变量没有绑定值时引发
      +-- OSError                   此异常在一个系统函数返回系统相关的错误时将被引发,此类错误包括 I/O 操作失败例如 "文件未找到" 或 "磁盘已满" 等(不包括非法参数类型或其他偶然性错误)
      |    +-- BlockingIOError      当一个操作阻塞一个设置为非阻塞操作的对象(例如套接字)时引发
      |    +-- ChildProcessError    在对子进程执行操作失败时引发
      |    +-- ConnectionError      连接相关问题的基类
      |    |    +-- BrokenPipeError 当试图在管道上写入而另一端已关闭时尝试写入,或试图写入已关闭写入的套接字时引发
      |    |    +-- ConnectionAbortedError  当连接尝试被同伴中止时引发
      |    |    +-- ConnectionRefusedError  当连接尝试被同伴拒绝时引发
      |    |    +-- ConnectionResetError    当连接被同伴重置时引发
      |    +-- FileExistsError      尝试创建已存在的文件或目录时引发
      |    +-- FileNotFoundError    当请求文件或目录但不存在时引发
      |    +-- InterruptedError     当系统调用被传入信号中断时引发
      |    +-- IsADirectoryError    在目录上请求文件操作时引发
      |    +-- NotADirectoryError   当目录操作被请求的目录不是目录时引发
      |    +-- PermissionError      当尝试运行没有足够访问权限的操作时引发
      |    +-- ProcessLookupError   当一个给定的过程不存在时引发
      |    +-- TimeoutError         当系统功能在系统级别超时时引发
      +-- ReferenceError            当用一个由 weakref.proxy() 函数创建的弱引用代理,去访问引用者的属性,而该引用者已经被垃圾回收时,会引发此异常
      +-- RuntimeError              当检出错误不属于任何其它类别时引发
      |    +-- NotImplementedError  在用户自定义的基类中,抽象方法应当在其要求所派生类重载该方法,或是在其要求所开发的类提示具体实现尚待添加时引发此异常。
      |    +-- RecursionError       它会在解释器检测发现超过最大递归深度 (参见 sys.getrecursionlimit()) 时被引发。
      +-- SyntaxError               当解析器遇到语法错误时引发
      |    +-- IndentationError     与不正确的缩进相关的语法错误的基类
      |         +-- TabError        当缩进中包含对制表符和空格的混用时引发
      +-- SystemError               当解释器发现内部错误,但情况并没有看起来那么严重,不至于到要放弃所有希望的地步,此时会引发本异常
      +-- TypeError                 当操作或函数应用于不合适类型的对象时引发
      +-- ValueError                当内建操作或函数,接收到类型正确,但值不正确的参数,而且这种情况不能用诸如 IndexError 这样的更精确的异常进行描述时引发
      |    +-- UnicodeError         当有关 Unicode 编码或解码错误出现时引发
      |         +-- UnicodeDecodeError      当解码过程中出现的一个 Unicode 相关的错误时引发
      |         +-- UnicodeEncodeError      当编码过程中出现的一个 Unicode 相关的错误时引发
      |         +-- UnicodeTranslateError   当翻译过程中出现的一个 Unicode 相关的错误时引发
      +-- Warning                           警告类别基类
           +-- DeprecationWarning           弃用特性警告基类
           +-- PendingDeprecationWarning    将来会被弃用特性的警告基类
           +-- RuntimeWarning               可疑 Runtime 行为警告基类
           +-- SyntaxWarning                可疑句法警告基类
           +-- UserWarning                  用户代码生成警告基类
           +-- FutureWarning                将来会改变语义结构的警告基类
           +-- ImportWarning                可能弄错模块导入警告基类
           +-- UnicodeWarning               Unicode 相关的警告基类
           +-- BytesWarning                 与 bytes 和 bytearray 相关的警告的基类
           +-- ResourceWarning              与资源使用相关的警告的基类。 会被默认的警告过滤器忽略
'''

 另外3个异常

  1. ##3个别名异常类##

  2. ##自3.3版本以后,以下3个异常已经合并入OSError##

'''
EnvironmentError	操作系统错误的基类
WindowsError		系统调用失败
IOError  			1.当错误的输入了一个不存在的文件名
         			2.不满足访问该文件的权限时
         			3.以读取方式打开了文件,并在读取模式中写入文件内容,所以引起错误
''' 

2、7个内置类属性

 '''
__build_class__		可以接受的 這成爲一個新的(隱藏) 內置函數的調用,命名 __build_class__
__doc__				输出文件开头注释的内容
__import__ 			一般用于动态加载模块
__loader__ 			是由加载器在导入的模块上设置的属性,访问它时将会返回加载器对象本身。
__name__			一段程序作为主线运行程序时其内置名称就是 __main__
__package__ 		模块的 __package__ 属性必须设定。 其取值必须为一个字符串,但可以与 __name__ 取相同的值。 当模块是包时,其 __package__ 值应该设为其 __name__ 值。 当模块不是包时,对于最高层级模块 __package__ 应该设为空字符串,对于子模块则应该设为其父包名。
__spec__			__spec__ 属性必须设为在导入模块时要使用的模块规格说明。 对 __spec__ 的正确设定将同时作用于 解释器启动期间初始化的模块。 唯一的例外是 __main__,其中的 __spec__ 会 在某些情况下设为 None.
 ''' 

3、6个内建常量

'''
None				它属于 NoneType 类型,表示没有值,也就是空值。
True				它属于 bool 类型,Python程序语言指定任何非0和非空(null)值为true
False				它属于 bool 类型,Python程序语言指定0 或者 null为false
Ellipsis			该对象bool测试是为真,用来省略代码,作用类似于pass的一种替代方案 
__debug__			内置的只读变量 __debug__, 除非解释器运行在最优模式中(通过使用-O选项指定),否则它的值为True。在运行额外的错误检查过程时,程序可能在需要时检查这个变量。
NotImplemented		广泛应用于二元魔术方法中表示该类型无法和其它类型进行对应的二元运算
''' 

4、6个特殊函数

##6个##
'copyright'
'credits'
'exit'
'help'
'license'
'quit'

5、26个非异常类和43个函数


##26个非异常类和43个函数##
'__build_class__'
'__import__'
'abs'
'all'
'any'
'ascii'
'bin'
'bool'
'breakpoint'
'bytearray'
'bytes'
'callable'
'chr'
'classmethod'
'compile'
'complex'
'delattr'
'dict'
'dir'
'divmod'
'enumerate'
'eval'
'exec'
'filter'
'float'
'format'
'frozenset'
'getattr'
'globals'
'hasattr'
'hash'
'hex'
'id'
'input'
'int'
'isinstance'
'issubclass'
'iter'
'len'
'list'
'locals'
'map'
'max'
'memoryview'
'min'
'next'
'object'
'oct'
'open'
'ord'
'pow'
'print'
'property'
'range'
'repr'
'reversed'
'round'
'set'
'setattr'
'slice'
'sorted'
'staticmethod'
'str'
'sum'
'super'
'tuple'
'type'
'vars'
'zip'

第三章、内建函数

一、print()函数

1、参数

def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
    """
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
    """
    pass

这段代码描述的是Python中的print()函数的定义,它是Python内置函数之一。print()函数用于将指定的值打印输出到控制台或指定的文件流,默认情况下输出到标准输出流 sys.stdout

下面是对print()函数的参数和功能的解释:

1、self

这个参数并不是实际的参数,而是表示该函数属于类的方法。在这里,print()函数是一个内置函数,属于内置模块 builtins,所以有一个 self 参数是为了保持和其他方法的一致性。

2、*args

这是一个可变位置参数,允许你传入任意数量的值。print()函数可以接受多个参数,并将它们打印输出到控制台。

3、sep=' '

这是一个关键字参数,用于指定打印输出多个值时的分隔符。默认情况下,分隔符是一个空格字符 ' '

4、end='\n'

这也是一个关键字参数,用于指定打印输出结束时的附加字符串。默认情况下,结束字符串是一个换行符 '\n',即在打印输出后会自动换行。

5、file=None

这也是一个关键字参数,用于指定输出的文件流。如果没有提供这个参数或参数值为None,则输出将默认到标准输出流 sys.stdout,即控制台输出。你可以传递一个文件对象作为参数来将输出重定向到其他文件

6、flush=False

这也是一个关键字参数,用于指定是否强制刷新输出流。默认情况下,输出是缓冲的,flush=False表示不强制刷新,而在程序结束或换行时自动刷新输出。如果将 flush=True,则每次调用 print()后都会立即刷新输出,确保立即将内容输出到目标文件流。

2、用法

# 作   者:JZQ
# 开发时间:2023/12/7 14:30

# 用法一:可以输出数字
print(520)
print(87.2)

# 用法二:输出字符串
print("Hello World!")

# 用法三:输出含有运算符的表达式
print(1 + 1)  # 2

# 用法四:将数据输出到文件中
# 1、所制定的盘符必须存在
# 2、使用file = fp语法
fp = open("D:/text.txt", "a+")  # a+ 模式:如果文件不存在就创建文件,文件存在就在文件内容的后面继续追加
print("Hello JZQ", file=fp)
fp.close()

fp = open("测试print函数标准输出流重定向.txt", "a+", encoding="utf8")
print("测试print函数标准输出流重定向", file=fp)
fp.close()

# 用法五:不进行换行输出
print("Hello", "World", sep="---", end=" ")
print("666")

二、help()函数

若是使用字符串作为参数传入help函数的话,help函数会自动提取字符串中的内容,获取对应的帮助信息,如果不传如字符串值的话,除了 __builtins__ 全局命名空间中的属性外,其他均需手动导入,否则不识别

推荐使用字符串往help函数中传值

1、参数

一般传入字符串作为参数

2、用法

        在 Python 中,help() 是一个内置函数,用于获取对象的帮助信息和文档字符串(Docstring)。help() 函数提供了一个简单的交互式方式来查询 Python 对象(如模块、函数、类等)的用法和说明。

        使用 help() 函数的方式非常简单,只需在交互式 Python 解释器或脚本中调用该函数并传入要查询的对象作为参数。例如:

# 作   者:JZQ
# 开发时间:2023/12/8 15:45

# 查询内置函数的帮助信息
# help(print)

# 查询模块的帮助信息
# import math
# help(math)

help("random")

# # 查询类的帮助信息
# help(list)

# # 查询函数的帮助信息
def my_function(x, y):
    """这是一个自定义函数的文档字符串。"""
    return x + y

help(my_function)

# help("str")

help() 函数会显示对象的说明、参数列表、返回值以及其他相关信息。对于内置函数、标准库模块以及自定义函数和类,编写良好的文档字符串是一个良好的实践,它有助于提高代码的可读性和维护性,并方便其他开发者了解和使用代码。

        需要注意的是,并不是所有的 Python 对象都有文档字符串或帮助信息。有些对象可能没有相关的文档说明,此时 help() 函数将显示一个简单的默认帮助信息。在编写自己的函数和类时,建议添加清晰的文档字符串,以便其他人可以方便地使用 help() 函数查看相关信息。

三、chr()函数

chr() 函数是一个内置函数,用于将一个整数转换为对应的 Unicode 字符。它接受一个整数参数,该整数应该是一个有效的 Unicode 码位,然后返回对应的字符。

例如,chr(65) 将返回字符串 'A',因为 65 是大写字母 'A' 的 Unicode 码位。同样,chr(97) 将返回字符串 'a',因为 97 是小写字母 'a' 的 Unicode 码位。

1、语法

chr(i)

2、参数

i: 必需,一个表示 Unicode 码位的整数。

3、返回值

返回一个表示 Unicode 字符的字符串。

4、示例

print(chr(65))  # 输出: A
print(chr(97))  # 输出: a
print(chr(8364))  # 输出: € (Euro符号的 Unicode 码位)

        在示例中,chr(65) 返回字符串 'A',因为 65 对应于大写字母 'A' 的 Unicode 码位。同样,chr(97) 返回字符串 'a',因为 97 对应于小写字母 'a' 的 Unicode 码位。如果提供的整数不是有效的 Unicode 码位,chr() 将引发 ValueError

print(chr(1200000)) # ValueError: chr() arg not in range(0x110000)

这个函数通常用于处理字符编码、文本处理以及与 Unicode 相关的操作。

四、dir()函数

dir() 是 Python 的一个内建函数,它返回一个包含对象的所有属性和方法的列表。这个函数可以用于探索模块、类、对象等的命名空间。

1、语法

dir([object])

object (可选): 要检查的对象。如果省略,dir() 返回当前范围内的名称列表。

2、返回值

dir() 返回一个字符串列表,包含对象的属性、方法和特殊的内建属性。

3、在全局范围使用

result = dir()
print(result)

这将返回当前全局范围内的所有名称列表。

import threading
from typing import List

# 读取模块的命名空间中的属性和方法
module_namespace: List[str] = dir(threading)
print(module_namespace)

4、在类范围使用

import threading
from typing import List

# 读取类的命名空间中的属性和方法
# 类中所有的method,property
class_namespace = dir(threading.Thread)
print(class_namespace)

 

5、在实例对象范围使用

# 读取对象的命名空间中属性和方法
# 对象中所有的method,property,field
class MyThread(threading.Thread):
    pass

my_thread = MyThread()
result: List[str] = dir(my_thread)
print(result)

 

class MyClass:
    def __init__(self):
        self.attribute = "Hello"
    
    def my_method(self):
        print("Method called")

my_object = MyClass()
result = dir(my_object)
print(result)

 这将返回 MyClass 类的实例 my_object 的所有属性和方法。

6、注意事项

  • 如果不提供对象参数,dir() 将返回当前范围内的名称列表。
  • 对于模块、类、或实例,dir() 可以用于查看其属性和方法。
  • dir() 返回的列表包含对象的所有有效名称,包括变量、函数、类、模块等。

dir() 的输出可能会很庞大,因此通常最好结合其他信息和文档来理解对象的属性和方法的含义。

五、eval()函数

eval() 是 Python 的一个内置函数,它用于执行存储在字符串中的表达式或代码。它接受一个字符串作为参数,并将其解析为 Python 表达式,然后执行该表达式,并返回结果。

1、语法

下面是 eval() 函数的基本语法:

eval(expression, globals=None, locals=None)

2、参数

  • expression 是一个字符串,表示要执行的 Python 表达式或代码。
  • globals 是一个字典,用于指定全局命名空间。如果未指定,则默认使用当前模块的全局命名空间。
  • locals 是一个字典,用于指定局部命名空间。如果未指定,则默认使用当前调用者的局部命名空间。

3、案例

x = 10
y = 20
expression = "x + y"
result = eval(expression)
print(result)  # 输出 30

        在这个例子中,我们定义了两个变量 xy,然后将一个字符串表达式 "x + y" 传递给 eval() 函数。eval() 函数解析并执行了这个字符串表达式,并返回了表达式的结果,即 30。 

4、注意事项

        需要注意的是,eval() 函数执行的是字符串中的代码,因此在使用时需要谨慎。如果 expression 参数中包含恶意代码,可能会导致安全问题。因此,在处理用户输入或不受信任的数据时,应该避免使用 eval() 函数,以防止代码注入或其他安全漏洞。

二、input()函数

1、源码

def input(__prompt: Any = ...) -> str: ...

def input(*args, **kwargs): # real signature unknown
    """
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.
    """
    pass

2、用法

        在 Python 中,input() 是一个内置函数,用于从用户处获取输入。它会暂停程序的执行,等待用户在命令行或终端中输入一行文本,并在用户按下回车键后返回输入的内容作为字符串。

input() 函数的语法如下:

input([prompt])
  • prompt(可选):用于提示用户输入的字符串。它是可选的,如果提供了该参数,将在等待用户输入之前显示该提示信息。

以下是 input() 函数的使用示例:

name = input("Please enter your name: ")
print(f"Hello, {name}!")

在这个示例中,用户将被提示输入他们的名字。输入的内容将被存储在变量 name 中,并在打印欢迎消息时使用。

需要注意以下几点:

  1. input() 函数返回的内容始终被视为字符串。如果你需要将输入的内容用作数值等其他类型,你需要显式地进行转换。

age = int(input("Please enter your age: "))
  1. 用户输入的内容通常是一行字符串,它会包括用户输入的所有字符,包括空格。你可以使用字符串处理方法(如 split())来处理输入的内容。

  2. 当用户在输入时按下回车键,input() 函数会将输入内容作为字符串返回。如果用户只是按下回车键而没有输入任何内容,返回的字符串将为空。

  3. 在一些情况下,特别是在交互式环境(如 Jupyter Notebook)中,input() 函数可能会导致一些问题,因为它会阻塞进程。这可能需要在某些情况下使用特殊技巧或替代方法。

总之,input() 函数是一个用于从用户获取文本输入的简单而有用的工具,适用于与用户进行基本的命令行交互。

四、id()函数

        在Python中,id() 函数用于获取对象的唯一标识符(identity)。这个标识符是一个整数值,对于每个对象在其生命周期中都是唯一且不变的。实际上,这个标识符可以被认为是对象在内存中的地址。

id() 函数接受一个对象作为参数,并返回该对象的唯一标识符。这个标识符可以用来判断两个变量是否引用同一个对象。

示例:

x = [1, 2, 3]
y = x
z = [1, 2, 3]

print(id(x))  # 输出 x 对象的标识符
print(id(y))  # 输出 y 对象的标识符,与 x 相同,因为它们引用同一个对象
print(id(z))  # 输出 z 对象的标识符,与 x 不同,因为它是一个新的列表对象

        在上面的例子中,xy 引用同一个列表对象,所以它们的标识符是相同的,而 z 是一个新的列表对象,所以其标识符与前两者不同。

        需要注意的是,id() 返回的值不会重复使用。一旦对象被销毁,其标识符也会释放,可能被其他对象再次使用。

        虽然 id() 可以用来比较对象是否相同,但在实际编程中,更常用的是使用 == 运算符进行值比较,或使用 is 运算符进行引用比较。is 运算符用于判断两个变量是否引用同一个对象。

a = [1, 2, 3]
b = a

print(a == b)  # 输出 True,值相同
print(a is b)  # 输出 True,引用相同

c = [1, 2, 3]
print(a == c)  # 输出 True,值相同
print(a is c)  # 输出 False,引用不同

总结:id() 函数返回对象的唯一标识符,可以用来比较两个变量是否引用同一个对象。在大多数情况下,值比较和引用比较更常用和更清晰。

五、max() 函数

max() 函数用于找到给定可迭代对象中的最大值。它接受一个或多个参数,并返回它们中的最大值。

语法

max_value = max(iterable, *iterables, key=None, default=object)
  • iterable:必需,用于查找最大值的可迭代对象。
  • *iterables:可选,可以传入多个可迭代对象进行比较。
  • key:可选,用于指定一个函数,该函数在每个元素上调用,返回值用于比较排序。默认为 None,即直接比较元素。
  • default:可选,用于在可迭代对象为空时指定一个默认值。

示例

numbers = [3, 9, 2, 5, 7]
max_value = max(numbers)
print(max_value)  # 输出: 9

words = ["apple", "banana", "cherry"]
longest_word = max(words, key=len)
print(longest_word)  # 输出: banana

六、min()函数

min() 函数用于找到给定可迭代对象中的最小值。它与 max() 函数的用法相似。

语法

min_value = min(iterable, *iterables, key=None, default=object)
  • 参数与 max() 函数类似。

示例

numbers = [3, 9, 2, 5, 7]
min_value = min(numbers)
print(min_value)  # 输出: 2

words = ["apple", "banana", "cherry"]
shortest_word = min(words, key=len)
print(shortest_word)  # 输出: apple

        需要注意的是,max()min() 函数的参数可以是包含多个可迭代对象的列表,以及其他可迭代对象。这些函数根据提供的比较条件找到最大或最小值。

        总结:max() 函数用于找到可迭代对象中的最大值,min() 函数用于找到可迭代对象中的最小值。它们都可以接受一个 key 参数用于指定比较函数,用于自定义比较逻辑。

七、any函数

any() 是 Python 内置的函数之一,用于判断可迭代对象中是否存在至少一个满足指定条件的元素。如果存在满足条件的元素,则返回 True,否则返回 False

语法

any(iterable)
  • iterable:一个可迭代对象,如列表、元组、集合等。

示例

numbers = [0, 2, 4, 6, 8]

# 使用 any() 判断是否存在奇数
result = any(x % 2 != 0 for x in numbers)
print(result)  # 输出: False

# 使用 any() 判断是否存在非空字符串
strings = ["apple", "", "banana"]
result = any(s != "" for s in strings)
print(result)  # 输出: True

        在第一个示例中,any() 函数用于判断列表 numbers 中是否存在奇数。通过生成器表达式,检查列表中的每个元素是否满足条件(即是否为奇数),如果至少有一个元素满足条件,则返回 True,否则返回 False

        在第二个示例中,any() 函数用于判断列表 strings 中是否存在非空字符串。通过生成器表达式,检查列表中的每个字符串是否不为空,如果至少有一个非空字符串,则返回 True,否则返回 False

        总结:any() 函数用于判断可迭代对象中是否存在至少一个满足指定条件的元素。它在需要检查集合中是否存在满足条件的元素时非常有用。

第四章、普通内置类

第四章、object类

一、概述

        在Python中,object类是所有类的根类。它是Python类层次结构的顶级父类,因此每个Python类都直接或间接地继承自object类。object类位于 内置模块 builtins.py 中,所以它不需要显式导入。

二、常用方法

  • object类提供了一些通用的方法,这些方法可以被所有Python类继承和使用。
  • object类中的这些方法部分是没有被声明为final的,因此可以被子类重写。
  • 由于所有的类都继承自object类,因此可以在任何对象上调用object类中的方法。这使得在进行一些通用操作时,比如对象的比较、转换为字符串等,非常方便。

三、__str__(self):

输出实例引用的时候,会自动调用__str__方法

print(obj)方法需要将对象转换为字符串,然后将字符串打印到控制台。而object类中的__str__()方法提供了一个通用的方式来获取对象的字符串表示形式。因此,为了方便输出对象引用,Python在print()方法内部自动调用对象的__str__()方法。

1、类型

 def __str__(self) -> str: ...

 源代码上的toString方法的默认实现是:

        返回  <完整类名 object  at  对象的内存地址转换为十六进制的形式>

        这个默认实现返回的字符串由类名和对象的哈希码组成。例如,对于一个名为MyClass的类的实例,__str__()方法的默认实现可能返回

类似于 <__main__.MyClass object at 0x000002C0491BA2B0> 的字符串。

2、设计目的

__str__方法的设计目的是:通过调用这个方法可以将一个“Python对象”转换成为“字符串表示形式”

3、重写方法

        大多数类都会覆盖object类中的__str__()方法,以提供更有用的信息来描述对象的状态。这样做可以增加代码的可读性和调试的便利性。

重写原则:

  • 越简洁越好,可读性越强越好
  • 向简洁的,详实的,易阅读的方向发展
class ObjectTest02(object):
    @classmethod
    def main(cls):
        p = Person("jzq",27)

        #未重写__str__方法
        print(p) #<__main__.Person object at 0x0000023FB309AB38>

        #重写__str__方法
        print(p) #Person {name = jzq, age = 27}
        print(p.__str__()) #Person {name = jzq, age = 27}


class Person(object):
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def __str__(self):
        return "Person {name = " + str(self.__name) + ", age = " + str(self.__age) + "}"

if __name__ == '__main__':
    ObjectTest02.main()

通过覆盖__str__()方法,我们可以根据对象的特定属性提供更有用的信息,并根据需要自定义输出格式。

4、print方法输出时自动调用对象__str__方法

在 Python 中,当你使用 print 函数来输出一个对象时,会自动调用该对象的 __str__ 方法来获取其字符串表示。这使得你可以通过重写 __str__ 方法来自定义对象在被打印时的输出格式。

四、__eq__( )

object类中的__eq__()方法用于比较当前对象与指定对象是否相等。该方法没有实现 NotImplemented

1、类型

def __eq__(self, o: object) -> bool: ...

2、设计目的

__eq__方法是判断两个对象是否相等的

3、重写方法

        判断两个实例对象是否相等,不能使用“==”,因为“==”比较的是两个实例对象的内存地址,这样的话,即使两个对象初始化相同,但是因为内存地址不同,也会返回false,

  •  __eq__方法没有默认实现,所以要进行方法重写
  • str类已经重写了__eq__方法和__str__方法

重写原则:

  1. 自反性(Reflexive):对于任意非空对象 xx.equals(x) 应该返回 true

  2. 对称性(Symmetric):对于任意非空对象 xy,如果 x.equals(y) 返回 true,则 y.equals(x) 也应该返回 true

  3. 传递性(Transitive):对于任意非空对象 xyz,如果 x.equals(y) 返回 true,并且 y.equals(z) 也返回 true,则 x.equals(z) 应该返回 true

  4. 一致性(Consistent):对于任意非空对象 xy,多次调用 x.equals(y) 应该始终返回相同的结果,前提是在比较过程中对象的状态没有发生变化。

  5. 对于任意非空对象 xx.equals(null) 应该返回 false

4、== 运算符 底层调用 __eq__()方法,比较的是对象的内容(值)

使用  a  ==  b  等同于  a.__eq__(b)

比较的对象的内容

__eq__()方法默认未实现,除自身与自身比较返回True外,其余比较一律返回False

5、is运算符,比较的是对象内存地址

6、案例一:时间年月日对比

class MyTime(object):
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    """
    重写__eq__()方法
    当 年 相同,月 相同,日 相同,表示两个日期相同,两个对象相等
    """


    # def __eq__(self, o: object) -> bool:
    #     # return super().__eq__(o)
    #     #获取第一个日期的年月日
    #     year1 = self.year
    #     month1 = self.month
    #     day1 = self.day
    #
    #     #获取第二个日期的年月日
    #     #类型保护,向下转型
    #     if isinstance(o,MyTime):
    #         year2 = o.year
    #         month2 = o.month
    #         day2 = o.day
    #
    #     if year1 == year2 and month1 == month2 and day1 == day2:
    #         return True
    #     #程序执行到此处,会返回False
    #     return False

    def __eq__(self, o: object) -> bool:
        if o is None or (not isinstance(o,MyTime)):
            return False
        #如果内存地址相同的时候,指向堆内存的对象肯定是同一个
        if self is o:
            return True
        #程序能执行到此处,说明obj一定是MyTime的实例,也是MyTime类型
        return self.year == o.year and self.month == o.month and self.day == o.day

if __name__ == '__main__':

    time1 = MyTime(2023,8,18)
    time2 = MyTime(2023,8,18)
    print(time1 == time2)
    print(time1.__eq__(time2))
    print(time1 is time2)
    """
    True
    True
    False
    """

7、案例二:学生ID和school对比

# 作   者:JZQ
# 开发时间:2023/8/18 14:11

class EqTest02(object):

    @classmethod
    def main(cls):
        s1 = Student(1,"希望小学")
        s2 = Student(1,"希望小学")

        # == 底层调用 __eq__方法,比较的是内容
        print(s1 == s2) #True
        # is 比较的是内存地址
        print(s1 is s2) #False

class Student(object):
    def __init__(self,id,school):
        self.id = id
        self.school = school

    #重写__str__方法
    def __str__(self) -> str:
        return "学号:" + str(self.id) + ",学校:" + str(self.school)

    #重写__eq__方法
    #要求:当一个学生的学号相等,并且学校也相同时,表示同一个学生
    def __eq__(self, o: object) -> bool:
        if o is None or (not isinstance(o,Student)):
            return False

        if self is o:
            return True

        return self.id == o.id and self.school == o.school

if __name__ == '__main__':
    EqTest02.main()

8、比较对象时使用“==”进行对比

Python中一切皆对象,所有数据类型均为对象,引用数据类型,因此在对象之间比较时均使用 “==” ,因为 “==” 底层调用的是 __eq__()方法,比较的是内容,说明 “==” 是在 __eq__方法上更高级的封装,直接比较的是内容,更符合人的思维,更高级了。

确实是要比较内存地址时才实用 is 运算符,是专门比较内存地址的

9、__eq__方法重写要彻底

Python中数据类型比较内容时,必须使用==运算符,底层调用 __eq__方法,当在自定义的类中使用 == 进行比较时,一定要确保自定义类中的 __eq__ 方法已经重写

# 作   者:JZQ
# 开发时间:2023/8/18 14:38

class Address(object):
    def __init__(self, city, street, zipcode):
        self.city = city
        self.street = street
        self.zipcode = zipcode

    #重写__eq__()方法
    #要求:城市,街道和邮编都相同时,则对象相同
    def __eq__(self, o: object) -> bool:

        if self is o: return True
        if o is None or (not isinstance(o,Address)): return False
        return self.city.__eq__(o.city) \
            and self.street.__eq__(o.street) \
            and self.zipcode.__eq__(o.zipcode)

class User(object):
    def __init__(self,name,address):
        self.name = name
        self.address = address

    #重写__eq__方法
    #重写规则:当一个用户的用户名和家庭住址都相同,则表示为同一个用户
    def __eq__(self, o: object) -> bool:
        if self is o: return True
        if o is None or (not isinstance(o,User)): return False
        return self.name == o.name and self.address == o.address

class EqTest03(object):
    @classmethod
    def main(cls):
        u1 = User("jzq",Address("西安","长延堡街道","710000"))
        u2 = User("jzq",Address("西安","长延堡街道","710000"))

        print(u1 == u2) #True  比较的是内容
        print(u1 is u2) #False 比较的是值

        u3 = User("lisi",Address("西安","长延堡街道","710000"))
        print(u1 == u3) #False

if __name__ == '__main__':
    EqTest03.main()

五、__hash__()

__hash__ 方法是 Python 中的一个特殊方法,用于定义对象的哈希码(hash code)。哈希码是一个整数值,用于在哈希表等数据结构中进行快速查找和比较对象。当你在自定义类中重写 __hash__ 方法时,你可以根据对象的属性来计算哈希码,以满足自己的需求。

以下是 __hash__ 方法的详细解释:

  1. 方法名称: __hash__

  2. 作用: 定义对象的哈希码,以便在哈希表中进行快速查找和比较。

  3. 返回值: 必须返回一个整数值(哈希码)。Python 要求相等的对象必须具有相同的哈希码,但相等的哈希码不一定表示对象相等。

  4. 使用场景: __hash__ 方法通常用于不可变对象,例如自定义的不可变类。可变对象默认不具有哈希码,因为它们可能在哈希表中的位置发生变化。

  5. 实现要求:

    • __hash__ 方法应该是稳定的,即对象的属性不变时,哈希码也不变。
    • 如果两个对象相等(通过 __eq__ 方法定义),它们的哈希码必须相等。
    • 如果两个对象不相等,它们的哈希码不一定要不相等,但相等的哈希码会导致哈希表性能下降(碰撞)。

以下是一个示例,演示了如何在自定义类中重写 __hash__ 方法:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __hash__(self):
        # 自定义哈希码计算,使用 XOR 运算
        return hash(self.x) ^ hash(self.y)

    def __eq__(self, other):
        # 自定义相等性比较
        return self.x == other.x and self.y == other.y

# 创建两个 Point 对象
point1 = Point(1, 2)
point2 = Point(1, 2)

# 使用哈希表查找对象
point_set = {point1}
print(point1 in point_set)  # 输出: True,point1 和 point2 相等

# 添加 point2 到哈希表
point_set.add(point2)
print(len(point_set))  # 输出: 1,point2 被认为和 point1 相等

        在这个示例中,Point 类重写了 __hash__ 方法,使用 XOR 运算来计算哈希码。这样,相等的 Point 对象将具有相同的哈希码,从而可以在哈希表中正确查找和比较。同时,__eq__ 方法用于定义对象的相等性比较。

需要注意的是,如果你重写了 __hash__ 方法,也应该同时实现 __eq__ 方法,以确保哈希码和相等性的一致性。

六、其他常见的魔术方法

        这段代码展示的是 Python 中的类 object 的一些特殊方法(也称为魔术方法或双下划线方法)。在 Python 中,所有的类都隐式或显式地继承自 object,它是所有类的基类,因此这些特殊方法适用于所有类。

        这些特殊方法允许您在类中定义自定义的行为,例如重载运算符、定制类的输出、管理属性等。以下是代码中展示的特殊方法的一些常见用途:

1、__delattr__(self, name)

  • 这个方法允许您自定义删除对象属性时的行为。
  • 当使用 del 关键字删除对象的属性时,__delattr__ 方法会被调用。

2、__dir__(self)

  • 这个方法允许您自定义 dir() 函数返回的属性列表。
  • dir() 函数用于获取对象的属性列表,如果类定义了 __dir__ 方法,则会返回该方法返回的属性列表。

3、__format__(self, format_spec)

  • 这个方法允许您自定义对象的格式化输出。
  • 当使用 format() 函数对对象进行格式化输出时,__format__ 方法会被调用。

这些特殊方法在类的定义中并不是必须的,如果不定义它们,Python 会提供默认的实现。但是,通过重载这些特殊方法,您可以更灵活地定制类的行为,使其更符合您的需求。

七、魔术方法都没有具体的实现过程

为什么都是pass占位,并没有实现过程尼

在给出的代码中,确实每个特殊方法都只是简单地使用 pass 语句,这是因为这些特殊方法是 Python 的内置方法,在 object 类中已经有了默认的实现。如果您不需要对这些特殊方法进行自定义操作,可以简单地使用 pass 来表示方法没有实际实现。

当 Python 解释器在类中找到这些特殊方法时,如果类没有定义特殊的实现,它会在 object 类中寻找默认的实现。因此,虽然这些方法在给定的代码中只是简单的 pass 语句,但实际上它们会继承自 object 类的默认实现。

在实际编程中,如果您的类需要自定义某些特殊方法的行为,可以在类中重新定义这些方法,并提供自定义的实现。当您重新定义这些方法后,Python 解释器会优先使用类中的实现,而不是继承自 object 类的默认实现。

以下是一个例子,展示了如何在类中重新定义 __eq__ 特殊方法来自定义相等比较的行为:

class MyClass:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return self.value == other.value

obj1 = MyClass(42)
obj2 = MyClass(42)

print(obj1 == obj2)  # 输出:True

        在上面的例子中,我们重新定义了 __eq__ 方法来比较对象的 value 属性是否相等,从而实现了自定义的相等比较行为。如果不重新定义 __eq__ 方法,对象的相等比较默认会比较它们是否是同一个对象的引用。

第十一章、range类

一、概述

用于生成一些数字序列,其中数字为数字类型数据

        在 Python 中,range 是一个类似于序列的对象,用于表示一个整数范围的不可变序列。它通常用于循环中,生成一系列连续的整数。

   range 对象是一个轻量级的、可迭代的整数序列,它在循环中特别有用,因为它只生成需要的值,而不会提前生成所有的值,从而节省内存和计算资源。

二、创建range对象

range 可以通过多种方式创建,但通常使用以下三种形式:

1、range(stop): 创建一个从0开始,到stop - 1结束的整数序列。

for i in range(5):
    print(i)
# 输出: 0 1 2 3 4

2、range(start, stop): 创建一个从start开始,到stop - 1结束的整数序列。

for i in range(2, 7):
    print(i)
# 输出: 2 3 4 5 6

3、range(start, stop, step): 创建一个从start开始,到stop - 1结束的整数序列,步长为step

for i in range(1, 10, 2):
    print(i)
# 输出: 1 3 5 7 9

参数详解

  • start:生成的数字序列从几开始,如果不写,默认为0
  • end:生成的数字序列到几结束,但不包含end这个数字
    • 左闭右开或前闭后开(start处为闭,end处为开)
  • step:补偿,生成的数字相邻间隔是几,可省略,默认为1,从左往右为正,从右往左为负
    • 函数range(5,2,-1)  5,4,3  range(5,2,-1)表示从5到2步长-1,不包括2

省略优先级:

range()函数省略优先级:先是省略step,再是start,优先识别end

三、不可变类型

range 对象是不可变的,这意味着一旦创建,就不能修改其中的值。range 对象只在需要时计算生成序列中的下一个整数,并且不会提前生成所有的值,因此它对于表示大范围的整数序列非常高效。

四、使用 list() 函数将 range 对象转换为列表

        在 Python 3 中,range 返回的对象是一个可迭代的序列,而不是一个真正的数组。这意味着 range 对象并不是一个完整的列表,它仅仅在需要的时候生成下一个值,而不是提前将所有值存储在内存中。这样可以节省内存空间,特别是当需要处理大规模的范围时。

        因为 range 对象并不是一个完整的列表,所以它没有像列表那样的所有方法和属性。例如,你不能对 range 对象进行切片,也不能直接查看其中的元素。但是你可以使用它在循环中生成整数序列,或者将其转换为列表,这样就能查看其中的所有元素。

        需要注意的是,在 Python 2 中,range 返回一个实际的列表,而在 Python 3 中,range 返回一个可迭代的对象,这样节省了内存。如果需要得到列表,可以使用 list(range(...)) 来转换为列表。

下面是一些示例:

# 从0到9(不包括10)
range_1 = range(10)
print(list(range_1))
# 输出: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 从5到9(不包括10)
range_2 = range(5, 10)
print(list(range_2))
# 输出: [5, 6, 7, 8, 9]

# 从1到10,步长为2(不包括10)
range_3 = range(1, 10, 2)
print(list(range_3))
# 输出: [1, 3, 5, 7, 9]

range 类在循环、列表生成式和其他需要处理整数范围的场景中非常有用,它能够帮助我们轻松生成整数序列,从而简化编程任务。

五、range对象通常用于for循环中

range 函数通常用于循环中,在迭代特定次数的情况下非常有用。它生成的整数序列不包括 stop 值,即结果范围是左闭右开的区间。如果需要包含 stop 值,可以通过调整 startstop 参数的值来实现。例如:range(1, 5) 将生成整数序列 [1, 2, 3, 4]。

第十二章、enumerate类

        在Python中,enumerate() 是一个内置函数,用于将一个可迭代对象(如列表、元组、字符串等)转换为一个枚举对象,同时返回每个元素的索引和对应的值。这对于在迭代过程中需要跟踪索引的情况非常有用。以下是enumerate() 方法的详细解释和示例:

语法:

enumerate(iterable, start=0)
  • iterable: 要枚举的可迭代对象,如列表、元组等。
  • start: 可选参数,指定起始索引,默认为0。

返回值: enumerate() 函数返回一个枚举对象,它包含可迭代对象中每个元素的索引和对应的值。这个枚举对象可以通过迭代来访问。

fruits = ['apple', 'banana', 'cherry', 'date']
enum_obj = enumerate(fruits)
print(enum_obj) #<enumerate object at 0x0000028EDFE74C18>
print(list(enum_obj)) #[(0, 'apple'), (1, 'banana'), (2, 'cherry'), (3, 'date')]

示例:

fruits = ['apple', 'banana', 'cherry', 'date']

# 使用enumerate()迭代列表
for index, fruit in enumerate(fruits):
    print(index, fruit)
    """
    0 apple
    1 banana
    2 cherry
    3 date
    """

在这个示例中,enumerate(fruits) 返回一个枚举对象,每次迭代都会返回一个包含索引和值的元组。通过在循环中使用元组拆包,我们可以轻松地访问索引和值。

使用指定的起始索引:

fruits = ['apple', 'banana', 'cherry', 'date']

# 使用enumerate()并指定起始索引为1
for index, fruit in enumerate(fruits, start=1):
    print(index, fruit)
    """
    1 apple
    2 banana
    3 cherry
    4 date
    """

在这个示例中,我们使用 start=1 来指定起始索引为1,而不是默认的0。

enumerate() 方法在需要同时迭代元素和索引的情况下非常有用,可以简化代码并提高可读性。

一、type内置类

type 是 Python 中非常重要的内置类之一,它有几种不同的用途。

1、对象的类型检查

type() 函数可以用于查看对象的类型。比如:

a = 5
print(type(a))  # 输出:<class 'int'>

2、动态创建类

使用 type() 还可以动态地创建类。通常,一个类由类名、继承的父类(如果有)、类属性和方法组成。例如,可以这样创建一个简单的类:

MyDynamicClass = type('MyDynamicClass', (), {'attr': 42})

# 创建了一个名为 MyDynamicClass 的类,没有父类,包含一个属性 attr 值为 42
obj = MyDynamicClass()
print(obj.attr)  # 输出:42

这个例子中,type() 接受类名、父类的元组和一个字典,字典中包含类的属性和方法。

3、元类(Metaclasses)

        在 Python 中,类本身也是对象。类对象是由元类创建的,而默认情况下,Python 中的元类是 type 类。元类控制着类的创建行为。通过自定义元类,可以改变类的创建方式。

        元类是用来创建类的类。在 Python 中,类本身也是对象,而这些类对象是由元类创建的。就像类是用来创建对象的模板一样,元类是用来创建类的模板。
        在 Python 中,大多数的类都是通过使用内置的 type 元类来创建的。当你定义一个类时,Python 默认会使用 type 元类来创建这个类。然而,你可以通过自定义元类来控制类的创建过程。
元类的主要作用包括:

  1. 控制类的创建行为: 通过重写元类的特殊方法(比如 __new__ 或 __init__),你可以控制类的属性、方法、甚至类的整体行为。这使得你可以在创建类时做一些特殊的操作。
  2. 实现类似 ORM(对象关系映射)和其他框架的功能: 一些框架使用元类来自动生成类,根据特定的配置或者元数据动态地创建类。ORM(例如 Django 的模型定义)就是一个很好的例子,它可以根据定义的模型自动生成对应的数据库表。

举个例子,你可以定义一个简单的元类来控制类的创建过程:

class MyMeta(type):
    def __new__(cls, name, bases, dct):
        # 在创建类时向类添加一个属性
        dct['new_attribute'] = 100
        return super().__new__(cls, name, bases, dct)

    def __init__(self, name, bases, dct):
        super().__init__(name, bases, dct)
        print("创建一个类对象")

# 使用自定义的元类创建类
class MyClass(metaclass=MyMeta):
    pass

# 创建 MyClass 的实例
obj = MyClass()
obj1 = MyClass()

# 访问新添加的属性
print(obj.new_attribute)  # 输出:100
print(MyClass.new_attribute)  # 输出:100

print(MyMeta.__mro__) # (<class '__main__.MyMeta'>, <class 'type'>, <class 'object'>)
print(MyClass.__mro__) # (<class '__main__.MyClass'>, <class 'object'>)

class MyMeta(type):

  • 这里定义了一个名为 MyMeta 的类,它继承自内置的 type 类。因此,MyMeta 是一个自定义的元类。
  • 在 Python 中,当你指定一个类的元类为 MyMeta 时,这个类的创建方式将受到 MyMeta 中定义的控制。

def __new__(cls, name, bases, dct):

  • 这是 MyMeta 类中的一个特殊方法 __new__,它在创建类时被调用。
  • __new__ 方法用于控制类的创建过程。它接收四个参数:
  • cls:类本身,即 MyMeta 类。
  • name:将要创建的类的名称。
  • bases:父类的元组。
  • dct:包含类属性和方法的字典。

dct['new_attribute'] = 100

  • 在 __new__ 方法中,这行代码向类的字典中添加了一个名为 new_attribute 的属性,赋值为 100

class MyClass(metaclass=MyMeta):

  • 这里定义了一个名为 MyClass 的类,并指定其元类为 MyMeta。因此,MyClass 类的创建将受到 MyMeta 控制。

obj = MyClass()

  • 创建了一个名为 obj 的 MyClass 类的实例。

print(obj.new_attribute) # 输出:100

  • 这行代码打印了 obj 实例的 new_attribute 属性的值,即输出 100

        所以,整个代码的流程是:通过元类 MyMeta 的 __new__ 方法,在类创建过程中向类添加了一个新的属性 new_attribute,然后创建了 MyClass 类的实例 obj,最后打印了这个实例的 new_attribute 属性,输出了其值 100

        在这个例子中,MyMeta 是一个自定义的元类,它继承自内置的 type 类。通过指定 metaclass=MyMeta,我们告诉 Python 使用 MyMeta 这个元类来创建 MyClass。在 MyMeta 中的 __new__ 方法中,我们向类 MyClass 添加了一个新的属性 new_attribute,然后创建了 MyClass 的实例 obj,最后打印了这个实例的 new_attribute 属性,输出了其值 100

二、zip内置类

zip() 是 Python 中的一个内置函数,用于将多个可迭代对象(例如列表、元组等)按索引位置打包成元组,然后返回这些元组组成的迭代器。

迭代器一旦被使用后就变为None,因为其指针已指到最后一位,无法在在继续迭代

1、基本用法

list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']

result = zip(list1, list2)
print(result) # zip 对象 <zip object at 0x000001EA0EE1EF00>

# 迭代器转换为元祖
print(tuple(result)) # 输出:((1, 'a'), (2, 'b'), (3, 'c'))

# 迭代器转换为列表
print(list(result))  # 输出:[(1, 'a'), (2, 'b'), (3, 'c')]

# 迭代器转换为集合
print(set(result))  # 输出:{(3, 'c'), (2, 'b'), (1, 'a')}

# 迭代器转换为字典
print(dict(result)) # 输出:{1: 'a', 2: 'b', 3: 'c'}

这个函数接受多个可迭代对象作为参数,并返回一个迭代器。这个迭代器生成的元素是由传入的可迭代对象在相同位置上对应的元素组成的元组。

2、解压缩序列

pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
numbers, letters = zip(*pairs)

print(numbers)  # 输出:(1, 2, 3)
print(letters)  # 输出:('a', 'b', 'c')

通过将 *pairs 传递给 zip() 函数,可以将原先打包在一起的元组进行解压缩,分别获得两个独立的序列。

3、合并多个序列

list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
list3 = ['x', 'y', 'z']

result = zip(list1, list2, list3)

for item in result:
    print(item)  # 输出:(1, 'a', 'x')、(2, 'b', 'y')、(3, 'c', 'z')

zip() 函数可以接受多个序列,将这些序列按索引位置打包成元组。这样可以轻松地将多个序列合并成一个元组的列表。

4、使用 zip() 实现矩阵转置

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

transposed = list(zip(*matrix))
print(transposed)
# 输出:[(1, 4, 7), (2, 5, 8), (3, 6, 9)]

在这个例子中,zip(*matrix) 将矩阵进行转置操作,将行变成列,实现了矩阵的转置。
zip() 函数在处理多个序列时非常有用,能够简化多序列的处理和操作。

5、注意事项

  1. 长度不一致的情况: 如果传入的可迭代对象长度不一致,zip() 函数会以最短的可迭代对象的长度为准,忽略超出部分。
  2. 迭代器: zip() 返回的是一个迭代器,如果需要查看结果,需要转换成列表或者使用在循环中进行遍历。
  3. 多个可迭代对象: zip() 可以接受多个可迭代对象作为参数,它将按照这些可迭代对象的索引位置进行打包。
  4. 空迭代对象: 如果传入空的可迭代对象,zip() 返回的迭代器也将为空。

zip() 函数常用于同时迭代多个序列或列表,并且将它们配对成元组,方便同时处理多个序列的对应位置的元素。

第十三章、map类

注意,map不改变原list,而是返回一个新list

在Python中,map() 是一个内置函数,它接受一个或多个可迭代对象(通常是函数和一个或多个序列)作为参数,并返回一个迭代器,该迭代器根据提供的函数对序列中的元素进行映射(转换)操作。map() 函数的语法如下:

map(function, iterable, ...)
  • function: 一个函数,它将被用于对每个可迭代对象中的元素进行映射操作。
  • iterable: 一个或多个可迭代对象,可以是序列(如列表、元组等)或其他可迭代对象。

返回值: map() 函数返回一个迭代器,该迭代器包含了通过将提供的函数应用于每个可迭代对象中对应元素而获得的结果。

示例:

# 演示map函数
def square(x):
    return x ** 2

numbers = [1, 2, 3, 4, 5]

#使用map()将函数用于与可迭代对象中的每一个值
squared_numbers = map(square,numbers)
print(squared_numbers) #<map object at 0x0000020D15CCA898>

#将迭代器转换为列表以查看结果
squared_numbers_list = list(squared_numbers)
print(squared_numbers_list) #[1, 4, 9, 16, 25]

在这个示例中,我们定义了一个 square() 函数来计算一个数的平方。然后,我们使用 map(square, numbers)square() 函数应用于 numbers 列表中的每个元素,生成一个迭代器。最后,通过将迭代器转换为列表,我们可以查看映射后的结果。

使用匿名函数(Lambda 函数):

map() 通常与匿名函数(lambda 函数)一起使用,以便在映射过程中直接指定函数逻辑,而不必事先定义函数。

numbers = [1, 2, 3, 4, 5]

# 使用map()和匿名函数将每个数加倍
doubled_numbers = map(lambda x: x * 2, numbers)

doubled_numbers_list = list(doubled_numbers)
print(doubled_numbers_list)

输出:

[2, 4, 6, 8, 10]

在这个示例中,我们使用匿名函数将每个数加倍,然后通过 map() 函数将匿名函数应用于 numbers 列表中的每个元素。

总之,map() 函数在需要对可迭代对象中的每个元素应用函数进行转换操作时非常有用,它返回一个迭代器,可以通过转换为列表或循环迭代来访问映射后的结果。

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值