010---内置方法

内置方法

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')())
  • 为什么要使用反射?
    • 实现可插机制
    • 动态导入模块
    import importlib
    module1 = 'a'
    # from test import module1
    #用上面的方法导入包会报错,因为import module1不会自动解析成import test;那如何才能import字符串格式的模块名呢?这就是下面动态导入的方法。
    
    module = 'test.a'
    aa = importlib.import_module(module)
    print(aa.C().name)
    #这样就导入了lib包下的aa模块,直接用aa.C()创建一个类C的对象。
    #动态导入模块的作用:根据用户输入的或者从其他地方获取到的字符串来导入需要的模块。
    

__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__

  • __getattr__比较
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()()
posted @ 2019-01-26 21:03  爬呀爬Xjm  阅读(147)  评论(0编辑  收藏  举报