话不多说,开始
1、hasattr函数
判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
语法:hasattr(object, name)
class A:
name = "demo"
def show(self):
pass
t = A()
res = hasattr(t, "name")
print(res) # True
res = hasattr(t, "show")
print(res) # True
2、getattr函数
获取对象object的属性或者方法,如果存在打印出来,如果不存在,返回默认值,默认值可选。
需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,可以通过在后面添加一对括号的方式直接运行
语法:getattr(object, name[,default]) 小提示:[]代表可选的意思,这个写法是通用的
class A:
name = "demo"
def show(self):
print("run...")
t = A()
res = getattr(t, "name")
print(res) # demo
res = getattr(t, "show")
print(res) # <bound method A.show of <__main__.A object at 0x00651350>>
res() # run...
print(getattr(t, "age", 18)) # 不存在,输出默认值18,如果不设置默认值则会报错
3、setattr函数
给对象的属性赋值,若属性不存在,先创建再赋值。
语法:setattr(object, name, values)
class A:
name = "demo"
def show(self):
print("run...")
t = A()
res = hasattr(t, "age")
print(res) # False
setattr(t, "age", 18)
print(hasattr(t, "age")) # True
setattr、getattr、hasattr这三个函数结合使用可以实现反射操作,准备在python技巧篇说
4、__setattr__函数
拦截所有属性的的赋值语句
如果定义了这个方法,self.arrt = value 就会变成self,__setattr__("attr", value)
需要注意。当在__setattr__方法内对属性进行赋值时,不可使用self.attr = value,因为他会再次调用self,__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value.
class A(dict):
def __setattr__(self, key, value):
self[key] = value
# 不要写 self.key = value,会超出最大递归深度,最后抛出堆栈溢出异常
# maximum recursion depth exceeded while calling a Python object
a = A()
a.name = "xiaoming"
print(a['name']) # xiaoming
5、__getattr__函数
动态返回一个属性
当调用不存在的属性时,Python会试图调用__getattr__(self,'key')来获取属性,并且返回key
示例
class A:
def __getattr__(self, item):
if item == "name":
return "xiaoming"
else:
raise AttributeError
a = A()
print(a.name) # xiaoming
print(a.age) # 抛出AttributeError异常
6、__call__函数
可调用对象(callable),但凡可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable。如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象。这个魔法方法可以让类的实例行为表现的像函数一样
示例
class Entity:
def __init__(self, size, x, y):
self.x, self.y = x, y
self.size = size
def __call__(self, x, y):
'''改变实体的位置'''
self.x, self.y = y, x
print(self.x) # 5
print(self.y) # 4
e = Entity(1, 2, 3)
e(4,5) # 实例可以象函数那样执行,并传入x y值,修改对象的x y
7、globals与locals
这两个函数提供了基于字典的访问局部和全局变量的方式。
python中使用名字空间来记录变量的轨迹,它是一个字典,key为变量名,value为变量值
每个函数都有自己的名字空间,叫做局部名字空间。记录着参数(PS:参数会变成本地变量),变量,局部变量。
每个模块有自己的名字空间,叫做全局名字空间,记录着模块的变量,函数、类、模块级的变量和常量
还有就是内置名字空间,任何模块均可访问它,它存放着内置的函数和异常(这就是为什么我们可以直接使用,因为内置空间是python自动开辟的)
当一行代码使用变量x时,Python会到所有可用的名字空间去查找变量,按照如下顺序:
1.局部名字空间 - 特指当前函数或类的方法。如果函数定义了一个局部变量 x,Python将使用这个变量,然后停止搜索局部名字空间 - 特指当前函数或类的方法。
2.全局名字空间 - 特指当前的模块。如果模块定义了一个名为 x 的变量,函数或类,Python将使用这个变量然后停止搜索
3.内置名字空间 - 对每个模块都是全局的。作为最后的尝试,Python将假设 x 是内置函数或变量
局部名字空间可以通过内置的 locals 函数来访问。全局 (模块级别) 名字空间可以通过内置的 globals 函数来访问。
locals 对局部 (函数) 名字空间做了些什么,globals 就对全局 (模块) 名字空间做了什么
并且globals的能力更强 ,因为一个模块的名字空间包含了模块级的变量和常量,它还包括了所有在模块中定义的函数和类,以及任何被导入到模块中的东西
使用 import module,模块自身被导入,但是它保持着自已的名字空间,
这就是为什么我们需要使用模块名来访问它的函数或属性: module.function 的原因。
但是使用 from module import,实际上是从另一个模块中将指定的函数和属性导入到我们自己的名字空间,
所以我们可以直接访问它们却不需要引用它们所来源的模块。
locals()实例:
def foo(arg, a):
x = 100
y = 'hello python!'
for i in range(10):
j = 1
k = i
print(locals())
foo(1,2) # {'k': 9, 'j': 1, 'i': 9, 'y': 'hello python!', 'x': 100, 'a': 2, 'arg': 1}
locals 是只读的,不可修改, 而globals可以修改,原因是:
locals()实际上没有返回局部名字空间,它返回的是一个拷贝。所以对它进行修改,修改的是拷贝,而对实际的局部名字空间中的变量值并无影响。
globals()返回的是实际的全局名字空间,而不是一个拷贝: 与 locals 的行为完全相反。
所以对 globals 所返回的 dictionary 的任何的改动都会直接影响到全局变量的取值
global示例:
a = 3
def demo():
global a
a = 4
demo()
print(a) # 4
globals()['a'] = 5
print(a) # 5
如果本篇文章对你有帮助,可否在文章右侧点个赞再走呢~~
本文为原创,转载请注明出处