Python 反射和动态执行
反射主要应用于类的对象上,在运行时,将对象中的属性和方法反射出来,通过字符串对对象成员(属性、方法)进行查找、获取、删除、添加成员等动作,是一种基于字符串的事件驱动技术。
python是一门动态语言,有许多支持反射和动态执行的方法。
一般使用场景:动态的向对象中添加属性和方法;也可以动态的调用对象中的方法或者属性。
反射的内容包括但不限于如下内容:
- 反射类中成员
- 反射对象中的成员
- 反射模块中的成员
查询类型信息的函数
dir()
dir([object])
如果没有实参,则返回当前本地作用域中的名称列表。如果有实参,它会尝试返回该对象的有效属性列表。
如果对象有一个名为 __dir__() 的方法,那么该方法将被调用,并且必须返回一个属性列表。这允许实现自定义 __getattr__() 或 __getattribute__() 函数的对象能够自定义 dir() 来报告它们的属性。
如果对象未提供 __dir__() 方法,该函数会尽量从对象的 __dict__ 属性和其类型对象中收集信息。得到的列表不一定是完整,如果对象带有自定义 __getattr__() 方法时,结果可能不准确。
默认的 dir() 机制对不同类型的对象行为不同,它会试图返回最相关而不是最全的信息:
如果对象是模块对象,则列表包含模块的属性名称。
如果对象是类型或类对象,则列表包含它们的属性名称,并且递归查找所有基类的属性。
否则,列表包含对象的属性名称,它的类属性名称,并且递归查找它的类的所有基类的属性。
返回的列表按字母表排序。例如:
>>>import struct
>>>dir() # show the names in the module namespace
['__builtins__', '__name__', 'struct']
>>>dir(struct) # show the names in the struct module
['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__','__initializing__', '__loader__', '__name__', '__package__','_clearcache', 'calcsize', 'error', 'pack', 'pack_into','unpack', 'unpack_from']
>>>class Shape:def __dir__(self):return ['area', 'perimeter', 'location']
>>>s = Shape()
>>>dir(s)
['area', 'location', 'perimeter']
定义__dir__()
class Test:def __dir__(self):return ['a','b','c']t = Test()
print(dir(t))’’’
['a', 'b', 'c’]
‘’’
sys.modules
sys.modules是一个全局字典,该字典是python启动后就加载在内存中。每当程序员导入新的模块,sys.modules都将记录这些模块。字典sys.modules对于加载模块起到了缓冲的作用。当某个模块第一次导入,字典sys.modules将自动记录该模块。当第二次再导入该模块时,python会直接到字典中查找,从而加快了程序运行的速度。
字典sys.modules具有字典所拥有的一切方法,可以通过这些方法了解当前的环境加载了哪些模块
import sys
print(sys.modules[__name__])
#<module '__main__' from '/Users/PycharmProjects/pythonProject4/demo5.py’>print(sys.modules.values())
#dict_values([<module 'sys' (built-in)>, <module 'builtins' (built-in)>,…, <module 'site' (frozen)>])print(sys.modules.keys())
#dict_keys(['sys', 'builtins', '_frozen_importlib', '_imp', '_thread', '_warnings', '_weakref', '_io', 'marshal', 'posix', '_frozen_importlib_external', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', '_abc', 'abc', 'io', '__main__', '_stat', 'stat', '_collections_abc', 'genericpath', 'posixpath', 'os.path', 'os', '_sitebuiltins', '_virtualenv', '_distutils_hack', 'site'])print(sys.modules.items())
#dict_items([('sys', <module 'sys' (built-in)>), ..., ('site', <module 'site' (frozen)>)])
直接访问导入的模块
#demo6.pyDemo_Value='Demo6'
def foo6(name:str):print('--foo6()--')return 'Hello ' + name#demo5.pyimport sys
import math
import demo6print(sys.modules['math'])print(sys.modules['demo6'].Demo_Value)print(sys.modules['demo6'].foo6('John’))‘’'
<module 'math' from '/Users/xiebo/anaconda3/lib/python3.11/lib-dynload/math.cpython-311-darwin.so'>
Demo6
--foo6()--
Hello John
‘''
删除导入的模块
import sys
import math
import demo6print(sys.modules['math'])print(sys.modules['demo6'].Demo_Value)print(sys.modules['demo6'].foo6('John'))if 'demo6' in sys.modules:print('demo6 in sys.modules.')
else:print('demo6 not in sys.modules.')del sys.modules['demo6']
demo6.foo6('Rose') #不受影响,继续可以使用if 'demo6' in sys.modules:print('demo6 in sys.modules.')
else:print('demo6 not in sys.modules.')#print(sys.modules['demo6'].foo6('John')) #KeyError‘’'
Load demo6!
<module 'math' from '/Users/xiebo/anaconda3/lib/python3.11/lib-dynload/math.cpython-311-darwin.so'>
Demo6
--foo6()--
Hello John
demo6 in sys.modules.
--foo6()--
demo6 not in sys.modules.
‘''
vars()
内置函数 vars() 返回对象的属性和属性值的字典对象。如果没有参数,就返回当前调用位置的属性和属性值,行为类似 locals()。
语法为 vars([object])
,其中对象可有可没有。来用返回模块、类、实例或任何其它具有 __dict__
属性的对象的 __dict__
属性。
带参数:
模块和实例这样的对象具有可更新的 __dict__
属性;但是,其它对象的 __dict__
属性可能会设为限制写入(例如,类会使用 types.MappingProxyType 来防止直接更新字典)。
如果指定了一个对象但它没有 __dict__
属性(例如,当它所属的类定义了 __slots__
属性时)则会引发 TypeError 异常。
不带参数时,vars() 的行为类似 locals(), 用来更新并返回表示当前本地符号表的字典。 请注意,locals 字典仅对于读取起作用,因为对 locals 字典的更新会被忽略。
如,我们进行赋值操作时,如 bar = 1,执行赋值语句后,名称 bar 引用到值 1,名字为键,将我们要取这个值时,可以用 vars() 返回的字典里用此键取得其引用值:
bar = 1
vars()['bar']
# 1
'bar' in vars().keys()
# True
# 在终端输入
vars()
# 输出(已美化格式)
{'__name__': '__main__','__doc__': None,'__package__': None,'__loader__': <class '_frozen_importlib.BuiltinImporter'>,'__spec__': None,'__annotations__': {},'__builtins__': <module 'builtins' (built-in)>
}# 1 对象没有__dict__ 属性
vars(1)
# TypeError: vars() argument must have __dict__ attributeclass Foo:def __init__(self):self.__dict__ = {'name':'Foo'}f = Foo()
vars(f)
# {'name': 'Foo'}# 再终端执行
vars()
# 输出(已美化格式)
{'__name__': '__main__','__doc__': None,'__package__': None,'__loader__': <class '_frozen_importlib.BuiltinImporter'>,'__spec__': None,'__annotations__': {},'__builtins__': <module 'builtins' (built-in)>,'Foo': <class '__main__.Foo'>,'f': <__main__.Foo object at 0x7fccf35f5120>
}
# 注意最后两项
__dict__
类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的 __dict__
里。一些内置的数据类型是没有 __dict__
属性的。
globals()
globals() 返回实现当前模块命名空间的字典。对于函数中的代码,这是在定义函数时设置的,并且无论在何处调用函数都保持不变。
符号表是由编译器维护的一种数据结构,它包含有关程序的所有必要信息。其中包括变量名、方法、类等。符号表主要有两种:局部符号表全局符号表。
局部符号表存储与程序的本地范围相关的所有信息,并在 Python 中使用 locals() 方法进行访问。局部作用域可以在函数、类等中。
同样,全局符号表存储与程序全局范围相关的所有信息,并在Python中使用 globals() 方法进行访问。全局范围包含与任何类或函数都不关联的所有函数和变量。
globals 表字典是当前模块的字典(在函数内部,这是定义它的模块,而不是调用它的模块)。
foo = 123globals()['foo'] = 456 # 修改
globals()['bar'] = 789 # 新增foo # 456
bar # 789
locals()
函数 locals() 更新并返回表示当前本地符号表的字典,它没有可传入的参数。 在函数代码块但不是类代码块中调用 locals() 时将返回自由变量。 请注意在模块层级上,locals() 和 globals() 是同一个字典。Python 的命名空间通过一种字典的形式来体现, 而具体到函数也就是 locals() 和 globals(), 分别对应着局部命名空间和全局命名空间。
# 在终端输入
locals()
# 输出(已美化格式)
{'__name__': '__main__','__doc__': None,'__package__': None,'__loader__': <class '_frozen_importlib.BuiltinImporter'>,'__spec__': None,'__annotations__': {},'__builtins__': <module 'builtins' (built-in)>
}# 1 对象没有__dict__ 属性
vars(1)
# TypeError: vars() argument must have __dict__ attributeclass Foo:def __init__(self):self.__dict__ = {'name':'Foo'}f = Foo()# 再终端执行
locals()
# 输出(已美化格式)
{'__name__': '__main__','__doc__': None,'__package__': None,'__loader__': <class '_frozen_importlib.BuiltinImporter'>,'__spec__': None,'__annotations__': {},'__builtins__': <module 'builtins' (built-in)>,'Foo': <class '__main__.Foo'>,'f': <__main__.Foo object at 0x7fccf35f5120>
}
# 注意最后两项
我们进行赋值操作时,如 bar = 1,执行赋值语句后,名称 bar 引用到值 1,名字为键,将我们要取这个值时,可以用 vars() 返回的字典里用此键取得其引用值:
bar = 1
locals()['bar']
# 1
'bar' in locals().keys()
# True
以下是几个相关内置函数对比表:
函数 | 有参数 | 无参数 | 返回类型 |
---|---|---|---|
globals() | - | 当前作用域全局变量,可以更新 | dict |
locals() | - | 当前作用域的局部变量,不应该被修改 | dict |
vars([object]) | 对象属性,同 object.__dict__ | 同 locals(),可以更新 | dict |
dir([object]) | 对象的属性、方法(含特殊方法)名称 | 当前作用域中的名称 | list |
Python globals() locals() vars() 三个内置函数的区别:
- globals() 始终返回模块命名空间的字典
- locals() 始终返回当前命名空间的字典
- vars() 返回当前命名空间的字典(如果调用时没有参数)或对象的字典
更多:
- globals()
- 作用:返回当前全局符号表, 通常在是返回当前模块下的全局符号表, 比如全局内建的函数,以及模块里的全局符号(定义声明的变量,类, 实例等), 在函数或者类方法中, globals()
- 返回的模块符号表是其所在模块, 而不是调用模块.
- locals()
- 作用:更新并以字典形式返回当前局部符号表. 自由变量由函数块的 locals() 返回, 而不会由 class 块来返回. 需要注意的是, locals() 字典不应该被修改
- vars()
- 作用:返回
__dict_
_ 属性 - 比如模块、类、实例或者其它带有 dict 属性的 object.
- vars() 使用时如果不传参数, 那么作用与 locals() 一样. 需要注意的是, locals 字典只在读操作时使用, 因为对 locals 的更新会被忽略.
- 作用:返回
注意:
locals 和 vars 需要再解释一下。如果在函数中调用了 locals(),它将使用当前局部变量名称空间(加上任何闭包变量)的值更新 dict,并返回它。在同一栈帧中多次调用 locals(),每次都返回相同的 dict——它作为 f_locals 属性附加到栈帧对象。dict 的内容在每次 locals() 调用和每个 f_locals 属性访问时更新,但仅在此类调用或属性访问时更新。分配变量时,它不会自动更新,在dict 中分配条目不会分配相应的局部变量:
import inspectdef f():x = 1l = locals()print(l) # {'x': 1}locals()print(l) # {'x': 1, 'l': {...}}x = 2print(x, l['x']) # 2 1l['x'] = 3print(x, l['x']) # 2 3inspect.currentframe().f_localsprint(x, l['x']) # 2 2f()
# 输出
'''
{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2
'''
第一次 print(l) 只显示一个“x”条目,因为对l的赋值发生在 locals() 调用之后。再次调用 locals() 后的第二个 print(l) 显示了一个l条目,尽管我们没有保存返回值。第三次和第四次打印显示,赋值变量不会更新l,反之亦然,但在访问 f_locals 后,局部变量会再次复制到 locals() 中。
__import__()
除了 import 语句来导入模块外,还有一个内置的 __import__()
函数,不过这不怎么常用。它还用于动态加载类和函数。
语法如下:
__import__(name,globals=None,locals=None,fromlist=(),level=0) -> module
参数有:
- name:模块的名字(空间)
- globals:全局上下文
- locals:本地上下文
- fromlist:序列,实现类似 from name import (a, b)
- level:用于确定是执行绝对导入还是相对导入:0 是绝对导入,而正数是相对于当前模块要搜索的父目录数
由于此函数是供Python解释器使用的,而不是一般用途,因此最好使用 importlib.import_module()
以编程方式导入模块。
如果仔细阅读,您会感觉到 API 最初是为了允许从模块延迟加载函数。然而,这不是 CPython 的工作方式,我不知道是否有其他 Python 实现能够做到这一点。
相反,CPython 在第一次导入时执行模块名称空间中的所有代码,然后将模块缓存在 sys.modules
中。__import__()
仍然有用。但是,根据文档了解它的功能相当困难。
此函数会由 import 语句发起调用。 它可以被替换 (通过导入 builtins 模块并赋值给 builtins.__import__)
以便修改 import 语句的语义,但是 强烈 不建议这样做,因为使用导入钩子 (参见 PEP 302) 通常更容易实现同样的目标,并且不会导致代码问题,因为许多代码都会假定所用的是默认实现。 同样也不建议直接使用 import() 而应该用 importlib.import_module()
。
本函数会导入模块 name,利用 globals 和 locals 来决定如何在包的上下文中解释该名称。fromlist 给出了应从 name 模块中导入的对象或子模块的名称。标准的实现代码完全不会用到 locals 参数,只用到了 globals 用于确定 import 语句所在的包上下文。
level 指定是使用绝对还是相对导入。 0 (默认值) 意味着仅执行绝对导入。 level 为正数值表示相对于模块调用 __import__()
的目录,将要搜索的父目录层数 (详情参见 PEP 328)。
当 name 变量的形式为 package.module
时,通常将会返回最高层级的包(第一个点号之前的名称),而 不是 以 name 命名的模块。 但是,当给出了非空的 fromlist 参数时,则将返回以 name 命名的模块。
例如,语句 import spam
的结果将为与以下代码作用相同的字节码:
spam = __import__('spam', globals(), locals(), [], 0)
语句 import spam.ham 的结果将为以下调用:
spam = __import__('spam.ham', globals(), locals(), [], 0)
请注意在这里 import() 是如何返回顶层模块的,因为这是通过 import 语句被绑定到特定名称的对象。
另一方面,语句 from spam.ham import eggs, sausage as saus
的结果将为
_temp = __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], 0)
eggs = _temp.eggs
saus = _temp.sausage
在这里, spam.ham
模块会由 __import__()
返回。 要导入的对象将从此对象中提取并赋值给它们对应的名称。
def importer(name, root_package=False, relative_globals=None, level=0):""" We only import modules, functions can be looked up on the module.Usage: from foo.bar import baz>>> baz = importer('foo.bar.baz')import foo.bar.baz>>> foo = importer('foo.bar.baz', root_package=True)>>> foo.bar.bazfrom .. import baz (level = number of dots)>>> baz = importer('baz', relative_globals=globals(), level=2)"""return __import__(name, locals=None, # locals has no useglobals=relative_globals, fromlist=[] if root_package else [None],level=level)baz = importer('foo.bar.baz')
foo = importer('foo.bar.baz', root_package=True)
baz2 = importer('bar.baz', relative_globals=globals(), level=2)assert foo.bar.baz is baz is baz2for name in dir(baz):print(getattr(baz, name))
可以使用 __import__()
更改或拦截导入行为。在这种情况下,让我们只打印它得到的参数,以证明我们正在拦截它:
old_import = __import__def noisy_importer(name, locals, globals, fromlist, level):print(f'name: {name!r}')print(f'fromlist: {fromlist}')print(f'level: {level}')return old_import(name, locals, globals, fromlist, level)import builtins
builtins.__import__ = noisy_importer>>> from os.path import join as opj
name: 'os.path'
fromlist: ('join',)
level: 0
>>> opj
<function join at 0x7fd08d882618>
属性和方法的反射
支持反射的常见方法有下面:
方法 | 用法 |
---|---|
hasattr(obj,name_str) | 判断输入的name_str字符串在对象obj中是否存在(属性或方法),存在返回True,否则返回False。 |
getattr(obj,name_str) | 将按照输入的name_str字符串在对象obj中查找,如找到同名属性,则返回该属性;如找到同名方法,则返回方法的引用;如果未能找到同名的属性或者方法,则抛出异常:AttributeError。 |
setattr(obj,name_str,value) | name_str为属性名或者方法名,value为属性值或者方法的引用。 |
delattr(obj,name_str) | 将你输入的字符串name_str在对象obj中查找,如找到同名属性或者方法就进行删除。 |
获取属性和方法
hasattr(obj, name, /)
参数有:
- obj:要操作的对象,类或者实例
- name:属性名,是一个字符串
判断输入的name字符串在对象object中是否存在(属性或方法),存在返回True,否则返回False。此功能是通过调用 getattr(object, name)
看是否有 AttributeError
异常来实现的。
getattr(object, name[, default]) -> value
参数:
- obj:要操作的对象,类或者实例
- name:属性名
- default: 可选,不存在此属性时返回此值
从对象中获取命名属性值,getattr(x, 'y')
相当于 x.y
操作。当给定默认参数时,当属性不存在时返回;如果没有它,在这种情况下会出现一个例外。
name 必须是字符串。如果该字符串是对象的属性之一,则返回该属性的值。
如果指定的属性不存在,且提供了 default 值,则返回它,否则触发 AttributeError。
getattr()可以返回类、对象、模块的的属性和方法。
反射获取成员方法,返回方法是一个引用地址,要想执行该方法,需要在后面加上小括号
class Person():# 定义类变量Nationality = "China"def __init__(self,name,age,id):self.name = nameself.age = ageself.id = iddef info(self):return (self.Nationality, self.name, self.age, self.id)wang = Person('WangBin', 40, '330103197504013070')
print(wang.name)
print(hasattr(wang, 'name'))
print(hasattr(wang, 'nice'))print(getattr(wang, 'name'))
print(getattr(wang, 'Nationality'))
print(getattr(wang, 'info'))print(getattr(wang, 'info')())‘’'
WangBin
True
False
WangBin
China
<bound method Person.info of <__main__.Person object at 0x10f591e90>>
('China', 'WangBin', 40, '330103197504013070’)
‘''
也可以直接在模块上操作:
#demo6.pyDemo_Value='Demo6'
def foo6(name:str):print('--foo6()--')return 'Hello ' + name#demo5.py
import demo6print(getattr(demo6, 'Demo_Value’))
#Demo6
设置属性和方法
setattr(obj, name, value, /)
参数
- object -- 对象。
- name -- 字符串,对象属性。
- value -- 属性值。
可以使用该方法设置类属性、成员属性和成员方法。
setattr(x, 'y', v)
相当于 x.y = v
操作。
如果对象已经有要设置的属性,则新值进行覆盖。setattr() 法返回值是 None。
设置成员方法时,name为设置加入的方法名,value为要加入方法的引用(不需要加引号)。
class Person():# 定义类变量Nationality = "China"def __init__(self,name,age,id):self.name = nameself.age = ageself.id = iddef info(self):return (self.Nationality, self.name, self.age, self.id)wang = Person('WangBin', 40, '330103197504013070')
print(wang.name)
setattr(wang, 'name', '王彬')
print(wang.name)
setattr(wang, 'nicename', '小王')
print(wang.nicename)def out(self):print(f'{self.name=}, {self.nicename=}')setattr(wang, 'out', out)
#wang.out() #TypeError: out() missing 1 required positional argument: 'self'
wang.out(wang)
#getattr(wang, 'out')()#TypeError: out() missing 1 required positional argument: 'self'
getattr(wang, 'out')(wang)‘’'
WangBin
王彬
小王
self.name='王彬', self.nicename='小王'
self.name='王彬', self.nicename='小王'
‘''
上面的例子可以看到,设置的成员方法调用的时候,要显示的把自己作为第一个参数传入。
setattr()
函数只能用于设置对象的属性或类的属性,而不能用于设置模块的属性或内置类型的属性。此外,如果要设置属性的名称是一个变量,则应该使用setattr()
函数,而不是直接将属性名称作为字符串传递给对象的__setattr__()
方法。
删除属性和方法
delattr(obj, name, /)
参数有:
- obj:要操作的对象,类或者实例
- name:属性名,是一个字符串
将字符串name在对象object中查找,如找到同名属性或者方法就进行删除。如果对象允许,该函数将删除指定的属性。例如 delattr(x, 'foobar')
等价于 del x.foobar
class Person():# 定义类变量Nationality = "China"def __init__(self,name,age,id):self.name = nameself.age = ageself.id = iddef info(self):return (self.Nationality, self.name, self.age, self.id)wang = Person('WangBin', 40, '330103197504013070')
print(wang.name)
delattr(wang, 'name')
print(wang.name) #AttributeError: 'Person' object has no attribute 'name'
动态执行
作为动态语言,python支持动态加载一段字符串代码并执行。
按是否返回结果,简单分为两种:exec和eval。
exec()
exec负责执行字符串代码,可支持多行,可定义变量,但无法返回结果.
def pr(x):print('My result: {}'.format(x))if __name__ == "__main__":s = '''
a = 15
b = 3
if a > b:pr(a+b)
'''exec(s)# My result: 18
eval()
eval可以返回结果,但只能执行单行表达式
def select_max(x, y):return x if x > y else yif __name__ == "__main__":a = 3b = 5c = eval('select_max(a , b)')print("c is {}".format(c))#c is 5
compile()
compile() 函数将指定的源(普通字符串、字节串或 AST 对象)作为代码对象返回。
compile() 方法返回的代码对象,可以使用 exec() 和 eval() 等方法调用,它们将执行动态生成的 Python 代码。
compile(
source,
filename,
mode,
flags=0,
dont_inherit=False,
optimize=-1,
*,
_feature_version=-1,
)
参数:
- source - 源代码可以表示 Python 模块、语句或表达式,包括 string、byte string、AST object
- filename - 从中读取代码的文件。如果它不是从文件中读取的,你可以自己给它起个名字
- mode - 字符串,exec 或 eval 或 single。
- eval - 只接受一个表达式。
- exec - 它可以采用包含Python语句、类和函数等的代码块
- single - 如果它由单个交互语句组成
- flags (可选) - 控制未来哪些语句会影响源代码的编译。默认值:0
- dont_inherit (可选) - 如果为true,则会停止继承代码调用中任何未来有效语句效果的编译
- optimize (可选) - 编译器的优化级别。默认值为-1。
将源代码编译成可由 exec() 或 eval()执行的代码对象。
compile() 将 source 编译成代码或 AST(Abstract Syntax Trees) 对象。代码对象可以被 exec() 或 eval() 执行。source 可以是常规的字符串、字节字符串,或者 AST 对象。
filename 实参需要是代码读取的文件名;如果代码不需要从文件中读取,可以传入一些可辨识的值(经常会使用 '<string>')。
mode 实参指定了编译代码必须用的模式。如果 source 是语句序列,可以是 'exec';如果是单一表达式,可以是 'eval';如果是单个交互式语句,可以是 'single'。(在最后一种情况下,如果表达式执行结果不是 None 将会被打印出来。)
可选参数 flags 和 dont_inherit 控制应当激活哪个 编译器选项 以及应当允许哪个 future 特性。 如果两者都未提供 (或都为零) 则代码会应用与调用 compile() 的代码相同的旗标来编译。 如果给出了 flags 参数而未给出 dont_inherit (或者为零) 则会在无论如何都将被使用的旗标之外还会额外使用 flags 参数所指定的编译器选项和 future 语句。 如果 dont_inherit 为非零整数,则只使用 flags 参数 -- 外围代码中的旗标 (future 特性和编译器选项) 会被忽略。
编译器选项和 future 语句是由比特位来指明的。 比特位可以通过一起按位 OR 来指明多个选项。 指明特定 future 特性所需的比特位可以在 __future__ 模块的 _Feature 实例的 compiler_flag 属性中找到。 编译器旗标 可以在 ast 模块中查找带有 PyCF_ 前缀的名称。
optimize 实参指定编译器的优化级别;默认值 -1 选择与解释器的 -O 选项相同的优化级别。显式级别为 0 (没有优化;__debug__ 为真)、1 (断言被删除, __debug__ 为假)或 2 (文档字符串也被删除)。
如果编译的源码不合法,此函数会触发 SyntaxError 异常;如果源码包含 null 字节,则会触发 ValueError 异常。
在 'single' 或 'eval' 模式编译多行代码字符串时,输入必须以至少一个换行符结尾。 这使 code 模块更容易检测语句的完整性。
codeInString = 'a = 5\nb=6\nsum=a+b\nprint("sum =",sum)'
codeObejct = compile(codeInString, 'sumstring', 'exec')exec(codeObejct)
# sum = 11eval(codeObejct)
# sum = 11
相关文章:
Python 反射和动态执行
反射主要应用于类的对象上,在运行时,将对象中的属性和方法反射出来,通过字符串对对象成员(属性、方法)进行查找、获取、删除、添加成员等动作,是一种基于字符串的事件驱动技术。 python是一门动态语言&…...
计算机网络常见端口号
端口号标识了一个主机上进行通信的不同的应用程序。比如网站服务器80端口一般都是开启的,等你来连接。 端口划分: (1)常用端口,公共端口(保留给公共服务所使用),端口号为0-1023之间…...
SpringBoot / Vue 对SSE的基本使用(简单上手)
一、SSE是什么? SSE技术是基于单工通信模式,只是单纯的客户端向服务端发送请求,服务端不会主动发送给客户端。服务端采取的策略是抓住这个请求不放,等数据更新的时候才返回给客户端,当客户端接收到消息后,…...
Qt串口基本设置与协议收发
前言 1.一直都想要做一个Qt上位机,趁着这个周末有时间,动手写一下 2.comboBox没有点击的信号,所以做了一个触发的功能 3.Qt的数据类型很奇怪,转来转去的我也搞得很迷糊 4.给自己挖个坑,下一期做一个查看波形的上位…...
interview3-微服务与MQ
一、SpringCloud篇 (1)服务注册 常见的注册中心:eureka、nacos、zookeeper eureka做服务注册中心: 服务注册:服务提供者需要把自己的信息注册到eureka,由eureka来保存这些信息,比如服务名称、…...
kafka详解一
kafka详解一 1、消息引擎背景 根据维基百科的定义,消息引擎系统是一组规范。企业利用这组规范在不同系统之间传递语义准确的消息,实现松耦合的异步式数据传递. 即:系统 A 发送消息给消息引擎系统,系统 B 从消息引擎系统中读取 A…...
Flutter yuv 转 rgb
1、引用yuv_converter库 yuv_converter: ^0.0.1 2、导入头文件: import package:yuv_converter/yuv_converter.dart;3、yuv转rgb YuvConverter.yuv420NV21ToRgba8888(yuvRawData, 512, 512) 根据yuv格式选择不同的api。 举个例子: void initState() …...
MySQL——子查询
2023.9.8 相关学习笔记: #子查询 /* 含义: 出现在其他语句中的select语句,称为子查询或内查询 外部的查询语句,称为主查询或外查询分类: 按子查询出现的位置:select后面:仅仅支持标量子查询fro…...
Java学习笔记---多态
面向对象三大特征之一(继承,封装,多态) 多态的应用场景:根据传递对象的不同,调用不同的show方法 一、多态的定义 同类型的对象,表现出的不同形态(对象的多种形态) 二…...
2023-09-10 LeetCode每日一题(课程表 II)
2023-09-10每日一题 一、题目编号 210. 课程表 II二、题目链接 点击跳转到题目位置 三、题目描述 现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] [ai, bi] ,表示在…...
合并区间【贪心算法】
合并区间 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 class Solution {public int[][] merge(int[…...
2023,软件测试人的未来在哪里?
2023年,IT行业出现空前的萧条,首先是年初一开始各大厂像着了魔似的不约而同的纷纷裁员、降薪、奖金包缩水,随之而来的是需求萎缩,HC减少或封锁等等。 而有幸未被列入裁员名单的在职人员,庆幸之余也心有余悸࿰…...
Python中的Numpy向量计算(R与Python系列第三篇)
目录 一、什么是Numpy? 二、如何导入NumPy? 三、生成NumPy数组 3.1利用序列生成 3.2使用特定函数生成NumPy数组 (1)使用np.arange() (2)使用np.linspace() 四、NumPy数组的其他常用函数 (1)np.z…...
LeetCode刷题笔记【27】:贪心算法专题-5(无重叠区间、划分字母区间、合并区间)
文章目录 前置知识435. 无重叠区间题目描述参考<452. 用最少数量的箭引爆气球>, 间接求解直接求"重叠区间数量" 763.划分字母区间题目描述贪心 - 建立"最后一个当前字母"数组优化marker创建的过程 56. 合并区间题目描述解题思路代码① 如果有重合就合…...
nvidia-smi 命令详解
nvidia-smi 命令详解 1. nvidia-smi 面板解析2. 显存与GPU的区别 Reference: nvidia-smi命令详解 相关文章: nvidia-smi nvcc -V 及 CUDA、cuDNN 安装 nvidia-smi(NVIDIA System Management Interface) 是一种命令行实用程序,用于监控和管理 NVIDIA G…...
fork()函数的返回值
在程序中,int pd fork() 是一个典型的 fork() 调用。fork() 函数会创建一个新的进程,然后在父进程中返回子进程的进程ID(PID),在子进程中返回0。所以 pd 的值会根据当前进程是父进程还是子进程而有所不同:…...
Stable Diffusion WebUI挂VPN不能跑图解决办法(Windows)
如何解决SD在打开VPN的状态不能运行的问题 在我们开VPN的时候会出现无法生成图片,也无法做其他任何事,这个时候是不是很着急呢? 别急,我这里会说明如何解决。 就像这样,运行半天生成不了图,有时还会出现…...
Android的本地数据
何为本地,即写完之后除非手动修改,否像嘎了一样在那固定死了 有些需求可能也会要求我们去写死数据,因为这需求是一成不变的,那么你通常会用什么方法写死呢? 1. 本地存储-SharedPreferences 此方法可以长时间保存于手…...
android NDK 开发包,网盘下载,不限速
记录下ndk 开发包的地址,分享给大家。 另外有Android studio的下载包, 在另一篇文章 链接:http://t.csdn.cn/JSr9x Android Studio.exe 下载 2023 最新更新,网盘下载_hsj-obj的博客-CSDN博客 主要是19-25,其他的没有…...
【每日一题Day320】LC2651计算列车到站时间 | 数学
计算列车到站时间【LC2651】](https://leetcode.cn/problems/calculate-delayed-arrival-time/) 给你一个正整数 arrivalTime 表示列车正点到站的时间(单位:小时),另给你一个正整数 delayedTime 表示列车延误的小时数。 返回列车实…...
C语言柔性数组详解:让你的程序更灵活
柔性数组 一、前言二、柔性数组的用法三、柔性数组的内存分布四、柔性数组的优势五、总结 一、前言 仔细观察下面的代码,有没有看出哪里不对劲? struct S {int i;double d;char c;int arr[]; };还有另外一种写法: struct S {int i;double …...
Redis-带你深入学习数据类型list
目录 1、list列表 2、list相关命令 2.1、添加相关命令:rpush、lpush、linsert 2.2、查找相关命令:lrange、lindex、llen 2.3、删除相关命令:lpop、rpop、lrem、ltrim 2.4、修改相关命令:lset 2.5、阻塞相关命令:…...
react拖拽依赖库react-dnd
注:对于表格自定义行可以拖拽和树自定义节点可以拖拽等比较适用,其余的拖拽处理可以使用dragstart,drop等js原生事件来实现 react-dnd使用方法很简单,直接上干货 第一步安装依赖并引入 import { DndProvider } from react-dnd;…...
win10环境安装使用docker-maxwell
目的:maxwell可以监控mysql数据变化,并同步到kafka、mq或tcp等。 maxwell和canal区别: maxwell更轻量,canal把表结构也输出了 docker bootstrap可导出历史数据,canal不能 环境 :win10,mysql5…...
Docker部署RabbitMQ
Docker部署RabbitMQ 介绍 RabbitMQ是一个开源的消息队列系统,它被设计用于在应用程序之间传递消息。它采用了AMQP(高级消息队列协议)作为底层通信协议,这使得它能够在不同的应用程序之间进行可靠的消息传递。 那么,…...
23个react常见问题
1、setState 是异步还是同步? 合成事件中是异步 钩子函数中的是异步 原生事件中是同步 setTimeout中是同步 相关链接:你真的理解setState吗?: 2、聊聊 react16.4 的生命周期 图片 相关连接:React 生命周期 我对 Reac…...
【python基础】——Anaconda下包更新的坑及安装与卸载、及安装后Jupyter Notebook没反应的解决方法
文章目录 前言一、起因:如何一步步走到卸载重装anaconda?二、卸载anaconda二、重新安装anaconda三、关于安装Anaconda后,打开Jupyter Notebook运行代码没反应且in[ ]没有*前言 本文主要用来记录自己近期踩坑的一些复盘。其中坑有: ‘.supxlabel’ 不起作用的解决pip list 与…...
CSS 中的 display 和 visibility
CSS 中的 display 和 visibility 都可以设置一个元素在浏览器中的显示或隐藏效果。 display: 隐藏某个元素时,不会占用任何空间。换句话讲,不会影响布局。visibility: 隐藏某个元素时,仍需占用与未隐藏之前一样的空间。换句话讲,…...
解决mysql报错this is incompatible with DISTINCT
环境 centos 9 php7.4 mysql5.7 问题 mysql查询报如下错误: SQLSTATE[HY000]: General error: 3065 Expression #1 of ORDER BY clause is not in SELECT list, references column hst_csc.q.timestamp which is not in SELECT list; this is incompatible with…...
C++-map和set
本期我们来学习map和set 目录 关联式容器 键值对 pair 树形结构的关联式容器 set multiset map multimap 关联式容器 我们已经接触过 STL 中的部分容器,比如: vector 、 list 、 deque 、forward_list(C11)等,这些容器统称为序列式…...
网站模板间距/西安seo
今天是Python专题的第12篇文章,我们来看看Python装饰器。一段囧事差不多五年前面试的时候,我就领教过它的重要性。那时候我Python刚刚初学乍练,看完了廖雪峰大神的博客,就去面试了。我应聘的并不是一个Python的开发岗位࿰…...
建设人才信息网是什么网站/南宁网站公司
文章目录1.1 为什么要过渡到IPv6原因1:IPv4地址耗尽原因2:让只使用IPv6的客户访问原因3:提升性能原因4:加固当前的网络。1.2 IPv6的历史1.3 IPv6的优点1.极大扩展的地址空间:2.无状态自动配置3.消除了NAT/PAT(网络地址…...
网站建设需要找工信部吗/网站建设制作
2019独角兽企业重金招聘Python工程师标准>>> 我们经常会看到有些系统,为了提高账户安全性,会在用户输入n次密码时候锁定对应的账户一段时间,这样可以避免暴力破解用户密码(说实话这样行不行我也不知道)。不…...
网站首页权重低/网店运营教学
BIM建模可以说是BIM工程师的基础,但是BIM建模工作贯穿于建筑工程全生命周期,为了满足设计需求,也会不断提高BIM建模的精度。那么bim如何导入CAD图建模1、项目中CAD图纸的载入和导入,载入和导入的区别,简单的来说就是载入可以用简单…...
建立学校网站/2023年最新时政热点
在ASP.NET MVC Web中,HttpResponseMessage作为一个返回类型,能将状态码与数据以Json的格式一并返回给客户端,但是在ASP.NET Core Web中,貌似有些小问题。我在做接口测试时,总是得到如下返回结果(可能格式与…...
网站建设需求文档模板/谷歌广告开户
额定电流10A 利用深圳铂科的软件辅助设计。 如下图,用磁环NPF226090,单股绕线直径2mm,匝数56匝,10安培时的感量下降到1.022毫哼,符合基本要求。 回头申请样品绕制,实验,在此先记录一下。...