1.类相关属性
1.1 类相关属性整理
特殊方法 | 含义 |
---|---|
obj.__class__ | 对象所属的类 |
class.__bases__ | 类的基类元组 |
class.__base__ | 类的基类 |
class.__mro__ | 类层次结构 |
class.__subclass__() | 子类类表 |
1.2 类相关属性操作
示例代码:
class A:
class_attr1 = "class_val1"
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
a1 = A("val_a_1", "val_a_2")
print("所属的类")
print(a1.__class__)
print("--" * 20)
print("基类元组,针对多继承的情况")
print(D.__bases__)
print("--" * 20)
print("类的基类")
print(D.__base__)
print("--" * 20)
print("类完整层次结构")
print(D.__mro__)
print('--' * 20)
print("直接子类列表")
print(A.__subclasses__())
运行结果:
所属的类
<class '__main__.A'>
----------------------------------------
基类元组,针对多继承的情况
(<class '__main__.B'>, <class '__main__.C'>)
----------------------------------------
类的基类
<class '__main__.B'>
----------------------------------------
类完整层次结构
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
----------------------------------------
直接子类列表
[<class '__main__.B'>, <class '__main__.C'>]
代码说明:
- 按照上面类继承关系示意图创建类A、类B、类C、类D
__class__
代表对象所属的类,对象a1是类A的实例,所以a1.__class__
对应的结果是:<class '__main__.A'>
- 因为python支持多继承,
__bases__
只返回直接继承父类的元组,定义类D过程中指定D(B, C)
,所以对应结果为:(<class '__main__.B'>, <class '__main__.C'>)
__base__
返回直接父类,可以使用在单继承和多继承中,对于多继承情况下是不准确的,只会返回第一个继承的类,定义类D过程中指定D(B, C)
,其中第一个类为B
,所以返回:<class '__main__.B'>
__mro__
属性用于返回从当前类到类object的完整继承关系,对应结果的类型是tuple。对于多继承多分支情况,有兴趣的同学可以测试一下,采用什么规则__subclasses__()
用于返回直接子类列表,在程序中,类B继承类A, 类C继承类A,所以对应的子类列表为:[<class '__main__.B'>, <class '__main__.C'>]
2.普通实例属性相关操作
实例属性相关特殊方法和特殊属性
方法 | 说明 | 例子 |
---|---|---|
__dict__ | 对象的属性字典 | a.__dict__ |
__getattr__ | 获取属性 | a.attr_name |
__setattr__ | 属性赋值 | a.attr_name = value |
__getattribute__ | 获取属性 | a.attr_name |
hasattr() | 判断属性是否存在 | hasattr(a, 'name') |
getattr() | 获取属性 | getattr(a, 'name') |
setattr() | 设置属性 | setattr(a, 'name') = 'niefajun' |
正常情况下,对于对象的实例属性可以直接操作,以上的属性或者方法是对操作
示例代码:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __setattr__(self, key, value):
print('__setattr__:key={0},value={1}'.format(key, value))
super(Person, self).__setattr__(key, value)
def __getattr__(self, item):
print('__getattr__')
print("获取的属性不存在")
def __getattribute__(self, item):
print("__getattribute__")
return super(Person, self).__getattribute__(item)
p1 = Person("聂发俊", 100)
print('--' * 20)
print("属性字典")
print(p1.__dict__)
print('--' * 20)
print("判断属性是否存在")
has_flag = hasattr(p1, "name")
print(has_flag)
print('--' * 20)
print("设置属性1-直接设置")
p1.age = 101
print('--' * 20)
print('设置属性2-setattr函数')
setattr(p1, 'age', 102)
print('--' * 20)
print("设置属性3-__setattr__()方法")
p1.__setattr__('age', 103)
print('--' * 20)
print("获取属性1-直接获取")
print(p1.age)
print('--' * 20)
print("获取属性2-getattr函数")
print(getattr(p1, 'age'))
print('--' * 20)
print("获取属性3-__getattribute__方法")
print(p1.__getattribute__('age'))
print('--' * 20)
print("获取不存在的属性")
print(p1.name1)
运行结果:
__setattr__:key=name,value=聂发俊
__setattr__:key=age,value=100
----------------------------------------
属性字典
__getattribute__
{'name': '聂发俊', 'age': 100}
----------------------------------------
判断属性是否存在
__getattribute__
True
----------------------------------------
设置属性1-直接设置
__setattr__:key=age,value=101
----------------------------------------
设置属性2-setattr函数
__setattr__:key=age,value=102
----------------------------------------
设置属性3-__setattr__()方法
__getattribute__
__setattr__:key=age,value=103
----------------------------------------
获取属性1-直接获取
__getattribute__
103
----------------------------------------
获取属性2-getattr函数
__getattribute__
103
----------------------------------------
获取属性3-__getattribute__方法
__getattribute__
__getattribute__
103
----------------------------------------
获取不存在的属性
__getattribute__
__getattr__
获取的属性不存在
None
程序说明:
1.实例化过程中输出__setattr__:key=name
和__setattr__:key=age
,这个是因为在__init__()
方法中设置了这两个属性,都会经过__setattr__()
方法,所以会执行两次。
2.属性字典中,本质上还是通过__getattribute__
,所以也会输出__getattribute__
的提示信息。
3.三种设置属性方法,比较特殊的是第三次,相比其他两次增加了__getattribute__
输出,因为有一次判断属性是否存在的过程。
4.三种获取属性值,比较特殊的也是第三次,多了一次__getattribute__
,和__setattr__()
方法一样,增加了一次属性是否存在的过程,所以看起来比较特殊。
5.当获取一个不存在的属性,首先调用__getattribute__(self, item)
,如果属性存在则直接返回,不存在时,判断__getattr__(self)
是否存在,存在的话,则执行__getattr__(self)
方法,作为获取不存在属性的一种兜底操作。如果没有存在__getattr__(self)
,则直接提示属性异常。
__getattribute__(self, item)
VS__getattr__(self, item)
:
相同点:都是用于属性获取
不同点:__getattribute__()
无论属性是否存在都会首先访问,获取对应值;__getattr__()
只有当属性不存在的时候,才会调用,作为兜底(异常)处理。
注意事项:对于__setattr__()
和__getattribute__()
不要在函数里面直接赋值和返回属性,这样操作的话,又会调用__setattr__()
和__getattribute__()
,构成死循环。
错误代码:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __setattr__(self, key, value):
"""错误操作"""
# 等效操作: self.__setattr__(key, value), 自己调用自己,造成死循环
self.key = value
def __getattribute__(self, item):
"""错误操作"""
# 等效操作: self.__getattribute__(item), 自己调用自己,造成死循环
return self.item
3.对象操作
对象操作整理:
方法 | 说明 | 例子 |
---|---|---|
__getitem__ | 通过索引获取 | a[key_index] |
__setitem__ | 通过索引设置 | a[key_index] = value |
在日常的开发过程中,使用的比较少
示例代码:
class Animal:
def __init__(self, animal_li):
self.animals_name = animal_li
def __getitem__(self, item):
return self.animals_name[item]
animals = Animal(['cat', 'dog', 'tiger'])
for animal in animals:
print(animal)
执行结构:
cat
dog
tiger
注:使用的很少,等后面有具体使用场景在补充完善。
备注:
更多精彩博客,请访问:聂发俊的技术博客
对应视频教程,请访问:python400
完整markdown笔记,请访问: python400_learn_github