python面向对象特殊属性_python面向对象中的一些特殊__方法__

阅读目录

1. __doc__

表示类的描述信息

copycode.gif

class Foo:

""" 描述类信息"""

def func(self):

pass

print (Foo.__doc__)

#输出:类的描述信息

copycode.gif

2. __module__ 和 __class__

__module__ 表示当前操作的对象在那个模块

__class__ 表示当前操作的对象的类是什么

copycode.gif

#!/usr/bin/env python

# -*- coding:utf-8 -*-

class C:

def __init__(self):

self.name = 'maple'

lib/aa.py

copycode.gif

from lib.aa import C

obj = C()

print (obj.__module__) # 输出 lib.aa,即:输出模块

print (obj.__class__ ) # 输出 lib.aa.C,即:输出类

3. __init__

构造方法,通过类创建对象时,自动触发执行。

copycode.gif

class Foo:

def __init__(self, name):

self.name = name

self.age = 18

obj = Foo('maple') # 自动执行类中的 __init__ 方法

copycode.gif

4. __del__

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

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

class Foo:

def __del__(self):

pass

5. __call__

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

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

copycode.gif

class Foo:

def __init__(self):

pass

def __call__(self, *args, **kwargs):

print ('__call__')

obj = Foo() # 执行 __init__

obj() # 执行 __call__

copycode.gif

6. __dict__

类或对象中的所有成员

copycode.gif

class Province:

country = 'China'

def __init__(self, name, count):

self.name = name

self.count = count

def func(self, *args, **kwargs):

print ('func')

# 获取类的成员,即:静态字段、方法、

print (Province.__dict__)

# 输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}

obj1 = Province('HeBei',10000)

print (obj1.__dict__)

# 获取 对象obj1 的成员

# 输出:{'count': 10000, 'name': 'HeBei'}

obj2 = Province('HeNan', 3888)

print (obj2.__dict__)

# 获取 对象obj1 的成员

# 输出:{'count': 3888, 'name': 'HeNan'}

copycode.gif

7. __str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值

copycode.gif

class Foo:

def __str__(self):

return 'maple'

obj = Foo()

print (obj)

# 输出:maple

copycode.gif

8、__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

copycode.gif

class Foo(object):

def __getitem__(self, key):

print ('__getitem__',key)

def __setitem__(self, key, value):

print ('__setitem__',key,value)

def __delitem__(self, key):

print ('__delitem__',key)

obj = Foo()

result = obj['k1'] # 自动触发执行 __getitem__

obj['k2'] = 'maple' # 自动触发执行 __setitem__

del obj['k1'] # 自动触发执行 __delitem__

copycode.gif

9、__getslice__、__setslice__、__delslice__

该三个方法用于分片操作,如:列表

copycode.gif

class Foo(object):

def __getslice__(self, i, j):

print ('__getslice__',i,j)

def __setslice__(self, i, j, sequence):

print ('__setslice__',i,j)

def __delslice__(self, i, j):

print ('__delslice__',i,j)

obj = Foo()

obj[-1:1] # 自动触发执行 __getslice__

obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__

del obj[0:2] # 自动触发执行 __delslice__

copycode.gif

10. __iter__

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

copycode.gif

class Foo(object):

pass

obj = Foo()

for i in obj:

print (i)

# 报错:TypeError: 'Foo' object is not iterable

第一步

copycode.gif

copycode.gif

#!/usr/bin/env python

# -*- coding:utf-8 -*-

class Foo(object):

def __iter__(self):

pass

obj = Foo()

for i in obj:

print (i)

# 报错:TypeError: iter() returned non-iterator of type 'NoneType'

第二步

copycode.gif

copycode.gif

#!/usr/bin/env python

# -*- coding:utf-8 -*-

class Foo(object):

def __init__(self, sq):

self.sq = sq

def __iter__(self):

return iter(self.sq)

obj = Foo([11,22,33,44])

for i in obj:

print (i)

第三步

copycode.gif

以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:

obj = iter([11,22,33,44])

for i in obj:

print (i)

copycode.gif

obj = iter([11,22,33,44])

while True:

val = obj.next()

print (val)

For循环语法内部

copycode.gif

11. __new__ 和 __metaclass__

阅读以下代码:

class Foo(object):

def __init__(self):

pass

obj = Foo() # obj是通过Foo类实例化的对象

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

print type(obj) # 输出: 表示,obj 对象由Foo类创建

