Python学习之==>面向对象编程(二)

一、类的特殊成员

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

1、__doc__

表示类的描述信息

1 class Foo:
2     '''
3     描述类信息
4     '''
5     def func(self):
6         pass
7 
8 print(Foo.__doc__)  # 描述类信息
View Code

2、__module__ 和  __class__ 

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

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

1 class C:
2     def __init__(self):
3         self.name = 'Jack'
/lib/practice.py
1 from lib.practice import C
2 
3 obj = C()
4 print(obj.__module__) # lib.practice,即模块
5 print(obj.__class__)  # <class 'lib.practice.C'>,即类
index.py

3、__init__

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

1 class Foo:
2     def __init__(self):
3         print('init')
4 
5 obj = Foo()  # init,自动执行类中的 __init__ 方法
View Code

4、__del__

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

扫描二维码关注公众号,回复: 4901539 查看本文章
 1 import pymysql
 2 class MyDb(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         except Exception 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     def ex_sql(self,sql):
21         try:
22             self.cur.execute(sql)
23         except Exception as e:
24             print('sql语句有问题:%s'%sql)
25         else:
26             self.res = self.cur.fetchall()
27             return self.res
28 
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__

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

 1 class Foo():
 2     '''
 3     这个类是干啥的。。
 4     '''
 5     def __init__(self, name, age):
 6         self.name = name
 7         self.age = age
 8 
 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__': <function Foo.__init__ at 0x000001EBA9FAF1E0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
View Code

6、__int__

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

 1 class Foo:
 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))# <class 'int'>,r是int类的对象
View Code

7、__str__

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

 1 class Foo:
 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 0x00000236A19CD278> <class '__main__.Foo'>,obj的类型是Foo类
10                       # niu <class '__main__.Foo'>,类中加上__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__方法,那么在两个对象进行相加时,返回的是该方法的返回值

 1 class Foo:
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __add__(self, other):
 7         return self.age + other.age
 8 
 9 obj1 = Foo('alex', 19)
10 obj2 = Foo('hiro', 55)
11 r = obj1 + obj2  # 两个对象相加时,自动执行第一个对象的__add__方法,并且将第二个对象当参数传入
12 print(r, type(r))# 74 <class 'int'>
View Code

9、__call__

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

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

 1 class Foo:
 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__

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

 1 class Foo():
 2 
 3     def __init__(self, name, age):
 4         self.name = name
 5         self.age = age
 6 
 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
 1 class Foo():
 2 
 3     def __init__(self, name, age):
 4         self.name = name
 5         self.age = age
 6 
 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]  # <class 'slice'>,切片处理,1 3 2
41 li[1:3:2] = [11,22] # <class 'slice'>,切片处理,1 3 2
42 del li[2:4:2] # <class 'slice'>,切片处理,2 4 2
View Code

11、__iter__

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

 1 class Foo():
 2 
 3     def __init__(self, name, age):
 4         self.name = name
 5         self.age = age
 6 
 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__

我们先来看一段代码:

1 class Foo:
2     def __init__(self):
3         pass
4 
5 obj = Foo()
6 print(type(obj))  #<class '__main__.Foo'>,表示obj对象由Foo类创建
7 print(type(Foo))  #<class 'type'>,表示Foo类对象由type类创建
View Code

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

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

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

(1)普通方式

1 class Foo():
2     def func(self):
3         print(123)
4 
5 obj = Foo()  # 实例化
6 obj.func()   # 调用对象中的方法
View Code

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

1 def function():
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类的派生类,从而查看类创建的过程,如下:

  1. 由MyType类来创建Foo类对象,执行MyType类中的__init__方法
  2. 执行obj = Foo(),首先执行MyType类中的__call__方法
  3. MyType类中的__call__方法又会调用Foo类中的__new__方法创建对象obj
  4. 创建对象后再调用Foo类中的__init__方法(将obj对象当参数传入)
 1 # type类内部实现创建类的,类创建对象
 2 class MyType(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:判断对象中是否有这个成员

 1 class Foo:
 2     height = 180
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6     def show(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:去对象中获取某个成员

 1 class Foo:
 2     height = 180
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6     def show(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

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

 1 class Foo:
 2     height = 180
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6     def show(self):
 7         return '%s-%s'%(self.name,self.age)
 8 
 9 # 直接操作类,因为类也是一个对象
10 print(getattr(Foo,'height'))  # 180
getattr

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

 1 NAME = 'niu'
 2 
 3 def func():
 4     return 'func'
 5 
 6 class Foo:
 7     height = 180
 8 
 9     def __init__(self,name,age):
10         self.name = name
11         self.age = age
12 
13     def show(self):
14         return '%s-%s'%(self.name,self.age)
practice.py
1 # 操作文件对象
2 import practice
3 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) # <practice.Foo object at 0x0000022C19E9DA58>
getattr

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

 1 class Foo:
 2     height = 180
 3 
 4     def __init__(self,name,age):
 5         self.name = name
 6         self.age = age
 7 
 8     def show(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:删除对象中的成员

 1 class Foo:
 2     height = 180
 3 
 4     def __init__(self,name,age):
 5         self.name = name
 6         self.age = age
 7 
 8     def show(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、反射的应用

1 def f1():
2     return '首页'
3 
4 def f2():
5     return '新闻'
6 
7 def f3():
8     return '精华'
practice.py
1 import practice
2 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

三、单例模式

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

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

 1 class Foo:
 2 
 3     __v = None
 4 
 5     @classmethod
 6     def get_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 0x000001B0C8C0D278>
16 obj2 = Foo.get_instance()
17 print(obj2)  # <__main__.Foo object at 0x000001B0C8C0D278>
18 # 创建多个对象都是同一个内存地址,说明使用的是同一个对象
View Code

猜你喜欢

转载自www.cnblogs.com/L-Test/p/10252954.html