很有一段时间没使用python了,前两天研究微信公众号使用了下python的django服务,感觉好多知识都遗忘了,毕竟之前没有深入的实践,长期不使用就忘得快。本博的主要目的就是对Python中我认为重要的面对对象知识进行总结,一是加深记忆,而是方便日后遗忘了好迅速的捡起来。

  目录索引:

  (1)隐式的基类object

  (2)python中类和对象的区别

  (3)实现python风格类所用特殊方法

    (a)__all__和__slots__

    (b)__format__()、__repr__()和__str__()

    (c)__init__()方法

    (d)__new__()和__del__()

    (e)__call__()方法

    (f)属性访问、特性和修饰符

    (g)@classmethod和@staticmethod

    (h)关于私有属性的说法

  (4)抽象基类和继承

1. 隐式的基类object

  每个Python类的定义都回隐式继承自object类,它的定义非常简单,几乎什么行为都不包括。

  

  可以看到类定义就是对type类的一个对象的类型声明,基类为object,相应的派生自object类中的对象方法也将继承各自相应的默认实现,在某些情况下,基类中一些特殊方法的默认行为也正是我们想要的,对于一些特殊情况,就需要重写这些方法。

  Python2 没有默认继承object

  Python3 默认全部继承object类,都是新式类

2. Python中类和对象的区别

(1)类属性和对象属性的区别

  对象可以通过 对象名.属性名 调用对象属性和类属性

  类可以通过 类名.属性名 调用类的属性,但是不能调用对象的属性

class People(object):
# 类属性是指定义在类的内部而且在方法的外部的属性
money =
def __init__(self,name,age,gender=):
# 对象属性是指定义在方法的内部的属性,例如本例中
# name,age和gender都是对象属性
self.name = name
self.age = age
self.gender = gender student1 = People("张三",)
student2 = People("李四",) print(student2.name)
print(student2.money)
print(People.money)
print(People.name)

  再注意看下面代码输出结果:

print(id(student1.money))
print(id(student2.money))
print(id(People.money))

  说明:对象student1、student2和类People的属性money的内存地址都是相同的

  继续往下看

student1.money -= 1000
print("student1.money:", student1.money)
print("student1.money id:",id(student1.money))
print("student2.money:", student2.money)
print("student2.money id:",id(student2.money))
print("People.money id:",id(People.money))

  说明:student1引用的money属性的内存地址已经和另外两个的不一样了而另外两个的内存地址却还是一样的

  原因:在经过表达式student1.money -= 1000 的过程时,会先在对象中查找是否有money这个属性,如果有的话,则直接进行运算如果没有,则会去类中查找是否有money属性,如果在类中找到money属性,那么student1就会创建一个对象属性money,在第二次调用的时候就会调用自己的对象属性,而不是类People中的属性了,而student2因为没有经过运算,所以不会创建自己的money属性,而是引用类People的属性,所以student2和People引用的还是同一个属性

3. 实现python风格类所用特殊方法

(a)__all__和__slots__

  关于__all__ = []总结两点:

  A:在__init__.py文件中 

表示形式:
__all__=["module_a","module_b"]
在使用 from package_name import * 时 , 表示import 该package 中的 两个module及 两个module相关的类、方法等。

  B:在普通的*.py中

表示形式:
__all__=["class_name","function_name"]
在使用 from module_name import * 时,表示import 该module中的__all__中所列出的。

  __slots__使用:

  如果我们想限制一个类的属性怎么办?比如只允许对Student实例添加name和age属性,为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量来限制class能添加的属性

>>> class Student(object):
... __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
... >>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = # 绑定属性'age'
>>> s.score = # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line , in <module>
AttributeError: 'Student' object has no attribute 'score'

  由于score没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError错误

  注意:__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的 

>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score =

  除非在子类中也定义__slots__,这样子类允许定义的属性就是自身的__slots__加上父类的__slots__

(b)__format__()、__repr__()和__str__()

  上面的三个方法都是为了为Python对象提供一个很好的字符串表示

  通常str()方法表示的对象对用户更加友好,这个方法由__str__()实现

  repr()方法的表示通常会被更加技术化,这个方法由__repr__()实现

  {!r} 调用__repr__方法

  {!s} 调用__str__方法

  string.format()和内置的format()函数都使用__format()__方法,都是为了获得给定对象的一个符合要求的字符串表示

  直接上例子能更好的进行说明:

class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex def __str__(self):
#return "{__class__.__name__}(name={0},age={1},sex={2})" .format(self.name,self.age,self.sex,__class__=self.__class__)
return "__str__:(name={name},age={age},sex={sex})" .format(__class__=self.__class__,**self.__dict__) def __repr__(self):
return "__repr__:{__class__.__name__}(name={name},age={age},sex={sex})" .format(__class__=self.__class__,**self.__dict__) def __format__(self, format_spec):
if format_spec == "":
return str(self)
return format_spec.replace("%n",self.name).replace("%s",self.sex) if __name__ == "__main__":
people = People("john",,"man")
print("{0!s}".format(people))
print("{0!r}".format(people))
print("format:",format(people,"%n-%s"))
print("__format__:",people.__format__("%n-%s"))
print("format:",format(people))

