一、类的特殊成员

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

1、__doc__

表示类的描述信息

 class Foo:
'''
描述类信息
'''
def func(self):
pass print(Foo.__doc__) # 描述类信息

2、__module__ 和  __class__ 

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

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

 class C:
def __init__(self):
self.name = 'Jack'

/lib/practice.py

 from lib.practice import C

 obj = C()
print(obj.__module__) # lib.practice,即模块
print(obj.__class__) # <class 'lib.practice.C'>,即类

index.py

3、__init__

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

 class Foo:
def __init__(self):
print('init') obj = Foo() # init,自动执行类中的 __init__ 方法

4、__del__

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

 import pymysql
class MyDb(object):
def __init__(self,host,user,db,passwd,
port=3306,charset='utf8'): # 构造函数
try:
self.conn = pymysql.connect(
host=host,user=user,passwd=passwd,port=port,db=db,charset=charset,
autocommit=True # 自动提交
)
except Exception as e:
print('数据库连接失败!:%s'%e)
else:
self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def __del__(self): # 析构函数,实例被销毁的时候执行
self.cur.close()
self.conn.close()
print('数据库连接关闭') def ex_sql(self,sql):
try:
self.cur.execute(sql)
except Exception as e:
print('sql语句有问题:%s'%sql)
else:
self.res = self.cur.fetchall()
return self.res my = MyDb('118.24.3.40','jxz','jxz','')
my.ex_sql('select * from stu;')
print(my.res) # 可以用实例属性取值
print(my.ex_sql('select * from stu;')) # 也可以用实例方法的返回值
print('我是最后一行代码') # 执行完最后这行代码后再执行析构函数

5、__dict__

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

 class Foo():
'''
这个类是干啥的。。
'''
def __init__(self, name, age):
self.name = name
self.age = age obj = Foo('alex',99)
d = obj.__dict__ # 对象有__dict__方法,显示对象的所有成员
print(d) # {'name': 'alex', 'age': 99}
ret = Foo.__dict__ # 类也有__dict__方法,显示类的所有成员
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>}

6、__int__

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

 class Foo:
def __init__(self): # 构造方法
print('init') def __int__(self):
return 1 obj = Foo() # init,创建对象时自动执行构造方法
r = int(obj) # int后面加上一个对象(obj),它就会自动执行对象(obj)当中的__int__方法,并将返回值赋给int对象(r是int的对象)
print(r) #
print(type(r))# <class 'int'>,r是int类的对象

7、__str__

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

 class Foo:
def __init__(self): # 构造方法
print('init') def __str__(self):
return 'niu' obj = Foo() #init,创建对象时自动执行构造方法
print(obj,type(obj)) # <__main__.Foo object at 0x00000236A19CD278> <class '__main__.Foo'>,obj的类型是Foo类
# niu <class '__main__.Foo'>,类中加上__str__()后的返回
# print()函数在执行时会自动调用对象中的__str__()方法,所以Foo类中加上__str__()方法之前显示为内存地址,加上__str__()方法之后,显示为__str__()方法的返回值‘niu’
# print(obj)相当于print(str(obj))
s = str(obj) # str后面加上一个对象(obj),它就会自动执行对象(obj)当中的__str__方法,并将返回值赋给str对象(s是str的对象)
print(s)

8、__add__

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

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

9、__call__

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

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

 class Foo:
def __init__(self): # 构造方法
print('init') def __call__(self, *args, **kwargs):
print('call') obj = Foo() #init,创建对象时自动执行构造方法
obj() #call,对象后面加括号直接调用类中的__call__()方法

10、__getitem__、__setitem__、__delitem__

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

 class Foo():

     def __init__(self, name, age):
self.name = name
self.age = age def __getitem__(self, item):
print(item + 10) def __setitem__(self, key, value):
print(key, value) def __delitem__(self, key):
print(key) li = Foo('alex',99)
# 索引
li[8] # 自动执行li对象的类中__getitem__方法,8当作参数传递给item
li[100] = 123 # 自动执行li对象的类中__setitem__方法,100和123当作参数传递给key和value
del li[99] # 自动执行li对象的类中__delitem__方法,99当作参数传递给key
 class Foo():

     def __init__(self, name, age):
self.name = name
self.age = age def __getitem__(self, item):
# 如果item是基本类型,int,str索引获取
# 如果item类型是slice,切片
print(type(item))
if type(item) == slice: # 切片是slice类型
print('切片处理')
print(item.start)
print(item.stop)
print(item.step)
else:
print('索引处理')
def __setitem__(self, key, value):
print(type(key))
if type(key) == slice:
print('切片处理')
print(key.start)
print(key.stop)
print(key.step)
else:
print('索引处理') def __delitem__(self, key):
print(type(key))
if type(key) == slice:
print('切片处理')
print(key.start)
print(key.stop)
print(key.step)
else:
print('索引处理') li = Foo('alex',99)
# 切片
li[1:3:2] # <class 'slice'>,切片处理,1 3 2
li[1:3:2] = [11,22] # <class 'slice'>,切片处理,1 3 2
del li[2:4:2] # <class 'slice'>,切片处理,2 4 2

