Python面对对象相关知识总结

很有一段时间没使用python了,前两天研究微信公众号使用了下python的django服务,感觉好多知识都遗忘了,毕竟之前没有深入的实践,长期不使用就忘得快。本博的主要目的就是对Python中我认为

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

  很有一段时间没使用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类,它的定义非常简单,几乎什么行为都不包括。

  Python面对对象相关知识总结

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

  Python2 没有默认继承object

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

2. Python中类和对象的区别

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

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

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

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

        
student1 = People("张三",20)
student2 = People("李四",25)

print(student2.name)
print(student2.money)
print(People.money)
print(People.name)

Python面对对象相关知识总结

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

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

Python面对对象相关知识总结

  说明:对象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))

 Python面对对象相关知识总结

  说明: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 = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

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

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

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

  除非在子类中也定义__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",18,"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))

 Python面对对象相关知识总结

(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()

Python面对对象相关知识总结

(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-8 -*-
 
class A(object):
    bar = 1
    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-8 -*-
 
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 = 16
    
print(People.__dict__)
p = People()
print(p.__dict__)

Python面对对象相关知识总结

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

4. 抽象基类和继承

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120072.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 谷歌离线地图包下载安卓版_谷歌地图 app

    谷歌离线地图包下载安卓版_谷歌地图 appGoogle离线地图发布文档一键离线地图发布(工具软件下载)  使用教程百度离线地图发布  教程 手机离线地图发布——Oruxmaps制作发布高清卫星离线地图谷歌离线地图发布API解析说明:1. 当前版本支持谷歌电子/卫星地图瓦片、高德地图、阿里云地图、超图、腾讯地图等(只需下载该地图源的瓦片拷贝到指定目录即可);2. 效果预览

  • Traceroute原理「建议收藏」

    Traceroute原理「建议收藏」通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径。当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一样,但基本上来说大部分时候所走的路由是相同的。linux系统中,我们称之为traceroute,在MSWindows中为tracert。traceroute通过发送小的数据包到目的设备直到其返回,来测量其需要多长时间。一条路径上的每个设备traceroute要测3次。输出结果中包括每次测试的时间(ms)和

  • form factor_perform和performance的区别和用法

    form factor_perform和performance的区别和用法performSelector:withObject:是在iOS中的一种方法调用方式。他可以向一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以这也是runtime的一种应用方式。performSelector和直接调用方法的区别就在与runtime。直接调用编译是会自动校验。如果方法不存在,那么直接调用在编译时候就能够发现,编译器会直接报错。但是使用performSelec…

    2022年10月24日
  • 解析MP4文件中的sps和pps[通俗易懂]

    解析MP4文件中的sps和pps[通俗易懂]一、MP4格式基本概念MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二、MP4封装格式核心概念1 MP4封装格式对应标准为ISO/IEC14496-12(信息技术视听对象编码的第12部分:ISO基本媒体文件格式/InformationtechnologyCodingofaudio-visualobjectsPart12

  • java trylock_lock.tryLock()方法的使用

    java trylock_lock.tryLock()方法的使用packageconcurrent;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassTestTryLock{privateListlist=…

    2022年10月16日
  • python set转为list_python 怎么把set转成list

    python set转为list_python 怎么把set转成list今天小就为大家分享一篇python-list,set间的转换实例,具有很好的参考价值,推荐手册:Python基础入门教程其实python中,set转list的非常的简单,直接将set的值放入list()的括号中即可,相反,list转set也同样如此。(推荐学习:Python视频教程)>>>s=set(‘123456’)>>>print(s){‘6’,’4…

    2022年10月18日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号