Python----类的方法(二)

通过字典的方式操纵类的属性:item系列方法

以点的方式操作属性,和attr有关。字典操纵属性,和item有关

和操作属性一样,如果不往字典里面写入是不会有相应的方法或属性的。添加一个属性:

class Test:
    def __setitem__(self, key, value):
        print('setitem')
        self.__dict__[key] = value

t = Test()
print(t.__dict__)
t['name'] = 'Jax'
print(t.__dict__)


>>> {}
>>> setitem
>>> {'name': 'Jax'}

获取一个属性:

class Test:
    def __getitem__(self, item):
        print('getitem')
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        print('setitem')
        self.__dict__[key] = value


t = Test()

t['name'] = 'Jax'
print(t['name'])


>>> setitem
>>> getitem
>>> Jax
>>> None

删除一个属性

class Test:
    def __setitem__(self, key, value):
        print('setitem')
        self.__dict__[key] = value

    def __delitem__(self, key):
        print('delitem')
        self.__dict__.pop(key)


t = Test()
t['name'] = 'Jax'
print(t.__dict__)
del t['name']
print(t.__dict__)

>>> setitem
>>> {'name': 'Jax'}
>>> delitem
>>> {}

__str__和__repr__方法:

1、两者的返回值都必须是字符串。

2、str函数和print函数触发__str__, repr函数或者交互式解释器触发__repr__()

3、__str__里面必须return一个值。打印一个实例对象(x)时,首先执行str(x)---->x.__str__() 如果再找不到就去找__repr__()

4、__repr__里面必须return一个值,在解释器里面有用 ,打印实例时触发,控制输出, 。两者共存时打印实例对象会显示__str__()

class Test:
    def __str__(self):
        return 'I am str'

    def __repr__(self):
        return 'I am repr'

t = Test()
print(t)


>>> I am str

format函数打印属性值

class Test:
    def __init__(self, name, value):
        self.name = name
        self.value = value

t = Test('Jax', 15)

print('{0.name}{0.value}'.format(t))

>>> Jax15

__slot__变量:

是一个类变量,变量值可以是列表、可迭代对象。如果一个属性很少的类有很多实例,就用__slots__节省内存。

但是用__slots__以后就不能再给实例对象添加新的属性。加上__slots__的类无法在支持一些类的特性,例如多继承。也无法进行赋值因为打不开__dict__
由__slots__创建的类不再具有__dict__的属性

class Test:
    __slots__ = ['name','gender']

t =Test()
t.name = 15
t.gender = 'Male'

print(t.__slots__)

__del__:

析构方法:只有当释放掉对象或内存时才会被触发,当python文件运行结束时也会释放掉空间,触发析构方法

class Test:
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('I an running')



t = Test('Jax')
del t.name   # 删掉的是一个属性所以不会触发析构方法
print('--------------')


>>> --------------
>>> I an running

删除实例对象,触发析构方法

class Test:
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('I an running')



t = Test('Jax')
del t    # 删掉的是对象所以触发析构方法
print('--------------')


>>> I an running
>>> --------------

__call__方法:

对象后面加括号,触发执行。是调用类的__call__方法,*args是初始化传递的参数,**kwargs是初始化传递的位置参数

class Test:
    def __call__(self, *args, **kwargs):
        print('running')


t = Test()
t()


>>> running

t()----->调用的是类的__call__方法,Test()---->调用的__call__方法,返回的只是一个类的地址而已

描述符:

在描述符协议中,它可以通过方法重写属性的访问。这些方法有 __get__(), __set__(), 和__delete__()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。

只要和x有关的操作不会写入到t的字典中,用foo来描述x属性,x被foo代理了。

class Foo:
    def __get__(self, instance, owner):
        print('get method')
        print(instance)
        print(owner)  # 来自哪个类

    def __set__(self, instance, value):
        print('set method')
        print(instance)  # 实例的对象
        print(value)   #  值

    def __delete__(self, instance):
        print('delete method')
        print(instance)


class Test:
    x = Foo()  # 用foo来描述x属性,x被foo代理了

    def __init__(self, x):
        self.x = x   # 触发了set函数,如果换成self.m就不会触发


t = Test(15)
print(Test.x)  # 触发了get函数


>>> set method
>>> get method

优先级:1、类属性高于数据描述符,把原来的覆盖掉了

class Foo:
    def __get__(self, instance, owner):
        print('get method')

class Test:
    x = Foo() 


Test.x = 15
print(Test.x)  # 类的属性优先级高


>>> 15

2、数据描述符高于实例属性,因为当实例对象找不到属性,会去类的属性里面找,类属性里面该属性是个描述符,所以描述符高于实例

class Foo:
    def __get__(self, instance, owner):
        print('get method')


class Test:
    x = Foo()


t = Test()
print(t.x)


>>> get method

4、非数据描述符  因为找不到描述符所以只好赋值,就是调用其他属性(叫做非数据描述符)

class Foo:
    def __get__(self, instance, owner):
        print('get method')

    def __set__(self, instance, value):
        print('set method')


class Test:
    x = Foo()  # 用foo来描述x属性,x被foo代理了


t = Test()
t.m = 15
print(t.m)


>>> 15

5、找不到属性就只能触发__getattr__()方法

总结优先级:类的属性 > 数据描述符 > 实例的属性 > 非数据描述符 > __getattr__()

猜你喜欢

转载自blog.csdn.net/weixin_41678001/article/details/82697918