Python面向对象编程基础解析(二)


Posted in Python onOctober 26, 2017

Python最近挺火呀,比鹿晗薛之谦还要火,当然是在程序员之间。下面我们看看有关Python的相关内容。

上一篇文章我们已经介绍了部分Python面向对象编程基础的知识,大家可以参阅:Python面向对象编程基础解析(一),接下来,我们看看另一篇。

封装

1.为什么要封装?

封装就是要把数据属性和方法的具体实现细节隐藏起来,只提供一个接口。封装可以不用关心对象是如何构建的,其实在面向对象中,封装其实是最考验水平的

2.封装包括数据的封装和函数的封装,数据的封装是为了保护隐私,函数的封装是为了隔离复杂度

3.数据的封装就是在属性前面加一个__

class People:
 def __init__(self,name,age,salary):
  self.name=name
  self.age=age
  self.__salary=salary
p=People('zhang',19,100000)
print(p.name)#zhang
print(p.age)#19
print(p.__salary)#AttributeError: 'People' object has no attribute '__salary'

咦,报错了,让我们打开对象的名称空间,看看发生了什么

print(p.__dict__)#{'name': 'zhang', 'age': 19, '_People__salary': 100000}

哦,原来python把__salary变形成了_People__salary,再来一遍

print(p._People__salary)#100000

所以,Python中并没有绝对的隐藏,只要你知道了上面这个,就无所谓隐藏了
这些变形操作,只在类的定义阶段或者对象定义(实例化阶段)阶段发生

虽然在外部无法直接访问加了__的属性,但是在类内部可以访问到,可以这么理解,在定义阶段,只要遇到__开头的,Python解释器自动识别为_类名__属性,所以在类内部是可以访问到的,这样的话,我们就可以搞一点小事情了

先来看这个

class A:
 def foo(self):
  print('from A foo')
  self.bar()
 def bar(self):
  print('from A bar')
class B(A):
 def bar(self):
  print('from B bar')
b=B()
b.foo()  #from A foo


#from B bar 别想多了,调用函数时别看定义位置,要看调用位置

如果就是想调用父类的bar()函数呢?该怎么做

class A:
 def foo(self):
  print('from A foo')
  self.__bar()
 def __bar(self):
  print('from A bar')
class B(A):
 def __bar(self):
  print('from B bar')
b=B()
b.foo() #from A foo
  #from A bar有没有感受到编程的美妙

4.封装的应用

1)不让外界看到我们的数据属性是怎么定义的,只能通过我们提供的接口,看到我们允许外界看到的内容

class People:
 def __init__(self,name,age,height,weight,hobby):
  self.__name=name
  self.__age=age
  self.__height=height
  self.__weight=weight
  self._hobby=hobby
 def tell_info(self):
  print('''
  name:%s
  age:%s
  height:%s
  weeight:%s
  '''%(self.__name,self.__age,
    self.__height,self.__weight))
p=People('zhang',18,1.90,75,'read')
p.tell_info()

2)更常用的场景是,我们可以限制数据的类型,添加自己的逻辑以后再封装好给用户

def tell_name(self):
  print(self.__name)
 #修改名字
 def set_name(self,new):
  if not isinstance(new,str):
   raise TypeError('名字必须是字符串类型')
  self.__name=new

5.看我们上面的操作,用户查看名字的时候还得p.tell_name(),本来是个数据属性,却被我们搞得变成了一个函数,怎么伪装一下呢,就可以用到property这个装饰器了

class People:
 def __init__(self,name,age,height,weight,hobby):
  self.__name=name
  self.__age=age
  self.__height=height
  self.__weight=weight
  self._hobby=hobby
 @property
 def name(self):
  return self.__name
p=People('zhang',18,1.90,75,'read')
print(p.name)#zhang

数据属性还应该有修改,删除操作

@property
 def name(self):
  return self.__name
 #name已经被property修饰过,就有setter和deleter
 @name.setter
 def name(self,new):
  if not isinstance(new,str):
   raise TypeError('名字必须是字符串类型')
  self.__name=new
 @name.deleter
 def name(self):
  del self.__name
p = People('zhang', 18, 1.90, 75, 'read')
print(p.name)#zhang
p.name='can' #修改
print(p.name)#can
del p.name #删除
print(p.name)#AttributeError: 'People' object has no attribute '_People__name'

1.多态

多态的概念虽然现在才说,但是我们一直在用。多态就是多种形态的意思,动物都猫,狗,猪等等,这些都是动物的多种形态。

反映在Python中,多态就意味着就算不知道变量所引用的对象类型是什么,也能对它进行操作。比如序列类型有计算长度的方法len(),那我们拿到一个序列类型x,我们不需要知道x是什么类型,只需要知道它是序列类型,那我们就可以用len(x)的方法计算x的长度。这就是多态性,Python本身就是多态的

当然我们学过一个内置函数isinstance(),可以用它来判断数据类型,但是这可不符合多态优美的特性

2.绑定方法与非绑定方法

类里面定义的函数有两种,绑定方法和非绑定方法

1)绑定方法

绑定方法又分为绑定给类的方法和绑定给对象用的方法。

凡是定义在类中,且没有被任何装饰器修饰的方法,都是绑定给对象用的方法。

特点是obj.func()会自动把obj当作第一个参数传入,因为func的逻辑就是要处理obj

在类中定义的被classmethod装饰器修饰的方法,就是绑定给类的方法

特点是cls.func()会自动把类cls当作第一个参数传入,因为func的逻辑是处理cls,就算是对象调用这个函数,也是把类当成第一个参数传入

class People:
 def __init__(self,name):
  self.name=name
 def bar(self):
  print('----->',self.name)
 @classmethod
 def func(cls):
  print(cls)
