python面向对象编程第2版_Python学习之==>面向对象编程(二)

一、类的特殊成员

我们在Python学习之==>面向对象编程(一)中已经介绍过了构造方法和析构方法,构造方法是在实例化时自动执行的方法,而析构方法是在实例被销毁的时候被执行,Python类成员中还存在着一些具有特殊意义的方法,下面我们来一一介绍一下:

1、__doc__

表示类的描述信息

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 '''

3 描述类信息4 '''

5 deffunc(self):6 pass

7

8 print(Foo.__doc__) #描述类信息

View Code

2、__module__ 和  __class__

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

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classC:2 def __init__(self):3 self.name = 'Jack'

/lib/practice.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 from lib.practice importC2

3 obj =C()4 print(obj.__module__) #lib.practice,即模块

5 print(obj.__class__) #,即类

index.py

3、__init__

构造方法,类再实例化时自动执行的方法

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self):3 print('init')4

5 obj = Foo() #init,自动执行类中的 __init__ 方法

View Code

4、__del__

析构方法,实例被销毁时自动执行的方法,一般可用于自动关闭文件、关闭连接、关闭数据库、删除测试数据等操作

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 importpymysql2 classMyDb(object):3 def __init__(self,host,user,db,passwd,4 port=3306,charset='utf8'): #构造函数

5 try:6 self.conn =pymysql.connect(7 host=host,user=user,passwd=passwd,port=port,db=db,charset=charset,8 autocommit=True #自动提交

9 )10 exceptException as e:11 print('数据库连接失败!:%s'%e)12 else:13 self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)14

15 def __del__(self): #析构函数,实例被销毁的时候执行

16 self.cur.close()17 self.conn.close()18 print('数据库连接关闭')19

20 defex_sql(self,sql):21 try:22 self.cur.execute(sql)23 exceptException as e:24 print('sql语句有问题:%s'%sql)25 else:26 self.res =self.cur.fetchall()27 returnself.res28

29 my = MyDb('118.24.3.40','jxz','jxz','123456')30 my.ex_sql('select * from stu;')31 print(my.res) #可以用实例属性取值

32 print(my.ex_sql('select * from stu;')) #也可以用实例方法的返回值

33 print('我是最后一行代码') #执行完最后这行代码后再执行析构函数

View Code

5、__dict__

将对象中封装的内容/成员通过字典的形式返回

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo():2 '''

3 这个类是干啥的。。4 '''

5 def __init__(self, name, age):6 self.name =name7 self.age =age8

9 obj = Foo('alex',99)10 d = obj.__dict__ #对象有__dict__方法,显示对象的所有成员

11 print(d) #{'name': 'alex', 'age': 99}

12 ret = Foo.__dict__ #类也有__dict__方法,显示类的所有成员

13 print(ret)#{'__module__': '__main__', '__doc__': '\n 这个类是干啥的。。\n ', '__init__': , '__dict__': , '__weakref__': }

View Code

6、__int__

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self): #构造方法

3 print('init')4

5 def __int__(self):6 return 1

7

8

9 obj = Foo() #init,创建对象时自动执行构造方法

10 r = int(obj) #int后面加上一个对象(obj),它就会自动执行对象(obj)当中的__int__方法,并将返回值赋给int对象(r是int的对象)

11 print(r) #1

12 print(type(r))#,r是int类的对象

View Code

7、__str__

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self): #构造方法

3 print('init')4

5 def __str__(self):6 return 'niu'

7

8 obj = Foo() #init,创建对象时自动执行构造方法

9 print(obj,type(obj)) #<__main__.foo object at> ,obj的类型是Foo类

10 #niu ,类中加上__str__()后的返回

11 #print()函数在执行时会自动调用对象中的__str__()方法,所以Foo类中加上__str__()方法之前显示为内存地址,加上__str__()方法之后,显示为__str__()方法的返回值‘niu’

12 #print(obj)相当于print(str(obj))

13 s = str(obj) #str后面加上一个对象(obj),它就会自动执行对象(obj)当中的__str__方法,并将返回值赋给str对象(s是str的对象)

14 print(s)

View Code

8、__add__

如果一个类中定义了__add__方法,那么在两个对象进行相加时,返回的是该方法的返回值

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self, name, age):3 self.name =name4 self.age =age5

6 def __add__(self, other):7 return self.age +other.age8

9 obj1 = Foo('alex', 19)10 obj2 = Foo('hiro', 55)11 r = obj1 + obj2 #两个对象相加时,自动执行第一个对象的__add__方法,并且将第二个对象当参数传入

12 print(r, type(r))#74

View Code

9、__call__

对象后面加括号,触发执行类中的__call__方法

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self): #构造方法

3 print('init')4

5 def __call__(self, *args, **kwargs):6 print('call')7

