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__的主要内容,如果未能解决你的问题,请参考以下文章