内建(内置)对象 (builtins)

我们常用的python内置函数,如print, help, max, dict等等是可以直接使用,不需要导入的。

__builtins__模块__builtins__ 是一个特殊的模块,它包含了所有内建(内置)的函数、异常和其他对象。当你启动一个 Python 解释器或运行一个 Python 脚本时,builtins 模块会自动加载到全局命名空间中。这意味着你可以在不显式导入的情况下直接使用这些内建函数和对象,例如 print(), len(), str(), int() 等等。

这个__builtins__就相当于我们 import builtins,不过我们没有必要显示导入builtins,因为里面这些内置对象是可以直接使用的,因为会自动加载到全局命名空间中。

print(__builtins__)
print(builtins)
print(__builtins__.print)

输出结果:

<module 'builtins' (built-in)>
<module 'builtins' (built-in)>
<built-in function print>

Stubs 文件: 当我们在使用像pycharm这种IDE去尝试查看一些内置函数的源码时,通常我们会发现导航到的源文件类似于 \user\AppData\Local\JetBrains\PyCharmCE2024.2\python_stubs\-2062853821\builtins.py 这样的路径,这是因为 PyCharm 使用了一个称为“stubs”的机制来提供更好的代码补全和类型检查功能。
Stubs 文件是一种特殊的 .pyi 文件,它们包含类型注解和其他元数据,但不包含实际的实现代码。这些文件主要用于静态分析工具(如 PyCharm 的代码编辑器),以便提供更准确的代码补全、类型检查和导航功能。
实际的内置模块和标准库模块通常是用 C 语言编写的,直接解析这些模块的源代码可能会比较慢。Stubs 文件提供了轻量级的替代方案,使得 IDE 可以更快地进行代码分析。

dir(): dir()函数用于返回某个对象的属性,其参数可以为任何对象,包括模块,类,类的实例,方法等。如果不传参数,那么dir()返回的结果取决于它被调用的范围。例如,如果其在模块全局被调用,则返回的是该模块的所有属性,如果是在函数内部,则返回的是函数内的局部变量及参数。
有时候,如果对象自己有__dir__属性,那么执行dir(obj)等价于执行obj.__dir__()。如果对象实现了自己的__dir__方法,那么dir(obj)的运行结果为__dir__方法的返回值。
传给dir的参数为类对象或实例对象时,dir返回的属性包括实例自身的属性,对应的类属性,以及类的父类的属性。
因此,dir函数的返回结果不光是看对象自己的__dict__属性,还会看其类、父类的。

print('dir在全局调用')
print(dir())

import struct
print('dir在导入模块后的全局调用')
print(dir())

def f(par):
    a = 1
    return dir()

print('dir在函数内部调用')
print(f('haha'))

class Bar():
    base_bar = 'base_bar'
    print('dir在class内部调用')
    print(dir())

class SubBar(Bar):
    sub_bar = 'sub_bar'


print('给dir传入类对象做为参数')
print(dir(Bar))

print('给dir传入子类做为参数')
print(dir(SubBar))

bar = Bar()
print('给dir传入实例对象做为参数')
print(dir(bar))

sub_bar = SubBar()
sub_bar.inst_prop = 'inst_prop'
print('给dir传入子类实例对象做为参数')
print(dir(sub_bar))

print('给dir传入函数做为参数')
print(dir(f))
print(f.__dir__())

class Foo():
    cls_pro = 'cls_pro'
    def __init__(self):
        self.obj_pro1 = 'obj_pro1'
        self.obj_pro2 = 'obj_pro2'
        self.obj_pro3 = 'obj_pro3'
    def __dir__(self):
        return [self.obj_pro1,self.obj_pro2]

foo = Foo()
print('类对象实现了__dir__方法,实例对象的dir将是')
print(dir(foo))

print(foo.__dir__())

输出结果:

dir在全局调用
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
dir在导入模块后的全局调用
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'struct']
dir在函数内部调用
['a', 'par']
dir在class内部调用
['__module__', '__qualname__', 'base_bar']
给dir传入类对象做为参数
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'base_bar']
给dir传入子类做为参数
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'base_bar', 'sub_bar']
给dir传入实例对象做为参数
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'base_bar']
给dir传入子类实例对象做为参数
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'base_bar', 'inst_prop', 'sub_bar']
给dir传入函数做为参数
['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['__new__', '__repr__', '__call__', '__get__', '__closure__', '__doc__', '__globals__', '__module__', '__builtins__', '__code__', '__defaults__', '__kwdefaults__', '__annotations__', '__dict__', '__name__', '__qualname__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__reduce_ex__', '__reduce__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
类对象实现了__dir__方法,实例对象的dir将是
['obj_pro1', 'obj_pro2']
['obj_pro1', 'obj_pro2']

help(): help函数用于查看一个对象的说明,相当于查看对象的__doc__属性。 一般当我们不能使用像pycharm这种强大的编辑器时,可以通过help()函数在不查看源码的情况下查看该对象的使用说明。

def f():
    '''parm: 无参数
    返回一个内部变量的值'''
    a = 1
    return a
print("下面是__doc___属性输出的内容")
print('-' * 25, '分隔线', '-' * 25)
print(f.__doc__)
print()
print("下面是用help函数输出的内容")
print('-' * 25, '分隔线', '-' * 25)
print(help(f))

输出结果:

下面是__doc___属性输出的内容
------------------------- 分隔线 -------------------------
parm: 无参数
    返回一个内部变量的值

下面是用help函数输出的内容
------------------------- 分隔线 -------------------------
Help on function f in module __main__:

f()
    parm: 无参数
    返回一个内部变量的值

None

getattr(), hasattr(): getattr函数相当于obj.attribute这种方式去获取属性值,但它额外提供一个default参数,用于属性不存在时返回缺省值。否则会抛出AttributeError异常。
hasattr()用于判断一个对象的属性是否存在,因此不会抛出异常。
由于有__getattr__, __getattribute__,以及描述器的存在,python的属性访问机制是高度动态的,可以相当复杂, 而不是简单的访问对象的__dict__属性里的内容。 假设我们只考虑简单的情况,那么属性查找的顺序为 实例对象 -> 类对象 -> 类的基类对象。

class Bar():
    base_bar = 'base_bar'
    base_other_prop = 'base_other_prop'
    __class_private = 'class_private'

class SubBar(Bar):
    sub_bar = 'sub_bar'

bar = Bar()
sub_bar = SubBar()

sub_bar.self_prop = 'self_prop'
sub_bar.__private_prop = 'private_prop'

print(getattr(Bar, 'base_bar', 'Bar中base_bar不存在')) # 属性来源于类对象本身
print(getattr(bar, 'base_bar', 'bar中base_bar不存在')) # 属性来源于实例对象的类对象
print(getattr(sub_bar, 'base_bar', 'sub_bar中base_bar不存在')) # 属性来源于实例对象的类的基类
print(getattr(bar, 'self_prop', 'bar中self_prop不存在')) # 子类的实例本身的对象在父类及父类实例中是访问不到的
print(getattr(sub_bar, '__private_prop', 'sub_bar中__private_prop不存在')) # 类的实例自己添加的双下划线开头的属性可以在类的实例中直接访问到
print(getattr(sub_bar, '__class_private', 'sub_bar中__class_private不存在')) # 类对象中定义的双下划线开头的属性在类的实例中不能直接访问到
print(getattr(sub_bar, '_Bar__class_private', 'sub_bar中_Bar__class_private不存在')) # 类对象中定义的双下划线开头的属性只能以_类名__属性名的方式访问到


print('-' * 25, '分隔线', '-' * 25)

print(hasattr(Bar, 'base_bar')) # True
print(hasattr(bar, 'base_bar')) # True
print(hasattr(sub_bar, 'base_bar')) # True
print(hasattr(sub_bar, 'self_prop')) # True
print(hasattr(bar, 'self_prop')) # False  父类及实例不可能访问到子类及实例中定义的属性。
print(hasattr(sub_bar, '__private_prop')) # True 实例对象中添加的属性,即便是以双下划线开头命名,也可以直接访问。
print(hasattr(sub_bar, '__class_private')) # False 类对象中定义的双下划线开头的属性,只能以_类名__属性名 的方式访问到。
print(hasattr(sub_bar, '_Bar__class_private')) # True 类对象中定义的双下划线开头的属性,只能以_类名__属性名 的方式访问到。

print('-' * 25, '分隔线', '-' * 25)

print(sub_bar.__private_prop)  # 实例对象中添加的双下划线开头的属性可以直接访问到
print(sub_bar._Bar__class_private) # 类对象中定义的双下划线开头的私有属性,在类对象本身,及其实例对象中,只能以_类名__属性名的方式访问。

输出结果:

base_bar
base_bar
base_bar
bar中self_prop不存在
private_prop
sub_bar中__class_private不存在
class_private
------------------------- 分隔线 -------------------------
True
True
True
True
False
True
False
True
------------------------- 分隔线 -------------------------
private_prop
class_private

setattr(): setattr函数给一个对象添加一个属性,或修改一个已存在的属性值。 相当于obj.attribute=value的用法。 其也受到python属性访问机制的影响,比如描述器。 不过在简单的场景中,他的效果也与getattr与setattr这两个方法的机制有所不同。 即,当对一个对象的属性赋值时,它不会去查找其类对象及基类中的同名属性,而是直接修改当前对象的属性值(若对象中已存在同名属性),或添加一个属性(若对象自身并不存在该属性,即使其所属的类或基类中可能存在同名属性)

class Bar():
    base_bar = 'base_bar'
    base_other_prop = 'base_other_prop'
    __class_private = 'class_private'

class SubBar(Bar):
    sub_bar = 'sub_bar'

bar = Bar()
sub_bar = SubBar()

sub_bar.self_prop = 'self_prop'
sub_bar.__private_prop = 'private_prop'


print('-' * 25, '分隔线', '-' * 25)

sub_bar.base_bar = 'sub_base_bar'  # 给sub_bar实例添加自己的属性,而不是修改类对象的属性值
print(bar.base_bar) # bar实例访问的仍然是类对象的属性
print(sub_bar.base_bar) # sub_bar实例访问的是自身的属性

setattr(bar, 'base_other_prop', 'instance_other_prop')  # 给bar实例添加自己的属性,而不是修改类对象的属性值

print(bar.base_other_prop) # bar实例访问的是自身刚添加的属性
print(sub_bar.base_other_prop) # sub_bar实例由于自身没有base_other_prop属性,所以查找其类对象,发现类对象上也没有,最终在父类对象中找到了该属性。

输出结果:

------------------------- 分隔线 -------------------------
base_bar
sub_base_bar
instance_other_prop
base_other_prop

globals() 和 locals(): 这两个函数是以字典的形式分别返回全局和局部命名空间中的变量信息。 globals()函数无论用在哪里,都返回其所在模块的全局变量信息,locals()函数若用在模块全局范围,则效果等同于globlas()。修改globals()返回的字典,相当于动态修改了当前模块全局命名空间里的变量,比如增加变量,修改变量值等,一般用于元编程,不推荐普通情况下使用。但locals()返回的字典则是局部变量信息的一个快照,修改其内容并不会真正的影响到局部变量,这点是与globals()机制不同的。
dir()函数返回的是对象的变量列表,只能用于查看或检查一个对象所拥有的变量,但其列表内容与这两个函数返回的字典中的key基本上相同,并且如果locals()函数放在一个子类中,它会像dir()函数一样,返回的变量中也包含其父类中的属性。
vars(): vars函数在不传参数的情况下,用在全局范围相当于globlas函数,用在局部范围相当于locals函数。当传给其对象做为参数时,相当于访问了该对象的__dict__属性,所以不包含其类对象及父类对象中的属性。

class Parent():
    cls_parent = 'cls_parent'

class Foo(Parent):
    cls_prop = 1
    print('')
    print('-' * 25, 'inside class', '-' * 25)
    print('globals:', globals())
    print('locals:', locals())  # 变量信息里会包含其父类中的属性 cls_parent
    print('dir:', dir()) # 变量信息里会包含其父类中的属性 cls_parent
    print('vars:', vars())

def bar(par: str):
    v_local = 2
    locals()['local_bar'] = 'local_bar'  # 修改locals()返回的字典并不会真正的影响到局部变量
    vars()['local_bar2'] = 'local_bar2'  # 修改vars()返回的字典并不会真正的影响到局部变量
    print('')
    print('-' * 25, 'inside function', '-' * 25)
    print('globals:', globals())
    print('locals:', locals())
    print('dir:', dir())
    print('vars:', vars())
    try:
        print(local_bar)  # 由于并没有真正声明local_bar变量,这里会报错的。
    except NameError as e:
        print("NameError, local_bar 局部变量不存在:", e)
    try:
        print(local_bar2)  # 由于并没有真正声明local_bar2变量,这里会报错的。
    except NameError as e:
        print("NameError, local_bar2 局部变量不存在:", e)


print('')
print('-' * 25, 'outside function', '-' * 25)
print('globals:', globals())
print('locals:', locals())
print('dir:', dir())
print('vars:', vars())

bar('None') # 调用函数

globals()['haha'] = 'hehe'  # 修改globals()返回的字典会真正的影响全局变量
vars()['guagua'] = 'guagua'  # 修改vars()返回的字典会真正的影响全局变量
print('')
print('-' * 25, '动态修改globals返回的字典后', '-' * 25)
print('globals:', globals())
print('vars:', vars())
print('globals返回的字典填加的变量:', haha)  # 虽然pycharm提示这个变量不存在,但实际执行时是不报错的。
print('vars返回的字典填加的变量:', guagua)  # 虽然pycharm提示这个变量不存在,但实际执行时是不报错的。

print('')
print('-' * 25, '查看实例对象', '-' * 25)
foo = Foo()  # 实例化一个Foo类,注意其有基类。
print('dir(foo):', dir(foo))
print('vars(foo):', vars(foo))  # vars函数返回对象自身的__dict__字典里存储的变量,而不包括对应的类对象及父类对象的属性。
print('foo.__dict__:',foo.__dict__)

输出结果:

------------------------- inside class -------------------------
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>}
locals: {'__module__': '__main__', '__qualname__': 'Foo', 'cls_prop': 1}
dir: ['__module__', '__qualname__', 'cls_prop']
vars: {'__module__': '__main__', '__qualname__': 'Foo', 'cls_prop': 1}

