一、__doc__
用于获取对象的文档字符串,文档字符串用三重引号表示,可以在函数、类、模块等Python对象中使用,于描述该对象的用途、参数、返回值等信息。
def my_function(): """This is the docstring for my_function.""" pass print(my_function.__doc__) # Output: This is the docstring for my_function.
二、__name__
__name__的值取决于代码是如何运行的。当我们编写一个Python脚本时,我们可以使用__name__变量来判断代码是被直接运行还是被导入到其他程序中时执行。一个模块被直接运行时,Python会把__name__赋值为__main__,否则__name__的值为模块名。
直接运行时执行:
def main(): print("Hello, world!") if __name__ == "__main__": main()
__main__:
"""__main__
是Python中的一个特殊内置变量,用于标识程序的入口。通过使用if __name__ == "__main__":
语句,我们可以将一个函数或类作为程序的入口。
"""导入时执行:
example.py
def say_hello(): print("Hello, world!") if __name__ == "example": # 直接运行该py时,没有任何显示,因为__name__的值为__main__ say_hello()test.py
import example print(example.__name__) # 导入时__name__为模块名 # 运行结果为: """ Hello, world! example """ #解释:在导入example时会运行example模块里的代码,这时__name__的值为example模块名,执行say_hello()函数
三、__file__
用于获取当前模块的文件路径。在Python中,每个模块都有一个__file__属性,可以通过该属性获取模块所在的文件路径。__file__变量可以用于获取模块所在的目录,或者用于读取模块所在的文件内容。
# test.py print(__file__) #/Users/bangbang/PycharmProjects/pythonProject/test.py # 获取文件目录 import os os.path.dirname(__file__) # 绝对路径 os.path.abspath(__file__) #/Users/bangbang/PycharmProjects/pythonProject/test.py
# 当前文件的绝对路径的目录
os.path.dirname(os.path.abspath(__file__))
# __file__与os.path.abspath(__file__)有什么区别
""" os.path.abspath(__file__)获取的是当前脚本的绝对路径,而__file__获取的是当前脚本的相对或绝对路径。在大多数情况下,这两种方法都可以得到相同的结果。
但是,如果脚本被移动到另一个位置,则__file__可能会得到错误的路径,而os.path.abspath(__file__)则总是可以得到正确的绝对路径。 """
# 读取当前模块内容
with open(__file__,mode='r',encoding="utf-8") as f:
print(f.read())
四、__all__(一般不使用,我们都是导入具体的属性或方法,很少导入整个模块)
用于定义模块中哪些属性、方法和类应该被导出,以供其他程序使用。当使用from module import *
语句时,只会导入__all__
中定义的属性、方法和类。如果__all__
未定义,则默认导入所有不以下划线开头的属性、方法和类。需要注意的是,__all__
只对from module import *
语句起作用,对于其他导入方式,如import module
和from module import name
,__all__
不会生效。因此,在编写模块时,应该避免使用from module import *
语句,而应该显式地导入需要的内容。
# module.py def public_function(): pass def _private_function(): pass class PublicClass: pass class _PrivateClass: pass __all__ = ['public_function', 'PublicClass']
# 在使用from module import *
语句导入模块时,只会导入public_function
和PublicClass
,而不会导入_private_function
和_PrivateClass
补充知识:
python内置函数 dir()、globals()、locals()
dir():查看当前范围或参数范围内的信息,包括属性、方法、类、变量等,列表的方式返回
""" 当不带参数调用dir()函数时,它返回当前范围内的变量、方法和定义的类型列表。当调用dir()函数时带参数,它返回参数的属性和方法列表。如果参数包含__dir__()方法,
该方法将被调用。如果参数不包含__dir__()方法,dir()函数将最大限度地收集参数信息。 """
dir() # 当前模块
dir(math) # 查看math类里的所有属性,方法globals():
""" 以字典类型返回当前位置之前的全部全局变量。符号表包含有关当前程序的必要信息,比如模块中定义的函数、类和变量、模块属性等 """ test.py """这是一个文档字符串""" a = 2 print(globals()) __name__ = 'test2' b = 3 # 结果 {'__name__': '__main__', '__doc__': '这是一个文档字符串', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x103687710>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/bangbang/PycharmProjects/pythonProject/test2.py', '__cached__': None, 'a': 2} # 因此并没有__name__和blocals():
""" 用于返回当前位置的全部局部变量,包括文档的属性,以字典类型返回。该函数适用于函数、方法、lambda 函数、类。 """ def test(): a = 1 b = 2 print(locals()) test() # {"a":1, "b":2}
五、__dict__
Python 中的特殊内置变量 __dict__
是一个字典,用于存储对象或类的属性。__dict__
存储类的属性,包括类属性和方法;在实例中,__dict__
存储实例的属性,包括实例变量。我们可以将其理解为一个容器
class MyClass: def __init__(self, x, y): self.x = x self.y = y obj = MyClass(1, 2) print(obj.__dict__) # 输出 {'x': 1, 'y': 2},字典形式输出实例属性 # 因为我们将其理解为一个容器,除了访问实例变量,__dict__ 还可以用于动态添加或删除实例变量。 obj.__dict__['z'] = 3 print(obj.z) # 输出 3
访问类变量
class MyClass: classVar = 1 obj = MyClass() print(obj.__class__.__dict__['classVar']) # 输出 1 # 方法二访问 MyClass.__dict__['classVar'] # 输出 1, obj.__class__就是指向MyClass
MyClass.__dict__ #会输出类的属性和方法
六、__class__
1.__class__是一个指向对象所属类的指针。
2.对于类的实例,__class__指向该实例所属的类。
3.对于类,__class__指向该类的元类。
class MyClass: pass mc = MyClass() print(mc.__class__) # <class '__main__.MyClass'> print(MyClass.__class__) # <class 'type'>
七、__bases__
用于获取一个类的所有父类。__bases__是一个元组,由该类的父类构成,__bases__只包含了父类,而不包含更远的祖先类。
class A: pass class B(A): pass class C(A): pass print(B.__bases__) # (<class '__main__.A'>,) print(C.__bases__) # (<class '__main__.A'>,) """ 为什么打印会出现__main__.A,因为这是表示这个py文件作为主程序运行,所以A类是在最高层级代码环境下定义的,因此它的名称中包含__main__。
当在其他py文件中导入此模块,则打印结果为:
(<class 'example.A'>,)
(<class 'example.A'>,)
为模块名 """
八、__slots__
__slots__
是Python中的一个特殊变量,可以限制类的实例只能有固定的属性(类可调用__slots__和__dict__,对类没有限制)。在Python中,每个实例对象都有一个字典(__dict__)用于存储属性。在使用__slots__
后,实例对象不再有自己的字典,不存在__dict__,只能绑定__slots__
中的属性,__dict__与__slots__只能存在一个。这样可以减少实例对象的内存使用,并提高访问属性的速度。
class Person: __slots__ = ('name', 'age') def __init__(self, name, age): self.name = name self.age = age p = Person('Alice', 25) print(p.name) # 输出:Alice print(p.age) # 输出:25 # 增加一个新属性 # p.gender = 'female' # 报错:AttributeError: 'Person' object has no attribute 'gender' # 访问__dict__ # print(p.__dict__) # AttributeError: 'Person' object has no attribute '__dict__'
print(Person.__slots__)
Person.ss = "asd"
print(Person.__dict__)
九、__weakref__
__weakref__是Python的一个特殊内置变量,它可以用于创建弱引用(weak reference)对象,弱引用对象可以引用一个对象,但是不会增加这个对象的引用计数。当一个对象只被弱引用对象所引用时,Python的垃圾回收机制会将其销毁并回收内存。
class MyClass: pass obj = MyClass() obj.ref = obj # 删除obj对象的引用,但是由于obj.ref还在引用它,所以obj对象并不会被销毁 obj = None # other.py import weakref class MyClass: pass obj = MyClass() obj.ref = weakref.ref(obj) # 删除obj对象的引用,此时obj对象只被弱引用对象所引用,所以obj对象会被销毁 obj = None
__weakref__的优点:
- 可以避免内存泄漏,提高程序的稳定性和可靠性。
- 可以减少对象的引用计数,从而让垃圾回收更加高效。
__weakref__的缺点:
- 使用__weakref__会增加程序的复杂度和代码量。
- 使用__weakref__可能会降低程序的性能,因为创建弱引用对象需要额外的开销。
import weakref class MyClass: pass obj = MyClass() ref = weakref.ref(obj) print(ref) # <weakref at 0x7f5c5e5a5b00; to 'MyClass' at 0x7f5c5e5a5a90> print(ref()) # <__main__.MyClass object at 0x7f5c5e5a5a90> del obj print(ref()) # None """ 当一个对象只被弱引用对象所引用时,Python的垃圾回收机制会将其销毁并回收内存(del时),从而避免了内存泄漏。 """
使用场景:在需要缓存大对象或映射时,避免对象被缓存或映射所持有,从而导致内存泄漏。
十、__module__
用于记录该类或函数所在的模块名。
class Person: __slots__ = ('name', 'age') """类对象""" a = 1 def __init__(self, name, age): self.name = name self.age = age print(locals()) p = Person('Alice', 25) print(Person.__module__) # __main__ print(p.__module__) # __main__ def func(): pass print(func.__module__) # __main__ """ 为什么是__main__: 当一个文件被作为脚本直接执行时,它就是主模块,因此__module__的值就是__main__,和__name__类似,导入时__module__值为模块名,区别就是__module__前跟函数或类对象,是函数或类对象的属性 """
十一、__annotations__
__annotations__
是函数维护的一个字典,即返回一个字典,可返回函数、模块、类的注释类型 。
函数:
def add(x: int, y: int = 1) -> float: return x + y print(add.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'float'>} 函数定义中的注解可以通过访问函数的__annotations__属性来获取,该属性是一个字典,其中键是参数名称,值是注解的内容 """ _annotations__属性提供了一种机制来记录函数的设计和预期用途,但并不是强制性的。使用注解来进行类型检查不是Python中的标准做法,可以使用第三方库来实现 """ class A(): def __init__(self, x:int,y:int): self.x = x self.y = y obj = A(1,2) print(obj.__init__.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>}类:
name: str
和age: int
就是对类的属性的注释class Person: name: str age: int print(Person.__annotations__) # {'name': <class 'str'>, 'age': <class 'int'>}
模块:
module_var: str
和st:str 就是对模块变量的注释st:str = "hello world" module_var: str = "Hello, world!" print(__annotations__) # {'st': <class 'str'>, 'module_var': <class 'str'>}
十二、__builtins__
__builtins__
是Python内置模块的一部分,包含Python的内置函数、变量和异常。在Python启动时,它会自动加载,无需显式导入即可使用其中的任何内容。在一些特殊情况下,可以通过重定义__builtins__
来模拟内置函数的行为,但是在普通的Python代码中,应该避免使用这种技巧。
import builtins print(builtins.dir()) # ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'builtins'] print(__builtins__.dir()) # ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'builtins'] # 访问内置函数 print(__builtins__.list('abc')) # ['a', 'b', 'c'] """ 导入builtins 和使用内置模块__builtins__ 一样,同样可以访问python的内置函数,如果想命名与内置函数相同的函数名,要调用内置函数就用builtins,当然通常我们不这样做,下面是重命名内置函数案例:(当然还是可以使用原来的open) """ # 重命名内置函数 import builtins def my_open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): print("Opening file...") return builtins.open(file, mode, buffering, encoding, errors, newline, closefd, opener) # 使用自定义的open函数 with my_open("example.txt", "w") as f: f.write("Hello World")
十三、__cached__
__cached__
就是用来表示缓存路径的一个字符串。当Python解释器首次导入一个模块时,它会在sys.path
中查找该模块,并将该模块编译成一个字节码文件。这个字节码文件会被存储在__pycache__
目录中(缓存),并且包含模块的版本信息和时间戳等元数据。下次导入该模块时,Python解释器会首先检查缓存中是否有该模块的字节码文件,并且检查该字节码文件是否已过期,如果没有过期,则直接加载缓存中的字节码文件,否则重新编译模块的源代码并更新缓存。
import os print(__cached__) # None,是因为我们在交互式Python环境中运行这个例子,而__cached__变量只有在模块被导入时才会被设置。 print(os.path.abspath(__cached__)) # 报错 print(os.__cached__) print(os.__file__) print(os.path.abspath(os.__cached__)) """ /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/__pycache__/os.cpython-36.pyc /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/__pycache__/os.cpython-36.pyc """ # example.py print(__cached__) # None # test.py import example """ 运行test.py后打印了:Users/bangbang/PycharmProjects/pythonProject/__pycache__/example.cpython-36.pyc。
导入时,python对该模块编译成字节码后进行了缓存,下次再导入则从缓存中取该模块的字节码并进行解释 """
十四、__loader__
__loader__
是一个特殊的内置变量,它在模块加载时被设置为加载该模块的导入器。它是一个可选的模块级别属性,它可以用来指定模块的加载器。
补充知识:sys.path
sys.path
是一个Python内置的列表,用于存储Python搜索模块时可以搜索的路径。因此我们可以添加自己的模块路径到该列表的最前面来优先加载模块。当模块名称与第三方模块或系统模块冲突时,Python会优先搜索
sys.path
列表中的路径。
sys.path
的作用是指定Python解释器在哪些目录下搜索模块,以便正确导入模块。
sys.path
可以在Python运行后添加自定义模块路径,然后直接导入模块。与PYTHONPATH
不同,sys.path
可以在Python运行后添加自定义模块路径,而不需要重新启动Python解释器。sys.path
可以通过os.environ['PYTHONPATH']
来传递自定义模块路径,这样Python解释器就可以搜索到自定义模块路径中的模块。
sys.path
变量的初始化值来自以下三个部分:
- 输入脚本的目录(当前目录)。
- 环境变量PYTHONPATH表示的目录列表中搜索。
- Python默认安装路径中搜索。
模块加载器、模块加载流程、模块的作用:
模块加载器:
在Python中,模块的加载器是由解释器内部完成的,无需用户干预。
模块加载流程:
当我们导入一个模块时,Python解释器会按照一定的搜索路径找到对应的模块文件,并将其加载到内存中。模块文件可以是以.py结尾的Python源代码文件,也可以是以.so、.pyd等二进制格式编译过的文件。模块的加载顺序如下:
- 首先,Python会在当前目录下查找模块文件,如果找到了就直接加载。
- 如果在当前目录下没有找到,Python会按照sys.path变量中指定的搜索路径依次查找,直到找到为止。sys.path是一个包含了Python解释器搜索模块文件的路径列表,其中包括了PYTHONPATH环境变量指定的路径以及Python的安装路径等。
- 如果在所有的搜索路径中都没有找到对应的模块文件,Python会抛出ImportError异常。
模块的作用:
模块的主要作用是将相关的代码组织成一个可重用的单元,使得代码更加易于维护和扩展。
Python中的命名空间可以分为以下几种:
- 局部命名空间:每个函数都有自己的局部命名空间,其中包含了函数中定义的变量以及外部变量的引用。
- 全局命名空间:Python解释器启动时会创建一个全局命名空间,其中包含了程序中定义的所有全局变量和函数。
- 内置命名空间:内置命名空间是Python解释器内部提供的一个命名空间,其中包含了Python解释器内部定义的所有常量、函数和类型。
十五、__package__
它用于表示当前模块的包名。__package__的出现是为了解决Python中包的相对导入问题,它的值由Python解释器自动设置,通常无需手动设置。在Python 3中,相对导入必须显式地使用相对路径来实现,而__package__变量则提供了当前模块所在包的信息,使相对导入更加简单和可靠。
解决脚本问题。__package__为none,没有包名导致脚本相对导入出问题,这时需要手动设置__package__名称
十六、__spec__
特殊内置变量__spec__是Python 3.4引入的新功能,它用于指定模块的特定属性,如名称、加载器、子模块等。它可以用于控制模块的加载和行为,特别是在导入子包时非常有用。__spec__变量是在导入模块时自动设置的。
__spec__变量是一个包含以下属性的命名元组:
- name: 模块的名称
- loader: 用于加载模块的加载器
- origin: 模块的源文件的路径或描述字符串
- submodule_search_locations: 子模块的搜索路径
import math print(math.__spec__) """ ModuleSpec(name='math', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in') 从输出中可以看出,math模块使用内置导入器加载,因为它是内置模块。如果我们导入一个自定义模块,__spec__变量将显示模块的详细信息。 """自定义的模块:
import my_module print(my_module.__spec__) """ ModuleSpec(name='my_module', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5daa9f7c10>, origin='/path/to/my_module.py') 在这个例子中,我们可以看到my_module是从源文件加载的,因为它的loader属性是_SourceFileLoader_。 """作用:
""" __spec__变量对于动态加载模块非常有用,因为它可以用于指定模块的加载器和源文件路径。它还可以用于控制模块的行为,例如在导入子包时执行特定操作。 """
持续更新中。。。。。。。。。。。