8

9 obj = Foo() #init,创建对象时自动执行构造方法

10 obj() #call,对象后面加括号直接调用类中的__call__()方法

View Code

10、__getitem__、__setitem__、__delitem__

用于索引、切片操作,如:列表、字典。以上三个方法分别获取、设置、删除数据

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo():2

3 def __init__(self, name, age):4 self.name =name5 self.age =age6

7 def __getitem__(self, item):8 print(item + 10)9

10 def __setitem__(self, key, value):11 print(key, value)12

13 def __delitem__(self, key):14 print(key)15

16 li = Foo('alex',99)17 #索引

18 li[8] #自动执行li对象的类中__getitem__方法,8当作参数传递给item

19 li[100] = 123 #自动执行li对象的类中__setitem__方法,100和123当作参数传递给key和value

20 del li[99] #自动执行li对象的类中__delitem__方法,99当作参数传递给key

View Code

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo():2

3 def __init__(self, name, age):4 self.name =name5 self.age =age6

7 def __getitem__(self, item):8 #如果item是基本类型,int,str索引获取

9 #如果item类型是slice,切片

10 print(type(item))11 if type(item) == slice: #切片是slice类型

12 print('切片处理')13 print(item.start)14 print(item.stop)15 print(item.step)16 else:17 print('索引处理')18 def __setitem__(self, key, value):19 print(type(key))20 if type(key) ==slice:21 print('切片处理')22 print(key.start)23 print(key.stop)24 print(key.step)25 else:26 print('索引处理')27

28 def __delitem__(self, key):29 print(type(key))30 if type(key) ==slice:31 print('切片处理')32 print(key.start)33 print(key.stop)34 print(key.step)35 else:36 print('索引处理')37

38 li = Foo('alex',99)39 #切片

40 li[1:3:2] #,切片处理,1 3 2

41 li[1:3:2] = [11,22] #,切片处理,1 3 2

42 del li[2:4:2] #,切片处理,2 4 2

View Code

11、__iter__

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo():2

3 def __init__(self, name, age):4 self.name =name5 self.age =age6

7 def __iter__(self):8 return 'alex'

9

10 li = Foo('alex',18)11 #如果类中有__iter__方法,创建的类就是可迭代对象

12 #对象.__iter__()方法的返回值是一个迭代器

13 for i in li.__iter__():14 #1、执行li对象的类Foo类中的__iter__方法,并获取到其返回值alex,是一个可迭代对象

15 #2、通过li.__iter__()将返回值转换为迭代器

16 #3、然后进行循环

17 print(i) #a l e x

18 #for循环遇到迭代器,直接执行next()

19 #for循环遇到可迭代对象,先执行对象.__iter__()方法,再执行next()

View Code

12、metaclass和__new__

我们先来看一段代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 def __init__(self):3 pass

4

5 obj =Foo()6 print(type(obj)) #,表示obj对象由Foo类创建

7 print(type(Foo)) #,表示Foo类对象由type类创建

View Code

在Python中有一句话叫做:一切事物皆为对象。通过类实例化的对象是对象,而类本身也是一个对象。

通过上面这段代码以及执行结果来看,obj是通过Foo类创建的一个对象,而Foo类同样也是一个对象,它是通过type类创建的一个类对象。obj对象是通过执行Foo类的构造方法创建,那么Foo类对象是通过执行type类的构造方法创建。

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

(1)普通方式

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo():2 deffunc(self):3 print(123)4

5 obj = Foo() #实例化

6 obj.func() #调用对象中的方法

View Code

(2)特殊方式(type类的构造方法)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 deffunction():2 print('Hello,world!!')3

4 Foo = type('Foo',(object,), {'func':function})5 #type第一个参数:类名

6 #type第二个参数:当前类的父类,这个类继承哪个类

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

8 Foo.func() #调用类对象中的方法

View Code

那么,我们好奇的是既然类对象是由type类实例化产生的,那么type类内部是如何实现创建类的?类又是如何创建对象的呢?

创建类时,通过指定metaclass=派生类,用来表示该类由谁来实例化创建。所以,我们可以为metaclass设置一个type类的派生类,从而查看类创建的过程,如下:

3c455be5c5b77e7e9aeb0e568052494f.png

由MyType类来创建Foo类对象,执行MyType类中的__init__方法

执行obj = Foo(),首先执行MyType类中的__call__方法

MyType类中的__call__方法又会调用Foo类中的__new__方法创建对象obj

创建对象后再调用Foo类中的__init__方法(将obj对象当参数传入)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #type类内部实现创建类的,类创建对象

2 classMyType(type):3 def __init__(self,*args,**kwargs):4 print(123)5 def __call__(self, *args, **kwargs):6 print(456)7 obj = self.__new__(self,*args,**kwargs) #调用Foo类中的__new__方法