------------------------- outside function -------------------------
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>}
locals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>}
dir: ['Foo', 'Parent', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'bar']
vars: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>}

------------------------- inside function -------------------------
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>}
locals: {'par': 'None', 'v_local': 2, 'local_bar': 'local_bar', 'local_bar2': 'local_bar2'}
dir: ['local_bar', 'local_bar2', 'par', 'v_local']
vars: {'par': 'None', 'v_local': 2, 'local_bar': 'local_bar', 'local_bar2': 'local_bar2'}
NameError, local_bar 局部变量不存在: name 'local_bar' is not defined
NameError, local_bar2 局部变量不存在: name 'local_bar2' is not defined

------------------------- 动态修改globals返回的字典后 -------------------------
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>, 'haha': 'hehe', 'guagua': 'guagua'}
vars: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000200717F4C90>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py', '__cached__': None, 'Parent': <class '__main__.Parent'>, 'Foo': <class '__main__.Foo'>, 'bar': <function bar at 0x00000200717A04A0>, 'haha': 'hehe', 'guagua': 'guagua'}
globals返回的字典填加的变量: hehe
vars返回的字典填加的变量: guagua

------------------------- 查看实例对象 -------------------------
dir(foo): ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cls_parent', 'cls_prop']
vars(foo): {}
foo.__dict__: {}

