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__()方法。

 

posted @ 2019-02-15 11:33  wqbin  阅读(848)  评论(0编辑  收藏  举报