p1=People('zhang')
p1.func() #<class '__main__.People'>
People.func()#<class '__main__.People'>

2)非绑定方法

还有一种方法是既不绑定给类,也不绑定给对象的,叫做非绑定方法

用staticmethod装饰器装饰

#文件名:pickle_test
import hashlib
import time
import pickle
import os
student_path=r'C:\Users\Administrator\PycharmProjects\test\student'
class People:
 def __init__(self,name,sex,user_id):
  self.name=name
  self.sex=sex
  self.user_id=user_id
  self.id = self.create_id()
 def tell_info(self):
  print('''
  --------%s info--------
  id:%s
  name:%s
  sex:%s
  user_id:%s
  ''' %(self.name,self.id,self.name,self.sex,self.user_id))
 def create_id(self):
  m=hashlib.md5()
  m.update(self.name.encode('utf-8'))
  m.update(self.sex.encode('utf-8'))
  m.update(str(self.user_id).encode('utf-8'))
  return m.hexdigest()
 def save(self):
  with open(self.id,'wb') as f:
   pickle.dump(self,f)
 @staticmethod #非绑定方法,就是一个函数,就是一个工具而已,不需要类,也不需对象
 def get_all():
  res = os.listdir(student_path)
  for item in res:
   file_path=r'%s\%s' %(student_path,item)
   with open(file_path,'rb') as f:
    obj=pickle.load(f)
    obj.tell_info()
#反序列化.py
from pickle_test import People
p=People('zhang','male',123123123)
p.get_all()

3.软件开发规范

在真正的软件开发过程中,并不是把所有代码写在一个文件中的,可以想象一下,一个小程序大概有10000行代码,都写在一个文件中的话,你还干这行吗?

正确的方式应该是把程序拆成一个一个模块。比如常用的bin目录放可执行文件,conf目录放配置文件
db目录放数据,log目录放日志文件,lib目录放库,src目录放一些重要的代码,比如重要的逻辑,类的定义等

总结

以上就是本文关于Python面向对象编程基础解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:Python探索之ModelForm代码详解、python中requests爬去网页内容出现乱码问题解决方法介绍等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
Python学习笔记之常用函数及说明
May 23 Python
python基于mysql实现的简单队列以及跨进程锁实例详解
Jul 07 Python
利用python操作SQLite数据库及文件操作详解
Sep 22 Python
Numpy的简单用法小结
Aug 28 Python
python将邻接矩阵输出成图的实现
Nov 21 Python
解析PyCharm Python运行权限问题
Jan 08 Python
Python面向对象中类(class)的简单理解与用法分析
Feb 21 Python
基于Python数据分析之pandas统计分析
Mar 03 Python
python图片剪裁代码(图片按四个点坐标剪裁)
Mar 10 Python
Python 使用 PyQt5 开发的关机小工具分享
Jul 16 Python
Python3.7安装PyQt5 运行配置Pycharm的详细教程
Oct 15 Python
python语言中pandas字符串分割str.split()函数
Aug 05 Python
Python面向对象编程基础解析(一)
Oct 26 #Python
获取Django项目的全部url方法详解
Oct 26 #Python
Python探索之ModelForm代码详解
Oct 26 #Python
启动targetcli时遇到错误解决办法
Oct 26 #Python
Mac中Python 3环境下安装scrapy的方法教程
Oct 26 #Python
python实现分页效果
Oct 25 #Python
python+pyqt实现12306图片验证效果
Oct 25 #Python
You might like
PHP 存取 MySQL 数据库的一个例子
2006/10/09 PHP
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
php实现的debug log日志操作类实例
2016/07/12 PHP
php mysql 封装类实例代码
2016/09/18 PHP
php的PDO事务处理机制实例分析
2017/02/16 PHP
php删除二维数组中的重复值方法
2018/03/12 PHP
PHP集成环境XAMPP的安装与配置
2018/11/13 PHP
PHP的PDO预定义常量讲解
2019/01/24 PHP
PHP设计模式之适配器模式(Adapter)原理与用法详解
2019/12/12 PHP
一个多次搜索+多次传值的解决方案
2007/01/20 Javascript
JavaScript获取Url里的参数
2014/12/18 Javascript
javascript实现获取浏览器版本、浏览器类型
2015/12/02 Javascript
浅析AngularJS中的指令
2016/03/20 Javascript
js获取元素的标签名实现方法
2016/10/08 Javascript
基于MVC方式实现三级联动(JavaScript)
2017/01/23 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
JavaScript基础进阶之数组方法总结(推荐)
2017/09/04 Javascript
Vue官网todoMVC示例代码
2018/01/29 Javascript
基于canvas实现手写签名(vue)
2020/05/21 Javascript
新手该如何学python怎么学好python?
2008/10/07 Python
Python内置的字符串处理函数整理
2013/01/29 Python
python模块之StringIO使用示例
2015/04/08 Python
Python实现的HTTP并发测试完整示例
2020/04/23 Python
Python使用Beautiful Soup包编写爬虫时的一些关键点
2016/01/20 Python
Python 爬虫图片简单实现
2017/06/01 Python
Python实现的视频播放器功能完整示例
2018/02/01 Python
详解Python 解压缩文件
2019/04/09 Python
使用python实现mqtt的发布和订阅
2019/05/05 Python
搞清楚 Python traceback的具体使用方法
2019/05/13 Python
django之静态文件 django 2.0 在网页中显示图片的例子
2019/07/28 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
汽车运用工程系毕业生自荐信
2013/12/27 职场文书
质监局领导班子对照检查材料思想汇报
2014/09/27 职场文书
MySql学习笔记之事务隔离级别详解
2021/05/12 MySQL
springBoot基于webSocket实现扫码登录
2021/06/22 Java/Android
Redis实战之Lettuce的使用技巧详解
2022/12/24 Redis