一、相关属性知识

1.__bases__: 元组,元素是继承的类

①含义:类名.__bases__ 可以得到这个类的父类是谁

②输出结果:父类作为元素存放在元组中(该类继承了哪些父类)

# __bases__: 元组,元素是继承的类
class A(object):
    pass
class B(object):
    pass

class MyClass(object):
    pass
if __name__ == '__main__':
    print(MyClass.__bases__)  # (<class 'object'>,)

注意,继承object是默认继承,如果要继承非object时,要省略object,否则会报错。

class A(object):
    pass
class B(object):
    pass

class MyClass(A, B):  # 这里要省略object
    pass
if __name__ == '__main__':
    print(MyClass.__bases__)  # (<class '__main__.A'>, <class '__main__.B'>)

 

2.实例属性管理器/类的静态函数、类函数、、、管理器:__dict__:

①定义:在__init__中声明的实例变量,会存到实例的__dict__中

 类和实例分别拥有自己的__dict__:

      --类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的

      --对象的属性(__init__里的实例变量)放在对象.__dict__里

class MyClass(object): # 定义如果创建对象的一段代码

    #类变量 归属于类
    count= 1

    def __init__(self, name,  age):
        num = 1  # 局部变量 (不在对象__dict__中)
        self.name = name
        self.age = age  # name,age是实例属性,归属于对象

if __name__ == '__main__':
    a = MyClass("zhangsan", 12)
    # 对象的__dict__
    print(a.__dict__)  #  {'name': 'zhangsan', 'age': 12}
    # 类的__dict__
    print(MyClass.__dict__)  #  {'__module__': '__main__', 'count': 1, '__init__': <function MyClass.__init__ at 0x000001C723C57168>,

 

3.__getattr__:  执行调用对象的属性,而对象无此属性时,会调用__getattr__方法。

当我们访问一个不存在的属性的时候,会抛出异常,提示我们不存在这个属性。而这个异常就是__getattr__方法抛出的,其原因在于他是访问一个不存在的属性的最后落脚点,作为异常抛出的地方提示出错再适合不过了。

# __getattr__方法
class Myclass(object):
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        return 1
if __name__ == '__main__':
    A = Myclass("zhangsan")
    print(A.value) # 1     对象A并没有value属性,但是输出的是__getattr__的返回值

不重写__getattr__方法,对象没有X属性而调用X属性时,会报系统内置的属性错误信息。

class Myclass(object):
    def __init__(self,name):
        self.name = name

    # def __getattr__(self, item):
    #     return 1
if __name__ == '__main__':
    A = Myclass("zhangsan")
    print(A.value)  # AttributeError: 'Myclass' object has no attribute 'value'

也可以自定义报错信息,重写__getattr__方法。如下:

__getattr__内置方法,没有属性时的异常抛出的大概设计思路。

#自定义获取对象属性的报错信息
class MyAttributionError(Exception):
    def __init__(self,msg = "属性不存在"):
        super().__init__(self)
        self.msg = msg

    def __str__(self):
        return self.msg

class Myclass(object):
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        raise MyAttributionError

if __name__ == '__main__':
    A = Myclass("zhangsan")
    print(A.value)
"""
    raise MyAttributionError
__main__.MyAttributionError: 属性不存在
"""

 

4.__setattr__:用于设置属性值,该属性不一定是存在的

①在对一个属性设置值的时候,会调用到这个函数,每个设置值的方式都会进入这个方法

②用于类实例进行属性赋值,其定义在Object类【1】中,官方提供的说明如下:

Called when an attribute assignment is attempted. 
This is called instead of the normal mechanism (i.e. store the value in the instance dictionary).
 name is the attribute name, value is the value to be assigned to it.

简单的说,__setattr__()在属性赋值时被调用,并且将值存储到实例字典中,这个字典应该是self的__dict__属性。即:在类实例的每个属性进行赋值时,都会首先调用__setattr__()方法,并在__setattr__()方法中将属性名和属性值添加到类实例的__dict__属性中。

举例:

"""__setattr__"""


class MyClass:
    def __init__(self, name, age):
        pass

    def __setattr__(self, key, value):
        print("setattr is running...")
        super().__setattr__(key, value)


