深圳专业建站公司有哪些,天门建设局官方网站,游戏源码搭建,个人网上卖货的平台反射主要应用于类的对象上#xff0c;在运行时#xff0c;将对象中的属性和方法反射出来#xff0c;通过字符串对对象成员#xff08;属性、方法#xff09;进行查找、获取、删除、添加成员等动作#xff0c;是一种基于字符串的事件驱动技术。
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_ValueDemo6
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()-当前作用域全局变量可以更新dictlocals()-当前作用域的局部变量不应该被修改dictvars([object])对象属性同 object.__dict__同 locals()可以更新dictdir([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,globalsNone,localsNone,fromlist(),level0) - 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_packageFalse, relative_globalsNone, level0): 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_packageTrue) foo.bar.bazfrom .. import baz (level number of dots) baz importer(baz, relative_globalsglobals(), level2)return __import__(name, localsNone, # locals has no useglobalsrelative_globals, fromlist[] if root_package else [None],levellevel)baz importer(foo.bar.baz)
foo importer(foo.bar.baz, root_packageTrue)
baz2 importer(bar.baz, relative_globalsglobals(), level2)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(fname: {name!r})print(ffromlist: {fromlist})print(flevel: {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: 0opj
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 Chinadef __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_ValueDemo6
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 Chinadef __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 Chinadef __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(ab)
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, flags0, dont_inheritFalse, optimize-1, *, _feature_version-1, )
参数
source - 源代码可以表示 Python 模块、语句或表达式包括 string、byte string、AST objectfilename - 从中读取代码的文件。如果它不是从文件中读取的你可以自己给它起个名字mode - 字符串exec 或 eval 或 single。 eval - 只接受一个表达式。exec - 它可以采用包含Python语句、类和函数等的代码块single - 如果它由单个交互语句组成flags (可选) - 控制未来哪些语句会影响源代码的编译。默认值0dont_inherit (可选) - 如果为true则会停止继承代码调用中任何未来有效语句效果的编译optimize (可选) - 编译器的优化级别。默认值为-1。
将源代码编译成可由 exec() 或 eval()执行的代码对象。
compile() 将 source 编译成代码或 ASTAbstract 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\nb6\nsumab\nprint(sum ,sum)
codeObejct compile(codeInString, sumstring, exec)exec(codeObejct)
# sum 11eval(codeObejct)
# sum 11