guxh的python笔记:面向对象之属性

1,类的私有属性

class Foo:
    
    def __init__(self, x):
        self.x = x

类的属性在实例化之后是可以更改的:

f = Foo(1)
print(f.x)   # 1
f.x = 2
print(f.x)   # 2

如果想禁止访问属性,即让属性私有,可以用“双下划线” 或者“单下划线”:

class Foo:

    def __init__(self, x, y):
        self._x = x
        self.__y = y

    def __repr__(self):
        return 'f._x = {}, f.__y = {}'.format(self._x, self.__y)

区别是“双下划线”解释器会对属性就行“名称更改”,而“单下划线”不会有更改,只是约定成俗。

但是知道规则还是可以轻松访问:

f = Foo(1, 1)
f._x = 2
f._Foo__y = 2
print(f)   # f._x = 2, f.__y = 2

所以如果只是为了属性私有,用“单下划线”和“双下划线”没有什么区别。

但“双下划线”在继承时可以避免基类属性被子类的属性覆盖。

2,属性只读(私有 + property)

私有属性 + property可以让属性变的只读:

class Foo:

    def __init__(self, x):
        self._x = x
    
    @property
    def x(self):
        return self._x

此时对Foo进行实例化后,可以访问对象的属性x,但无法给x赋值:

f = Foo(1)
print(f.x)  # 1
f.x = 2   # AttributeError: can't set attribute

因为实例化时的x存在私有属性self._x中,当然可以用1中提到的访问私有属性的方法去修改,但这被认为是粗略的行为:

f = Foo(1)
f._x= 2
print(f.x)  # 2

3,属性管理(init)

4,属性管理(property)

对属性的操作有:get,set,del。

property只是完成了get操作,配套的get / del分配由setter / delettr完成,组合起来就可以实现对属性的管理:

class Foo:

    def __init__(self, x):
        self.x = x

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, val):
        if val < 0:
            raise ValueError('x must be >= 0')
        self._x = val

    @x.deleter
    def x(self):
        pass

再看看对x属性的访问情况:

f = Foo(1)
print(f.x)  # 1
f.x = 2
print(f.x)  # 2
f = Foo(-1)  # ValueError: x must be >= 0
f.x = -1  # ValueError: x must be >= 0

 如果__init__中使用self._x = x会出现什么后果?

class Foo:

    def __init__(self, x):
        self._x = x
    ......

f = Foo(-1)
print(c.x)   #  -1
f.x = -1   # ValueError: x must be >= 0

self.x = x在实例化时会触发set,而self._x = x在实例化时绕过了set,也就是不会对实例化时的参数做检查。

另外,del可以不定义,del f.x会触发AttributeError: can't delete attribute,这里pass演示,del f.x没什么效果。

5,属性管理(描述符)

6,动态存取属性

getattr,setattr,delattr,hasattr

猜你喜欢

转载自www.cnblogs.com/guxh/p/10236035.html