8 self.__init__(obj)9

10 class Foo(object,metaclass=MyType): #执行父类MyType类中的__init__方法

11 def __init__(self):12 print(111)13 def __new__(cls, *args, **kwargs): #创建obj对象

14 print(789)15 return object.__new__(cls,*args,**kwargs)16

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

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

19 obj = Foo() #执行MyType类中的__call__方法

View Code

二、反射

反射,主要指程序可以访问、检测和修改它本身状态或行为的一种能力。Python中面向对象中的反射则是指:通过字符串的形式操作对象中的成员。因Python中一切事物皆为对象,所以都可以使用反射。

1、hasattr:判断对象中是否有这个成员

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 height = 180

3 def __init__(self,name,age):4 self.name =name5 self.age =age6 defshow(self):7 return '%s-%s'%(self.name,self.age)8

9 obj = Foo('niu',99)10 print(hasattr(obj,'name')) #True,obj对象中有name这个成员

11 print(hasattr(obj,'age')) #True,obj对象中有age这个成员

12 print(hasattr(obj,'show')) #True,obj对象中有show这个成员

13 print(hasattr(obj,'long')) #False,obj对象中没有long这个成员

hasattr

2、getattr:去对象中获取某个成员

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 height = 180

3 def __init__(self,name,age):4 self.name =name5 self.age =age6 defshow(self):7 return '%s-%s'%(self.name,self.age)8

9 obj = Foo('niu',99)10 inp = input('>>>') #通过输入成员名来获取属性,这样更灵活

11 r = getattr(obj,inp) #这里r可以是name,age,height,show等

getattr

直接操作一个类,类也是一个对象:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 height = 180

3 def __init__(self,name,age):4 self.name =name5 self.age =age6 defshow(self):7 return '%s-%s'%(self.name,self.age)8

9 #直接操作类,因为类也是一个对象

10 print(getattr(Foo,'height')) #180

getattr

操作文件,文件也是一个对象:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 NAME = 'niu'

2

3 deffunc():4 return 'func'

5

6 classFoo:7 height = 180

8

9 def __init__(self,name,age):10 self.name =name11 self.age =age12

13 defshow(self):14 return '%s-%s'%(self.name,self.age)

practice.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #操作文件对象

2 importpractice3 r1 = getattr(practice,'NAME') #practice.py文件中的NAME常量

4 print(r1) #niu

5 r2 = getattr(practice,'func') #practice.py文件中的func函数

6 print(r2())#func

7 cls = getattr(practice,'Foo') #practice.py文件中的Foo类

8 obj = cls('niuren',99) #实例化

9 print(obj) #

getattr

3、setattr:给对象中设置一个成员

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 height = 180

3

4 def __init__(self,name,age):5 self.name =name6 self.age =age7

8 defshow(self):9 return '%s-%s'%(self.name,self.age)10

11 obj = Foo('niu',99)12 setattr(obj,'sex','男') #给obj对象设置一个sex成员,值为‘男’

13 print(obj.sex) #男

setattr

4、delattr:删除对象中的成员

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2 height = 180

3

4 def __init__(self,name,age):5 self.name =name6 self.age =age7

8 defshow(self):9 return '%s-%s'%(self.name,self.age)10

11 obj = Foo('niu',99)12 delattr(obj,'name') #删除obj对象中的name成员

13 print(obj.name) #'Foo' object has no attribute 'name',Foo类中没有name成员了

delattr

5、反射的应用

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 deff1():2 return '首页'

3

4 deff2():5 return '新闻'

6

7 deff3():8 return '精华'

practice.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 importpractice2 inp = input('请输入要查看的URL:')3 if hasattr(practice,inp): #输入URL来判断practice文件是否存在相应的成员

4 func = getattr(practice,inp) #如果有则获取这个成员

5 result =func()6 print(result)7 else:8 print('404') #如果不存在则返回404页面

View Code

43b4cab1f0dee5c9bb9b3b58184afb89.png

b42c224f528934021333d22ab04e9932.png

c3de6d27a3e9d1c5e0aa035f0aa18c43.png

12c8669ddc6b57d58c361ec6f7b72df4.png

三、单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classFoo:2

3 __v =None4

5 @classmethod6 defget_instance(cls):7 if cls.__v:8 return cls.__v

9 else:10 cls.__v =Foo()11 return cls.__v

12

13 #实例化时不需要再使用类名+括号,直接调用类方法get_instance

14 obj1 =Foo.get_instance()15 print(obj1) #<__main__.foo object at>

16 obj2 =Foo.get_instance()17 print(obj2) #<__main__.foo object at>

18 #创建多个对象都是同一个内存地址,说明使用的是同一个对象

View Code

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值