if __name__ == '__main__':
    obj = MyClass("zhangsan", 19)
    obj.name = "li"  # 只要操作:设置对象属性的行为,就会进入__setattr__方法中
"""
output:
setattr is running...
"""

应用举例:

class MyClass:
    def __init__(self, name, age):
        pass

    def __setattr__(self, key, value):
        print("setattr is running...")
        super().__setattr__(key, value)


if __name__ == '__main__':
    obj = MyClass("zhangsan", 19)
    if hasattr(obj, "gender"):
        print(getattr(obj, "gender"))
    else:
        setattr(obj, "gender", "male")
    print(obj.__dict__)  # {'gender': 'male'}

"""
setattr is running...
{'gender': 'male'}
"""

总结:python的实例属性的定义、获取和管理可以通过__setattr__()和__dict__配合进行,__setattr__()方法在类的属性赋值时被调用,并通常需要把属性名和属性值存储到self的__dict__字典中。

③应用:(如上例子)

一般先判断对象中是否存在某属性,如果存在则返回;如果不存在,则给对象增加属性并赋值;很简单的if-else判断

 

5.delattr: 删除属性

①语法:delattr(object, name)   ----name表示对象的属性

②参数

  • object -- 对象。
  • name -- 必须是对象的属性。

③返回值:无

举例:

"""删除属性 __delattr__"""


class MyClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __setattr__(self, key, value):
        print("setattr is running...")
        super().__setattr__(key, value)

    def __delattr__(self, item):
        print("delattr is running...")
        if item == "name":
            raise AssertionError("name 属性不允许删除")
        else:
            super(MyClass, self).__delattr__(item)


class Car:
    refcount = 0

    def __init__(self, power):
        self.power = power
        self.totaldistance = 0

    def __delattr__(self, name):
        print(f"execute __delattr__:name={name}")
        super().__delattr__(name)


if __name__ == '__main__':
    obj = MyClass("zhangsan", 19)
    print(obj.__dict__)
    del obj.age
    print(obj.__dict__)
    del obj.name
"""
setattr is running...
setattr is running...
{'name': 'zhangsan', 'age': 19}
delattr is running...
{'name': 'zhangsan'}
delattr is running...
Traceback (most recent call last):
  File "/Users/PycharmProjects/pythonProject1/testdevp_work/属性/__delattr__.py", line 38, in <module>
    del obj.name
  File "/Users/PycharmProjects/pythonProject1/testdevp_work/属性/__delattr__.py", line 16, in __delattr__
    raise AssertionError("name 属性不允许删除")
AssertionError: name 属性不允许删除
"""

 

6.__slots__: 限制类的属性,减少内存

有时候我们想要限制class的属性怎么办?比如,只允许对Student实例添加nameage属性,其他的属性无法添加。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class能添加的属性:

举例:下面的MyClass类的实例属性,只能添加三个属性:name,age,height.所以再实例化时添加的hoppy属性,就会报错。

"""__slots__: 减少内存
覆盖__dict__中的属性,即限制对象有哪些属性
应用场景:创建大量的对象,可以用__slots__指定对象属性,减少内存
"""
class MyClass:
    __slots__ = ["name", "age", "height"]
    def __init__(self, name, age, hoppy):
        self.name = name
        self.age = age
        self.hoppy = hoppy

if __name__ == '__main__':
    obj = MyClass("zhangsan", 10, "dance")
    print(obj.__slots__)
    print(MyClass.__dict__)
"""
    self.hoppy = hoppy
AttributeError: 'MyClass' object has no attribute 'hoppy'
"""
class MyClass:
    __slots__ = ["name", "age", "height"]
    def __init__(self, name, age):
        self.name = name
        self.age = age

if __name__ == '__main__':
    obj = MyClass("zhangsan", 10)
    print(obj.__slots__)  # ['name', 'age', 'height']
    print(MyClass.__dict__)  # {'__module__': '__main__', '__slots__': ['name', 'age', 'height'], '__init__': <function MyClass.__init__ at 0x000002408A1D6288>, 'age': <member 'age' of 'MyClass' objects>, 'height': <member  'height' of 'MyClass' objects>, 'name': <member 'name' of 'MyClass' objects>, '__doc__': None}

 注意:__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的;

除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__