python基础类的特殊成员(类的特殊内置属性和方法)

Posted 非晚非晚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础类的特殊成员(类的特殊内置属性和方法)相关的知识,希望对你有一定的参考价值。

  • __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。
  • _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
  • __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问

Python 用下划线作为变量前缀和后缀指定方法为特殊方法,下面介绍一些常用的特殊方法。(本文会根据自己遇到的内置属性和方法,随时更新!)

0. 特殊属性

先来看属性:

  • Class.__doc__ # 类型帮助信息 ‘Class1 Doc.’
  • Class.__name__ # 类型名称 ‘Class1’
  • Class.__module__ # 类型所在模块 ‘main
  • Class.__bases__ # 类型所继承的基类 (<type ‘object’>,)
  • Class.__dict__ # 类型字典,存储所有类型成员信息。 <dictproxy object at 0x00D3AD70>
  • obj.__class__ # 类型 <class ‘__main__.Class1’>
  • obj.__module__ # 实例类型所在模块 ‘__main__’
  • obj.__dict__ # 对象字典,存储所有实例成员信息。 ‘i’: 1234

直接看程序会更清晰

class A:
    '''A的帮助信息''' #给__doc__使用
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def foo(self):
        pass

    def bar(self):
        pass

a = A('口罩', 0.5)
#-----------------class---------------------
print(A.__doc__) #类的帮助信息
print(A.__name__) # 类的名字:A
print(A.__module__) ## __main__
print(A.__base__) ## A的基类:<class 'object'>
print(A.__dict__) #类别字典,类存储的成员信息

#---------------------obj-----------------------
print(a.__class__) #<class '__main__.A'>
print(a.__module__) # __main__
print(a.__dict__) #对象字典'name': '口罩', 'price': 0.5

1. 类的基础方法

目的所编写代码Python 实际调用
初始化一个实例x = MyClass()x.__init__()
字符串的“官方”表现形式repr(x)x.__irepr__()
字符串的“非正式”值str(x)x.__str__()
字节数组的“非正式”值bytes(x)x.__ibytes__()
格式化字符串的值format(x, format_spec)x.__iformat__(format_spec)

1.1 __init__()

在创建实例对象时,调用该方法。

class A():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('__init__被调用了!')

a = A('xiaoming', 22)

输出:

__init__被调用了!

1.2 __repr__()

该方法继承自object类。当创建我们用print打印对象时,会默认调用该方法得到我们关于类的信息。一般默认打印的信息为<xxxx object at 0x000000879>,我们可以对它的输出进行改变。如下:

class A():
    def __repr__(self):
        return '__repr__被调用了!'

a = A()
print(a)

输出:

__repr__被调用了!

1.3 __str__()

与repr类似。区别如下:

  • __str__ 的返回结果可读性强。也就是说,__str__ 的意义是得到便于人们阅读的信息,就像上面的 ‘2019-10-20 20:59:47.003003’ 一样。
  • __repr__ 的返回结果应更准确。__repr__ 存在的目的在于调试,便于开发者使用。将 __repr__ 返回的方式直接复制到命令行上,是可以直接执行的。
class A():
    def __str__(self):
        return '__str__被调用了!'
a = A()
print(a)

输出:

__str__被调用了!

2. 与迭代器类似(__iter__()与__next__())

目的所编写代码Python 实际调用
遍历某个序列iter(seq)seq.__iter__()
从迭代器中获取下一个值next(seq)seq.__next__()
按逆序创建一个迭代器reversed(seq)seq.__reversed__()

iter与next常常一起使用,reversed方法并不常用,它是一个现有序列为参数,并将该序列中所有元素从尾到头以逆序排列生成一个新的迭代器。

class A():
    def __init__(self,num):
        self.num = num
        self.start_num = -1
    def __iter__(self):
        print('__iter__被调用')
        return self
    def __next__(self):
        print('__next__被调用')
        self.start_num +=1
        if(self.start_num >= self.num):
            raise StopIteration()
        return self.start_num

for i in A(5): #迭代5次
    print(i)

输出:

__iter__被调用
__next__被调用
0
__next__被调用
1
__next__被调用
2
__next__被调用
3
__next__被调用
4
__next__被调用

3. 行为方式与函数类似(__call__())

目的所编写代码Python 实际调用
遍历某个序列my_instance()my_instance.__call__()

把实例当做函数一样调用。

class A():
    def __call__(self, *args, **kwargs):
        print('__call__被调用')
        print(args)
        print(kwargs)

a = A()
a(1,2,q = 1)