print type(Foo) # 输出: 表示,Foo类对象由 type 类创建

所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式

class Foo(object):

def func(self):

print ('hello maple')

b).特殊方式(type类的构造函数)

copycode.gif

def func(self):

print ('hello maple')

Foo = type('Foo',(object,), {'func': func})

#type第一个参数:类名

#type第二个参数:当前类的基类

#type第三个参数:类的成员

copycode.gif

==》 类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

copycode.gif

class MyType(type):

def __init__(self, what, bases=None, dict=None):

super(MyType, self).__init__(what, bases, dict)

def __call__(self, *args, **kwargs):

obj = self.__new__(self, *args, **kwargs)

self.__init__(obj)

class Foo(object):

__metaclass__ = MyType

def __init__(self, name):

self.name = name

def __new__(cls, *args, **kwargs):

return object.__new__(cls, *args, **kwargs)

# 第一阶段:解释器从上到下执行代码创建Foo类

# 第二阶段:通过Foo类创建obj对象

obj = Foo()

copycode.gif

12.__repr__

在python解释器环境下,会默认显示对象的repr表示。

copycode.gif

>>> class Student:

... def __init__(self, name, age):

... self.name = name

... self.age = age

... def __repr__(self):

... return self.name

...

>>> s1 = Student('张三', 24)

>>> s1

张三

copycode.gif

总结:

str函数或者print函数调用的是obj.__str__()repr函数或者交互式解释器调用的是obj.__repr__()

注意:如果__str__没有被定义,那么就会使用__repr__来代替输出。__str__和__repr__方法的返回值都必须是字符串。

13.__format__

copycode.gif

class Student:

def __init__(self, name, age):

self.name = name

self.age = age

__format_dict = {

'n-a': '名字是:{obj.name}-年龄是:{obj.age}', # 名字是:maple-年龄是:18

'n:a': '名字是:{obj.name}:年龄是:{obj.age}', # 名字是:maple:年龄是:18

'n/a': '名字是:{obj.name}/年龄是:{obj.age}', # 名字是:/年龄是:18

}

def __format__(self, format_spec):

if not format_spec or format_spec not in self.__format_dict:

format_spec = 'n-a'

fmt = self.__format_dict[format_spec]

print(fmt) #{obj.name}:{obj.age}

return fmt.format(obj=self)

s1 = Student('maple', 24)

ret = format(s1, 'n/a')

print(ret) # maple/24

copycode.gif

14.__item__

copycode.gif

class Foo:

def __init__(self, name):

self.name = name

def __getitem__(self, item):

print(self.__dict__[item])

def __setitem__(self, key, value):

print('obj[key]=maple赋值时,执行我')

self.__dict__[key] = value

def __delitem__(self, key):

print('del obj[key]时,执行我')

self.__dict__.pop(key)

def __delattr__(self, item):

print('del obj.key时,执行我')

self.__dict__.pop(item)

f1 = Foo('sb')

print(f1.__dict__)

f1['age'] = 18

f1.hobby = '泡妞'

del f1.hobby

del f1['age']

f1['name'] = 'maple'

print(f1.__dict__)

copycode.gif

15.__new__

其实__init__是在类实例被创建之后调用的,它完成的是类实例的初始化操作,而 __new__方法正是创建这个类实例的方法

copycode.gif

class Person:

def __new__(cls, *args, **kwargs):

print('调用__new__,创建类实例')

return super().__new__(Person)

def __init__(self, name, age):

print('调用__init__,初始化实例')

self.name = name

self.age = age

def __str__(self):

return ''.format(self.name, self.age)

p1 = Person('张三', 24)

print(p1)

copycode.gif

输出:

调用__new__,创建类实例

调用__init__,初始化实例

__new__方法在类定义中不是必须写的,如果没定义的话默认会调用object.__new__去创建一个对象(因为创建类的时候默认继承的就是object)。

如果我们在类中定义了__new__方法,就是重写了默认的__new__方法,我们可以借此自定义创建对象的行为。

举个例子:

重写类的__new__方法来实现单例模式。

copycode.gif

class Singleton:

# 重写__new__方法,实现每一次实例化的时候,返回同一个instance对象

def __new__(cls, *args, **kw):

if not hasattr(cls, '_instance'):

cls._instance = super().__new__(Singleton)

return cls._instance

def __init__(self, name, age):

self.name = name

self.age = age

s1 = Singleton('张三', 24)

