内置方法
isinstance(obj,cls) 和 issubclass(sub,super)
- isinstance:判断obj是否是cls的对象
- issubclass:判断sub是否是super的子类
class A:
pass
class B:
pass
class C(A, B):
pass
a = A()
b = B()
c = C()
print(isinstance(a, A))
print(isinstance(b, B))
print(isinstance(c, C))
print(isinstance(1, int))
print(issubclass(C, (A, B)))
反射
- 什么是反射:根据字符串映射对象中的属性或方法
- hasattr(obj, 'name'):判断obj对象中是否有一个name字符串对应的属性或方法
- getattr(obj, 'name', default):检测对象中是否有name字符串的属性或者方法。属性存在就直接返回属性的值,方法存在则返回该方法的内存地址,加括号可调用。不存在如果没设置默认值。则报错,否则返回设置的默认值。
- setattr(obj, key, value):设置obj.key = value
- delattr(obj,'name'):删除对象中的name字符串的属性或方法。不存在则报错。
- 简单使用示例
# 定义:通过字符串映射到对象属性和方法
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
return '%s 在说话' % self.name
obj = People('egon', 18)
print('obj是否有name属性:', hasattr(obj, 'name'))
print('obj是否有talk方法:', hasattr(obj, 'talk'))
print('不存在给出默认值:', getattr(obj, 'namexxx', 'default'))
print('存在返回方法的内存地址:', getattr(obj, 'talk', None))
print('调用该方法:', getattr(obj, 'talk', None)())
print('映射属性:', getattr(obj, 'name'))
print('设置obj.ex = male:', setattr(obj, 'sex', 'male'))
print('查看是否设置成功:', obj.sex)
print('删除obj中的age属性:', delattr(obj, 'age'))
print('查看对象的名称空间,是否删除成功:', obj.__dict__)
import sys
test = '查看模块是否有某个属性'
def func():
return '查看模块是否有某个方法'
class s1:
pass
this = sys.modules[__name__]
print(hasattr(this, 's1'))
print(hasattr(this, 'test'))
print(getattr(this, 'test'))
print(getattr(this, 'func')())
__setattr__、__getattr__、__delattr__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __setattr__(self, key, value):
"""
给对象赋值时,触发此函数
:param key:
:param value:
:return:
"""
print(key, value)
# 误区:self.key = value 这样会造成无限递归。仔细想想。
self.__dict__[key] = value
def __getattr__(self, item):
"""
查找属性不存在的值的时候才会触发此函数
:param item:
:return:
"""
return '你查找的属性:%s 不存在' % item
def __delattr__(self, item):
"""
删除属性时触发此函数
:param item:
:return:
"""
self.__dict__.pop(item, None)
p = Person('江子牙', 22)
#########__setattr__#########
p.sex = '男'
print('执行__setattr__:', p.__dict__)
#########__getattr__#########
sex = p.sex
print('不会触发__getattr__:', sex)
print('原本对象查找不存在的值会报错,但是重写了__getattr__,所以不会报错:', p.weight)
#########__delattr__#########
del p.se
print('执行__delattr__:', p.__dict__)
__getattribute__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattribute__(self, item):
"""
获取属性的时候触发此函数,但是不管属性存不存在,都会执行它
:param item:
:return:
"""
print('执行__getattribute__:', item)
# 两者同时存在,则不会执行__getattr__。除非它抛出异常:raise AttributeError
# raise AttributeError
return item
def __getattr__(self, item):
"""
获取不存在的属性的时候触发此函数
:param item:
:return:
"""
print('执行__getattr__', item)
return item
p = Person('江子牙', 21)
print(p.name)
描述符
- 描述符(
__get__、__set__、__del__
)是什么:本质就是一个新式类。
__str__、__repr__
__str__
:函数或者printh函数-->obj.str()
__repr__
:交互式解释器-->obj.repr()
- 注意:这两个是双胞胎,没有定义__str__才使用__repr__。两者必须都返回字符串,否则抛出异常。
slots
- slots:是一个类变量,变量值可以是列表、元祖、字典或者可迭代对象。也可以是一个字符串。(意味着所有实例只有一个数据属性)
- 访问属性,本是用__dict__.(类的字典是共享的,实例的属性是独立的)
- 为什么要用它:字典会占用大量的内存,如果你有一个属性很少的类。但是有很多实例,为了节省内存可以用__slots__来取代__dict__。
- 缺点:一旦使用__slots__之后,就不能再给实例添加新的属性,只能用__slots__定义的那些属性名。也不支持多继承的特性。
class Bar:
__slots__ = ['name', 'age']
b1 = Bar()
b2 = Bar()
b1.name = '江子牙'
b2.name = '王青'
print(b1.__slots__)
print(b2.__slots__)
# b1.sex = '男' 报错,不能添加新的属性
# print(b1.__dict__) 不再有__dict__了,统一归slots管理,节省内存
__next__、 __iter__
实现迭代器协议
class Foo:
"""
实现range(start,end)不加步长
"""
def __init__(self, start, end, ):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
n = self.start
if n > self.end - 1:
raise StopIteration
self.start += 1
return n
f = Foo(1, 4)
for i in f:
print(i)
class Foo:
"""
实现range(start,end,step)加步长
"""
def __init__(self, start, end, step=None):
self.start = start
self.end = end
self.step = step
def __iter__(self):
return self
def __next__(self):
n = self.start
if n > self.end - 1:
raise StopIteration
if self.step:
self.start += self.step
else:
self.start += 1
return n
f = Foo(1, 10)
for i in f:
print(i)
__doc__
class A:
"""
呵呵,用于描述
"""
pass
print(A.__doc__)
__module__、__class__
__module__
:表示当前操作的对象在哪个模块
__class__
:表示当前操作的对象的类是什么
class A:
"""
呵呵,用于描述
"""
pass
a = A()
print(a.__module__)
print(a.__class__)
__del__
# 代码执行完成之后,就会触发__del__
class A:
def __init__(self, name):
self.name = name
def __del__(self):
print('对象的属性%s还在' % self.name)
print('这里是析构方法')
print('即将删除')
a = A('jw')
print('----------')
# print(a.name)
- 应用场景:当程序结束时。只会回收自己内存空间。即用户态内存。而操作系统的资源没有被回收,这就需要__del__。
__call__
- 对象后面加括号,触发执行
- 说明:构造方法的执行是由创建对象触发的,即:对象 = 类()。而对于
__call__
的执行是由对象加括号触发的。即对象.() or 类()()
class A:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('对象()')
a = A()
a()
A()()