python面向对象基础内置方法 __xx__

Posted 少年阿斌

tags:

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

__str__和__repr__,__format__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

 

#_*_coding:utf-8_*_

format_dict={
    \'格式1\':\'{obj.name}-{obj.addr}-{obj.type}\',#学校名-学校地址-学校类型
    \'格式2\':\'{obj.type}:{obj.name}:{obj.addr}\',#学校类型:学校名:学校地址
    \'格式3\':\'{obj.type}/{obj.addr}/{obj.name}\',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return \'School(%s,%s)\' %(self.name,self.addr)
    def __str__(self):
        return \'(%s,%s)\' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec=\'格式1\'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School(\'清华\',\'北京\',\'公立\')
print(\'from repr: \',repr(s1))
print(\'from str: \',str(s1))
print(s1)

\'\'\'
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
\'\'\'
\'\'\'
注意:这三个方法的返回值必须是字符串,否则抛出异常
\'\'\'
print(format(s1,\'格式1\'))
print(format(s1,\'格式2\'))
print(format(s1,\'格式3\'))
print(format(s1,\'xxx\'))

 

 

 

class B:

     def __str__(self):
         return \'str : class B\'

     def __repr__(self):
         return \'repr : class B\'


b=B()
print(\'%s\'%b)
print(\'%r\'%b)

__del__

析构方:当对象在内存中被释放的同时自动触发执行该方法。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo:

    def __del__(self):
        print(\'执行我啦\')

f1=Foo()
del f1
# 执行我啦
print(\'------->\')
f1
# NameError: name \'f1\' is not defined

 

item系列

__getitem__\\__setitem__\\__delitem__

  ==》__dict__

 

在Python中,如果我们想实现创建类似于序列和映射的类,可以通过重写魔法方法__getitem__、__setitem__、__delitem__方法去模拟。

这些魔术方法的原理就是:当我们对类的属性item进行下标的操作时,首先会被__getitem__()、__setitem__()、__delitem__()拦截,从而进行我们在方法中设定的操作,如赋值,修改内容,删除内容等等。

对类的属性item进行下标的操作==>obj["属性"]

 

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

    def __getitem__(self, item):
        print("呵呵你看不到")

    def __setitem__(self, key, value):
        self.__dict__[key]=value
        print(\'设置了 obj 属性 [%s] 为 %s\'%(key,value))
        
    def __delitem__(self, key):
        print(\'del obj[%s]时,我执行\'%key)
        self.__dict__.pop(key)
    
    def __delattr__(self, item):
        print(\'del obj.%s时,我执行\'%item)
        self.__dict__.pop(item)
    
    def __setattr__(self, item,value):
        print("调用了__setattr__方法")
        self.__dict__[item]=value
        
    def daren(self):
        pass
    
    

a=A(\'斌哥\')
#这个过程也调用了__setattr__方法

print(a.__dict__)
# {\'name\': \'斌哥\'}

a.name
#==>\'斌哥\'

print(a[\'name\'])
#调用了__getitem__方法
# 呵呵你看不到
# None

a[\'age\']=18
#=触发=__setitem__>设置了 obj 属性 [age] 为 18
a.age=19
#=触发=__setitem__>调用了__setattr__方法
a[\'appear\']=\'很帅\'
# #=触发=>设置了 obj 属性 [appear] 为 很帅

del a.appear
#触发__delattr__==>del obj.appear时,我执行
del a[\'age\']
#触发__delitem__==>del obj[age]时,我执行
a.school=\'nc\'
print(a.__dict__)
# {\'school\': \'nc\', \'name\': \'斌哥\'}
# 结论:感觉属性维护了一个doc字典


# 结论 : obj.属性 调用 使用的是xxattr()方法
#xxitem()方法提供了 访问属性一个【】接口

 

__dict__

发现dict是一个mappingproxy类型,为何不是一个简单的python dict呢?

>>> class A(object): pass
...
>>> A.__dict__
mappingproxy({\'__module__\': \'__main__\', \'__dict__\': <attribute \'__dict__\' of \'A\' objects>, \'__weakref__\': <attribute \'__weakref__\' of \'A\' objects>, \'__doc__\': None})

不清楚,回头研究下。

Python的实例有自己的__dict__,它对应的类也有自己的__dict__   (但是有些特殊的对象是没有__dict__属性的)

class A:
    def __init__(self,name):
        self.name=name
    def __len__(self):
        return len(self)
a=A(\'斌哥\')
print(A.__dict__)
# {\'__doc__\': None, \'__module__\': \'__main__\', \'__len__\': <function A.__len__ at 0x0000014FF1C71EA0>,
#  \'__init__\': <function A.__init__ at 0x0000014FF1BE1730>, \'__weakref__\': <attribute \'__weakref__\' of \'A\' objects>, 
# \'__dict__\': <attribute \'__dict__\' of \'A\' objects>}

print(a.__dict__)
# {\'name\': \'斌哥\'}

class B(A):
    def __init__(self,age,name):
        super().__init__(name)
        self.age=age
    def __len__(self):
        return len(self)
b=B(18,"bb")
print(B.__dict__)
print(b.__dict__)

# {\'__doc__\': None, \'__module__\': \'__main__\', 
#  \'__init__\': <function B.__init__ at 0x0000014FF1CB1A60>,
# \'__len__\': <function B.__len__ at 0x0000014FF1CB1730>}
# 
# {\'name\': \'bb\', \'age\': 18}

 

class A:
    a = 0
    b = 1

    def __init__(self):
        self.a = 2
        self.b = 3

    def test(self):
        print(\'a normal func.\')

    @staticmethod
    def static_test(a):
        print(\'a static func.\'+a)

    @classmethod
    def class_test(cls):
        print(\'a calss func.\')


obj = A()
print(A.__dict__)
print(obj.__dict__)
A.static_test("1")
A.class_test()

 

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

2.对象的属性(不含类的)保存在实例__dict___

3.子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中。对象也这样。

4.内置的数据类型没有__dict__属性

 

 

__dir__

dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

dir([object])

参数说明:

  • object -- 对象、变量、类型。
class A(object): pass
a=A()
a.name="wqbin"

print(A.__dict__)
print(a.__dict__)
print(a.__dir__())

 

 

 Note:dir是最大范围的收集一个类或者一个对象的属性,所以是包含__dict__.keys

 

 

__call__

对象后面加括号,触发执行。

对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class C:

    def __init__(self):
        print("__init__")
    
    def __call__(self, *args, **kwargs):

        print(\'__call__\')


obj = C() # 执行 __init__
obj()       # 执行 __call__

为什么函数对象可以触发?

f = abs

print(dir(f))

 

__len__

果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。

要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))
#2

 

__hash__

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        # return str(self.a)+\'哈哈\'+str(self.b)
        
        return int(str(1024)+str(self.a)+str(self.b))
a = A()
print(hash(a))
# TypeError: __hash__ method should return an integer

 

__eq__

__eq__ 当判断两个对象的是否相等时,==触发此方法

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b) #true

== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。默认会调用对象的 __eq__()方法。

 

以上是关于python面向对象基础内置方法 __xx__的主要内容,如果未能解决你的问题,请参考以下文章

python-面向对象-内置方法补充

Python之面向对象:类的内置方法

python-38-用于面向对象的内置函数

python面向对象常用内置方法

关于pyhton中的__xxx__格式的方法与变量的理解

Python之路(第二十六篇) 面向对象进阶:内置方法