s2 = Singleton('李四', 20)

print(s1, s2) # 这两实例都一样

print(s1.name, s2.name)

copycode.gif

16.__enter__和__exit__

一个对象如果实现了__enter__和___exit__方法,那么这个对象就支持上下文管理协议,即with语句

copycode.gif

class A:

def __enter__(self):

print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量')

return 'oo'

def __exit__(self, exc_type, exc_val, exc_tb):

print('退出with代码块时执行此方法')

print('1', exc_type)

print('2', exc_val)

print('3', exc_tb)

with A() as f:

print('进入with语句块')

# with语句中代码块出现异常,则with后的代码都无法执行。

# raise AttributeError('sb')

print(f) #f打印出oo

print('嘿嘿嘿')

copycode.gif

上下文管理协议适用于那些进入和退出之后自动执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁的编码场景等

17.__len__

拥有__len__方法的对象支持len(obj)操作。

copycode.gif

class A:

def __init__(self):

self.x = 1

self.y = 2

def __len__(self):

return len(self.__dict__)

a = A()

print(len(a))

copycode.gif

18.__hash__

拥有__hash__方法的对象支持hash(obj)操作。

copycode.gif

class A:

def __init__(self):

self.x = 1

self.x = 2

def __hash__(self):

return hash(str(self.x) + str(self.x))

a = A()

print(hash(a))

copycode.gif

19.__eq__

拥有__eq__方法的对象支持相等的比较操作

copycode.gif

class A:

def __init__(self,x,y):

self.x = x

self.y = y

def __eq__(self,obj):

# 打印出比较的第二个对象的x值

print(obj.x)

if self.x +self.y == obj.x+obj.y:

return True

else:

return False

a = A(1,2)

b = A(2,1)

print(a == b)

copycode.gif

20.描述符(__get__,__set__,__delete__)

1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议__get__():调用一个属性时,触发__set__():为一个属性赋值时,触发__delete__():采用del删除属性时,触发

copycode.gif

class Foo(): #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符

def __get__(self, instance, owner):

pass

def __set__(self, instance, value):

pass

def __delete__(self, instance):

pass

定义一个描述符

copycode.gif

2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

copycode.gif

#描述符Str

class Str:

def __get__(self, instance, owner):

print('Str调用')

def __set__(self, instance, value):

print('Str设置...')

def __delete__(self, instance):

print('Str删除...')

#描述符Int

class Int:

def __get__(self, instance, owner):

print('Int调用')

def __set__(self, instance, value):

print('Int设置...')

def __delete__(self, instance):

print('Int删除...')

class People:

name=Str()

age=Int()

def __init__(self,name,age): #name被Str类代理,age被Int类代理,

self.name=name

self.age=age

#何地?:定义成另外一个类的类属性

#何时?:且看下列演示

p1=People('ffm',18)

#描述符Str的使用

p1.name

p1.name='maple'

del p1.name

#描述符Int的使用

p1.age

p1.age=18

del p1.age

#我们来瞅瞅到底发生了什么

print(p1.__dict__)

print(People.__dict__)

#补充

print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的

print(type(p1).__dict__ == People.__dict__)

描述符应用之何时?何地?

copycode.gif

3 描述符分两种一 数据描述符:至少实现了__get__()和__set__()

class Foo:

def __set__(self, instance, value):

print('set')

def __get__(self, instance, owner):

print('get')

二 非数据描述符:没有实现__set__()

class Foo:

def __get__(self, instance, owner):

print('get')

4 注意事项:一 描述符本身应该定义成新式类,被代理的类也应该是新式类二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中三 要严格遵循该优先级,优先级由高到底分别是1.类属性2.数据描述符3.实例属性4.非数据描述符5.找不到的属性触发__getattr__()

类属性>数据描述符

数据描述符>实例属性

实例属性>非数据描述符

非数据描述符>找不到

利用描述符原理完成一个自定制的@staticmethod

copycode.gif

class StaticMethod:

def __init__(self,func):

self.func=func

def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,

def feedback(*args,**kwargs):

print('在这里可以加功能啊...')

return self.func(*args,**kwargs)

return feedback

class People:

@StaticMethod# say_hi=StaticMethod(say_hi)

def say_hi(x,y,z):

print('------>',x,y,z)

People.say_hi(1,2,3)

p1=People()

p1.say_hi(4,5,6)

自己做一个@staticmethod

copycode.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值