11、__iter__

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

 class Foo():

     def __init__(self, name, age):
self.name = name
self.age = age def __iter__(self):
return 'alex' li = Foo('alex',18)
# 如果类中有__iter__方法,创建的类就是可迭代对象
# 对象.__iter__()方法的返回值是一个迭代器
for i in li.__iter__():
# 1、执行li对象的类Foo类中的__iter__方法,并获取到其返回值alex,是一个可迭代对象
# 2、通过li.__iter__()将返回值转换为迭代器
# 3、然后进行循环
print(i) # a l e x
# for循环遇到迭代器,直接执行next()
# for循环遇到可迭代对象,先执行对象.__iter__()方法,再执行next()

12、metaclass和__new__

我们先来看一段代码:

 class Foo:
def __init__(self):
pass obj = Foo()
print(type(obj)) #<class '__main__.Foo'>,表示obj对象由Foo类创建
print(type(Foo)) #<class 'type'>,表示Foo类对象由type类创建

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

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

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

(1)普通方式

 class Foo():
def func(self):
print(123) obj = Foo() # 实例化
obj.func() # 调用对象中的方法

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

 def function():
print('Hello,world!!') Foo = type('Foo',(object,), {'func':function})
# type第一个参数:类名
# type第二个参数:当前类的父类,这个类继承哪个类
# type第三个参数:类的成员
Foo.func() # 调用类对象中的方法

那么,我们好奇的是既然类对象是由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对象当参数传入)
 # type类内部实现创建类的,类创建对象