(c)__init__()方法

  __init__(self)就如同类的构造函数,尽量在构造函数中实现属性清单,这里就不多做介绍

  下面主要总结下Python继承中super()方法的使用:

  super实现原理:通过c3算法,生成mro(method resolution order)列表,根据列表中元素顺序查询调用新式类调用顺序为广度优先,旧式类为深度优先
  super类似于嵌套的一种设计,当代码执行到super实例化后,先去找同级父类,若没有其余父类,再执行自身父类,再往下走,简单说就是子类在父类前,所有类不重复调用,从左到右(见下面例子的D.mro()打印)

  Python2 super调用 super(开始类名,self).函数名()

  Python3  super().函数名()

  上例子更能说明上述问题:

class A():
def go(self):
print ("go A go!")
def stop(self):
print ("stop A stop!")
def pause(self):
raise Exception("Not Implemented")
class B(A):
def go(self):
super(B, self).go()
print ("go B go!")
class C(A):
def go(self):
super(C, self).go()
print ("go C go!")
def stop(self):
super(C, self).stop()
print ("stop C stop!")
class D(B,C):
def go(self):
super(D, self).go()
print ("go D go!")
def stop(self):
super(D, self).stop()
print ("stop D stop!")
def pause(self):
print ("wait D wait!")
class E(B,C):
pass a = A()
b = B()
c = C()
d = D()
e = E()
# 说明下列代码的输出结果
d.go()
print('--------')
e.go()
print('--------')
d.stop()
print('--------')
e.stop()
print(D.mro())
a.pause()
b.pause()
c.pause()
d.pause()
e.pause()

(d)__new__()和__del__()

  __ new__ ()在__ init__()之前被调用,用于生成实例对象.利用这个方法和类属性的特性可以实现设计模式中的单例模式.单例模式是指创建唯一对象吗,单例模式设计的类只能实例化一个对象.

class Singleton(object):
__instance = None # 定义实例 def __init__(self):
pass def __new__(cls, *args, **kwd): # 在__init__之前调用
if Singleton.__instance is None: # 生成唯一实例
Singleton.__instance = object.__new__(cls, *args, **kwd)
return Singleton.__instance

  __new__()方法的使用和Python元编程相关,可以查看我之前的博客:Python元编程

  __del__()方法涉及到Python对象销毁,Python文档中用不稳定性来描述__del__()方法的这种行为,并且提供了额外的关于异常处理的注释,总之,该函数的使用要慎重之慎重。

  __ del__称作析构方法
  析构方法,当对象在内存中被释放时,自动触发执行。
  注:此方法一般无须定义,因为在Python中,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。在程序执行结束之后,执行此方法

(e)__call__()方法

  Python可调用对象:函数,方法,使用 yield 关键字的函数或方法,类的实例

  __call__方法将类的实例变成可调用对象

>>>class Reader():
    def __init__(self,name,nationality):
      self.name = name
      self.nationality = nationality
    def __call__(self):
      print('Reader: %s Nationality: %s' % (self.name, self.nationality))
>>>r = Reader('Annie','Chinese')
>>>r()
Reader:Annie Nationality: Chinese

(f)属性访问、特性和修饰符

  之前的博客Python之属性、特性和修饰符作了详细说明

(g)@classmethod和@staticmethod

  classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。

#!/usr/bin/python
# -*- coding: UTF- -*- class A(object):
bar =
def func1(self):
print ('foo')
@classmethod
def func2(cls):
print ('func2')
print (cls.bar)
cls().func1() # 调用 foo 方法 A.func2() # 不需要实例化

  staticmethod修饰符实现静态方法,该方法不强制要求传递参数

#!/usr/bin/python
# -*- coding: UTF- -*- class C(object):
@staticmethod
def f():
print('runoob'); C.f(); # 静态方法无需实例化
cobj = C()
cobj.f() # 也可以实例化后调用

(h)关于私有属性的说法

  Python并没有真正的私有化支持,但可用下划线得到伪私有

  个人习惯:

  (1)_XXX 单下划代表protected

  (2)__XXX 双下划线开始的且不以_结尾表示private(下面说明)

  (3)__XXX__系统定义的属性和方法

  看下面的例子:

class People:
__name="zhanglin" def __init__(self):
self.__age = print(People.__dict__)
p = People()
print(p.__dict__)

  会发现__name和__age属性名都发生了变化,都变成了(_类名+属性名),只有在__XXX这种命名方式下才会发生变化,所以以这种方式作为伪私有说明

4. 抽象基类和继承

  该主题内容请查看之前的博客:Python之抽象基类