isinstance(): 用于判断一个对象是否是一个类或其子类(包括子类,间接子类,或虚拟子类)的实例。
先看下最简单的示例:

print(isinstance(123, int))  # True
print(isinstance(123, str))  # False

再看一下自定义类的示例:

class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True

其实,可以判断一个对象是否是多个类中某一个的实例,可以使用元组,内置类型提示里的"|"符号,或使用typing.Union。

print(isinstance(123, (str, list)))  # False
print(isinstance(123, (int, list)))  # True
print(isinstance(123, str | list))  # False
print(isinstance(123, int | str))  # True

from typing import Union
print(isinstance(123, Union[str,list]))  # False
print(isinstance(123, Union[int | str]))  # True

一会补充虚拟子类的内容

issubclass(): 判断一个类是否为另一个类(或一组类)的子类(包括直接子类,间接子类,虚拟子类)。
其传参规则跟isinstance函数基本相同。

class Animal:
    pass

class Dog(Animal):
    pass

print(issubclass(Dog, Dog)) # True  判断一个类是其自身的子类也返回True
print(issubclass(Dog, Animal)) # True

print(issubclass(Dog, (int, Animal))) # True  判断一个类是其自身的子类也返回True
print(issubclass(Dog, (int, str))) # False

print(issubclass(Dog, str | list))  # False
print(issubclass(Dog, str | Animal))  # True

from typing import Union
print(issubclass(Dog, Union[str,list]))  # False
print(issubclass(Dog, Union[str | Animal]))  # True

稍后补充虚拟子类的内容

posted @ 2024-11-26 16:55  RolandHe  阅读(30)  评论(0编辑  收藏  举报