class MyType(type):
def __init__(self,*args,**kwargs):
print(123)
def __call__(self, *args, **kwargs):
print(456)
obj = self.__new__(self,*args,**kwargs) # 调用Foo类中的__new__方法
self.__init__(obj) class Foo(object,metaclass=MyType): # 执行父类MyType类中的__init__方法
def __init__(self):
print(111)
def __new__(cls, *args, **kwargs): # 创建obj对象
print(789)
return object.__new__(cls,*args,**kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建object对象
obj = Foo() # 执行MyType类中的__call__方法

二、反射

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

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

 class Foo:
height = 180
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
return '%s-%s'%(self.name,self.age) obj = Foo('niu',99)
print(hasattr(obj,'name')) # True,obj对象中有name这个成员
print(hasattr(obj,'age')) # True,obj对象中有age这个成员
print(hasattr(obj,'show')) # True,obj对象中有show这个成员
print(hasattr(obj,'long')) # False,obj对象中没有long这个成员

hasattr

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

 class Foo:
height = 180
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
return '%s-%s'%(self.name,self.age) obj = Foo('niu',99)
inp = input('>>>') # 通过输入成员名来获取属性,这样更灵活
r = getattr(obj,inp) # 这里r可以是name,age,height,show等

getattr

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

 class Foo:
height = 180
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
return '%s-%s'%(self.name,self.age) # 直接操作类,因为类也是一个对象
print(getattr(Foo,'height')) #

getattr

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

 NAME = 'niu'

 def func():
return 'func' class Foo:
height = 180 def __init__(self,name,age):
self.name = name
self.age = age def show(self):
return '%s-%s'%(self.name,self.age)

practice.py

 # 操作文件对象
import practice
r1 = getattr(practice,'NAME') # practice.py文件中的NAME常量
print(r1) # niu
r2 = getattr(practice,'func') # practice.py文件中的func函数
print(r2())# func
cls = getattr(practice,'Foo') # practice.py文件中的Foo类
obj = cls('niuren',99) # 实例化
print(obj) # <practice.Foo object at 0x0000022C19E9DA58>

getattr

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

 class Foo:
height = 180 def __init__(self,name,age):
self.name = name
self.age = age def show(self):
return '%s-%s'%(self.name,self.age) obj = Foo('niu',99)
setattr(obj,'sex','男') # 给obj对象设置一个sex成员,值为‘男’
print(obj.sex) # 男

setattr

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

 class Foo:
height = 180 def __init__(self,name,age):
self.name = name
self.age = age def show(self):
return '%s-%s'%(self.name,self.age) obj = Foo('niu',99)
delattr(obj,'name') # 删除obj对象中的name成员
print(obj.name) # 'Foo' object has no attribute 'name',Foo类中没有name成员了

delattr

5、反射的应用

 def f1():
return '首页' def f2():
return '新闻' def f3():
return '精华'

practice.py

 import practice
inp = input('请输入要查看的URL:')
if hasattr(practice,inp): # 输入URL来判断practice文件是否存在相应的成员
func = getattr(practice,inp) # 如果有则获取这个成员
result = func()
print(result)
else:
print('') # 如果不存在则返回404页面

三、单例模式

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

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

 class Foo:

     __v = None

     @classmethod
def get_instance(cls):
if cls.__v:
return cls.__v
else:
cls.__v = Foo()
return cls.__v # 实例化时不需要再使用类名+括号,直接调用类方法get_instance
obj1 = Foo.get_instance()
print(obj1) # <__main__.Foo object at 0x000001B0C8C0D278>
obj2 = Foo.get_instance()
print(obj2) # <__main__.Foo object at 0x000001B0C8C0D278>
# 创建多个对象都是同一个内存地址,说明使用的是同一个对象

Python学习之==>面向对象编程(二)的更多相关文章

  1. Python进阶之面向对象编程(二)

    Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...

  2. 从0开始的Python学习014面向对象编程

     简介 到目前为止,我们的编程都是根据数据的函数和语句块来设计的,面向过程的编程.还有一种我们将数据和功能结合起来使用对象的形式,使用它里面的数据和方法这种方法叫做面向对象的编程. 类和对象是面向对象 ...

  3. Python学习--10 面向对象编程

    面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 本节对于面向对象的概念不做 ...

  4. Python学习之==>面向对象编程(一)

    一.面向对象与面向过程 面向对象与面向过程是两种不同的编程范式,范式指的是按照什么方式去编程.去实现一个功能.不同的编程范式本质上代表对各种不同类型的任务采取不同的解决问题的思路. 1.面向过程编程 ...

  5. python之路---面向对象编程(二)

    类的继承 1.在python3中,只有新式类,新式类的继承方式为:广度优先.而python2中,经典类的继承方式为:深度优先.那么我们来看看深度优先和广度优先的区别吧 如下图,为类之间的继承关系.B, ...

  6. Python入门之面向对象编程(二)python类的详解

    本文通过创建几个类来覆盖python中类的基础知识,主要有如下几个类 Animal :各种属性.方法以及属性的修改 Dog :将方法转化为属性并操作的方法 Cat :私人属性讲解,方法的继承与覆盖 T ...

  7. python学习_数据处理编程实例(二)

    在上一节python学习_数据处理编程实例(二)的基础上数据发生了变化,文件中除了学生的成绩外,新增了学生姓名和出生年月的信息,因此将要成变成:分别根据姓名输出每个学生的无重复的前三个最好成绩和出生年 ...

  8. Python 中的面向对象编程

    面向对象编程(Object-oriented programming, OOP)是一种基于对象概念的编程范式,可包含属性(attribute)形式的数据以及方法(method)形式的代码.另一种对 O ...

  9. 《Python学习手册》(二)

    <Python学习手册>(二) --类型和运算 数字 十六进制 八进制 二进制 0x 0o 0b hex() oct() bin() >>>int('10',2) 2 & ...

随机推荐

  1. PHP的函数获取图片的宽高等信息

    PHP的函数getimagesize可以得到图片的宽高等信息 array getimagesize ( string $filename [, array &$imageinfo ] )   ...

  2. Lambda学习总结(二)--Stream流

    一.Stream 流 1.1 概念 官方解释:可以支持顺序和并行对元素操作的元素集合. 简单来讲,Stream 就是 JDK8 提供给我们的对于元素集合统一.快速.并行操作的一种方式. 它能充分运用多 ...

  3. char()和VARCHAR()的主要区别是什么?

    1.char的长度是不可变的,而varchar的长度是可变的 字段b:类型char(10),     值为:abc,存储为:abc             (abc+7个空格) 字段d:类型varch ...

  4. 【LuoguP5328】[ZJOI2019]浙江省选

    题目链接 题意 给你一堆斜率和纵截距都为正的直线 ,求对于一个条直线是否存在一个 x 使得在这条直线在 x 处能是前 m 大,输出最高能够达到的排名(排名定义为在 x 处严格大于自己的直线条数+1) ...

  5. kubernetes运用

    1:kubernetes基本介绍 kubernetes 是一个开源的容器集群管理系统,K8s用于容器化应用程序的部署 扩展和管理,提供容器编排 资源调度 弹性伸缩 部署管理  服务发现等一系列功能. ...

  6. 千万级别数据量mysql优化策略

    表结构优化 1.  使用独立表空间 独立表空间指的是innodb表的一种数据结构 独占表空间:  每一个表都将会生成以独立的文件方式来进行存储,每一个表都有一个.frm表描述文件,还有一个.ibd文件 ...

  7. jdk,jre下载安装

    JDK安装https://blog.csdn.net/u012934325/article/details/73441617/jre需要手动生成在JDK安装目录下,的bin cmd执行bin\ jli ...

  8. CMS 与 框架

    Framework:框架.是整合的工具集,基于编程语言.可以帮助我们快速开发网站.比较常见的是J2EE(基于Java),Symfony2(基于PHP),Django(基于Python),Ruby on ...

  9. 微信小程序开发整理

    具体介绍包含以下内容: 1.文件结构 2.组件 4.API 4.工具 5.问题

  10. cp:复制文件和目录

    cp 命令,主要用来复制文件和目录,同时借助某些选项,还可以实现复制整个目录,以及比对两文件的新旧而予以升级等功能. cp 命令的基本格式如下:cp [选项] 源文件 目标目录/文件 选项: -a:相 ...