Python面对对象相关知识总结的更多相关文章

  1. Python - 面对对象(其他相关,异常处理,反射,单例模式,等..)

    目录 Python - 面对对象(其他相关,异常处理,反射,等..) 一.isinstance(obj, cls) 二.issubclass(sub, super) 三.异常处理 1. 异常处理 2. ...

  2. Python - 面对对象(基础)

    目录 Python - 面对对象(基础) 一. 概述 二. 创建类和对象 三. 面向对象三大特征 封装 继承 多态 Python - 面对对象(基础) 一. 概述 面向过程:根据业务逻辑从上到下写垒代 ...

  3. Python - 面对对象(进阶)

    目录 Python - 面对对象(进阶) 类的成员 一. 字段 二. 方法 三. 属性 类的修饰符 类的特殊成员 Python - 面对对象(进阶) 类的成员 一. 字段 字段包括:普通字段和静态字段 ...

  4. 小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系)

    小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系 1. 依赖关系. 最轻的一种关系 在方法中引入另一个类的对象 class Elephant: def __init__(sel ...

  5. 小学生绞尽脑汁也学不会的python(面对对象-----成员)

    小学生绞尽脑汁也学不会的python(面对对象-----成员) 成员 class Person: def __init__(self, name, num, gender, birthday): # ...

  6. 16、python面对对象之类和继承

    前言:本文主要介绍python面对对象中的类和继承,包括类方法.静态方法.只读属性.继承等. 一.类方法 1.类方法定义 使用装饰器@classmethod装饰,且第一个参数必须是当前类对象,该参数名 ...

  7. 15、python面对对象之类和对象

    前言:本文主要介绍python面对对象中的类和对象,包括类和对象的概念.类的定义.类属性.实例属性及实例方法等. 一.类和对象的概念 问题:什么是类?什么是实例对象? 类:是一类事物的抽象概念,不是真 ...

  8. python面对对象编程------4:类基本的特殊方法__str__,__repr__,__hash__,__new__,__bool__,6大比较方法

    一:string相关:__str__(),__repr__(),__format__() str方法更面向人类阅读,print()使用的就是str repr方法更面对python,目标是希望生成一个放 ...

  9. python面对对象编程----2:__init__

    面对对象编程估计我们最早接触到的就是__init__了,也就是实例的初始化处理过程: 1:来看看最基础的__init__ class Card(object): #抽象类Card,并不用于实例化 de ...

随机推荐

  1. Spring4.2.3+Hibernate4.3.11整合( IntelliJ maven项目)(使用Annotation注解)(Junit测试类)

    1. 在IntelliJ中新建maven项目 给出一个建好的示例 2. 在pom.xml中配置依赖 包括: spring-context spring-orm hibernate-core mysql ...

  2. SVN更新的时候报断言失败解决办法

    解决办法:没啥好方法,重新检出代码就好使了.

  3. 2062326 齐力锋 实验三《敏捷开发与XP实践》实验报告

    北京电子科技学院(BESTI) 实 验 报 告 课程: 程序设计与数据结构 班级: 1623 姓名: 齐力锋 学号: 20162326 成绩: 指导教师: 娄嘉鹏/王志强 实验日期: 2017年5月1 ...

  4. C++中int转为char 以及int 转为string和string 转int和字符串的split

    1.对于int 转为char 直接上代码: 正确做法: void toChar(int b) { char u; ]; _itoa( b, buffer, ); //正确解法一 u = buffer[ ...

  5. bzoj 2748: [HAOI2012]音量调节

    2748: [HAOI2012]音量调节 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 872  Solved: 577[Submit][Status] ...

  6. Docker在渗透中的应用

    起因 环境因素影响,我他么路由器映射端口 msf就是反弹不回来session,在跟大牛交流后,大牛说服务器装个kali就行了,我以为是叫idc那边直接安装,但是因为这个系统特殊,很多 idc不允许安装 ...

  7. 电脑 HOST 文件

    路径: C:\Windows\System32\drivers\etc\HOSTS

  8. IDEA 修改JSP和后端数据后,页面刷新可以实时更新

    情况:刚开始使用IDEA进行开发时,发现修改JSP页面或者后端数据后,再刷新浏览器页面,发现没有变化,页面无更新. 这样就导致不得不频繁重启tomcat服务器.非常麻烦 解决方法: 步骤1. 先设置t ...

  9. 用TestPMD测试DPDK性能和功能

    本文介绍了数据平面开发工具包(DPDK)TestPMD应用程序,展示了如何构建和配置TestPMD, 以及如何用它来检查使用DPDK的不同网络设备的性能和功能. TestPMD是一个使用DPDK软件包 ...

  10. 初探UiAutomator2.0中使用Xpath定位元素

    J 今天的主题是讲一下在使用过程中遇到的一个问题,如何在UiAutomator2.0中使用Xpath定位元素? 背景 现在的app在打包成apk的时候都是有加固处理的,各种混淆加固,所以已经破坏了或扰 ...