很有一段时间没使用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. Java 基础总结(二)

    本文参见:http://www.cnblogs.com/dolphin0520/category/361055.html 1. 字节流与和字符流 1). 字符流操作时使用了缓冲区,而在关闭字符流时会强 ...

  2. C# 字符串中正则表达式的应用

    1.截取字符串中指定内容 {"weatherinfo":{"city":"北京","cityid":"1010 ...

  3. 【hihocoder】01背包

    描述 且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了! 小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要ne ...

  4. 08/27 Django admin相关

    一.django-admin的简单回顾: admin: Django的后台数据管理的web版本 1.admin a:models.py - 创建表 b:admin.py - 注册表    admin. ...

  5. COS-7设备管理

    操作系统(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行.   操作系 ...

  6. Caffe实现多标签输入,添加数据层(data layer)

    因为之前遇到了sequence learning问题(CRNN),里面涉及到一张图对应多个标签.Caffe源码本身是不支持多类标签数据的输入的. 如果之前习惯调用脚本create_imagenet.s ...

  7. LeetCode——single-number系列

    LeetCode--single-number系列 Question 1 Given an array of integers, every element appears twice except ...

  8. BZOJ3205/UOJ107 [Apio2013]机器人

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  9. 没有服务器,关于angular路由访问静态页面chrome报错的问题

    这个找不到html,报错因为没有xhr,但是在火狐下没有问题的. 比如说ajax,直接写路径的话,我们的chrome也是不支持的,火狐可以的.

  10. X2.5 添加自定义数据调用模块(简单方法)

    Discuz!X系列的diy功能还是相当不错的,在对其进行二次开发的过程中,或许需要加入新的数据调用模块,这样可以使你开发的功能模块也像原来的模块一样,只需要点点鼠标,填写一些简单的信息,就可以在各个 ...