输出:

__call__被调用
(1, 2)
'q': 1

4. 行为方式与序列类似的类

目的所编写代码Python 实际调用
序列的长度len(seq)seq.__len__()
了解某序列是否包含特定的值x in seqseq.__contains__(x)

4.1 __len__()

可以计算实例长度。

class A():
    def __len__(self):
        print('__len__被调用')
        return 10
a = A()
print(len(a))

输出:

__len__被调用
10

4.2 __contains__(x)

可以像序列一样遍历类

class A():
    def __init__(self):
        self.items = 'a':1, 'b':2,'c':3
    def __contains__(self, item):
        print('__contains__被调用')
        return item in self.items
a = A()
print('a' in a)
print('d' in a)

输出:

__contains__被调用
True
__contains__被调用
False

5. 行为方式与字典类似

目的所编写代码Python 实际调用
通过键来获取值x[key]x.__getitem__(key)
通过键来设置值x[key] = valuex.__setitem__(key, value)
删除一个键值对del x[key]x.__delitem__(key)
为缺失键提供默认值x[nonexistent_key]x.__missing__(nonexistent_key)

5.1 __setitem__(key, value)

像字典一样设定键值对

class A():
    def __setitem__(self, key, value):
        print('__setitem__被调用')

a = A()
a[3] = 4

输出:

__setitem__被调用

5.2 __getitem__(key)

像字典一样取值

class A():
    def __setitem__(self, key, value):
        print('__setitem__被调用')
    def __getitem__(self, item):
        print('__getitem__被调用')
        print("item: ",item)
        return 10

a = A()
a['3'] = 4
print("-"*20)
print(a['3'])

输出:

__setitem__被调用
--------------------
__getitem__被调用
item:  3
10

5.3 __delitem__(key)

像字典一样删除键值对

class A():
    def __setitem__(self, key, value):
        print('__setitem__被调用')
    def __delitem__(self, key):
        print('__delitem__被调用')

a = A()
a['3'] = 4
del a[3]

输出:

__setitem__被调用
__delitem__被调用

6. 计算属性

目的所编写代码Python 实际调用
获取一个计算属性(无条件的)x.my_propertyx.__getattribute__(‘my_property’)
获取一个计算属性(后备)x.my_propertyx.__getattr__(‘my_property’)
设置某属性x.my_property = valuex.__setattr__(‘my_property’,value)
删除某属性del x.my_propertyx.__delattr__(‘my_property’)
列出所有属性和方法dir(x)x.__dir__()

6.1 __getattribute__(‘my_property’)

如果某个类定义了 __getattribute__() 方法,在 每次引用属性或方法名称时Python 都调用它(特殊方法名称除外,因为那样将会导致讨厌的无限循环)。

class A():
    def __init__(self,num):
        self.num = num
    def __getattribute__(self, item):
        print('__getattribute__被调用')
        print(item)
        return object.__getattribute__(self,item)

a = A(3)
print(a.num)

输出:

__getattribute__被调用
num
3

6.2 __dir__()

列出所有属性和方法

class A():
    def __init__(self):
        pass

a = A()
print(dir(a))

输出:

[‘class’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’, ‘eq’, ‘format’, ‘ge’, ‘getattribute’, ‘gt’, ‘hash’, ‘init’, ‘init_subclass’, ‘le’, ‘lt’, ‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’]

7. 可比较的类

目的所编写代码Python 实际调用
相等x == yx.__eq__(y)
不相等x != yx.__ne__(y)
小于x < yx.__lt__(y)
小于或等于x <= yx.__le__(y)
大于x > yx.__gt__(y)
大于或等于x >= yx.__ge__(y)
布尔上上下文环境中的真值if x:x.__bool__()

如果定义了 __lt__() 方法但没有定义 __gt__() 方法,Python 将通过经交换的算子调用__lt__() 方法。然而,Python 并不会组合方法。例如,如果定义了__lt__() 方法和 __eq()__ 方法,并试图测试是否 x <= y,Python 不会按顺序调用__lt__() 和__eq()__ 。它将只调用__le__() 方法。

以上是关于python基础类的特殊成员(类的特殊内置属性和方法)的主要内容,如果未能解决你的问题,请参考以下文章

Python学习:17.Python面向对象(属性(特性),成员修饰符,类的特殊成员)

类的特殊成员

Python基础:Python类(真累~)

类的特殊成员

python入门第二十四天----成员修饰符 类的特殊成员

python 面向对象整理 --------3.面向对象进阶--类的特殊成员