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获取DLL和EXE文件版本号的方法
Mar 10 Python
Python数据类型详解(一)字符串
May 08 Python
Python找出最小的K个数实例代码
Jan 04 Python
详解flask入门模板引擎
Jul 18 Python
python3转换code128条形码的方法
Apr 17 Python
python定时按日期备份MySQL数据并压缩
Apr 19 Python
详解用Python为直方图绘制拟合曲线的两种方法
Aug 21 Python
Python3搭建http服务器的实现代码
Feb 11 Python
浅谈Python中文件夹和python package包的区别
Jun 01 Python
Python内置函数及功能简介汇总
Oct 13 Python
Python实现的扫码工具居然这么好用!
Jun 07 Python
Python3.8官网文档之类的基础语法阅读
Sep 04 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 在windows下配置虚拟目录的方法介绍
2013/06/26 PHP
教大家制作简单的php日历
2015/11/17 PHP
PHP 将dataurl转成图片image方法总结
2016/10/14 PHP
php语言注释,单行注释和多行注释
2018/01/21 PHP
php写入mysql中文乱码的实例解决方法
2019/09/17 PHP
PHP如何通过带尾指针的链表实现'队列'
2020/10/22 PHP
基于PHP实现邮箱验证激活过程详解
2020/10/28 PHP
jquery实现的让超出显示范围外的导航自动固定屏幕最顶上
2011/09/22 Javascript
网页运行时提示对象不支持abigimage属性或方法
2014/08/10 Javascript
IE6浏览器中window.location.href无效的解决方法
2014/11/20 Javascript
判断js的Array和Object的实现方法
2016/08/29 Javascript
微信小程序 HTTPS报错整理常见问题及解决方案
2016/12/14 Javascript
JavaScript实现移动端轮播效果
2017/06/06 Javascript
vue项目中使用百度地图的方法
2018/06/08 Javascript
详解webpack4之splitchunksPlugin代码包分拆
2018/12/04 Javascript
详解vue项目接入微信JSSDK的坑
2018/12/14 Javascript
微信小程序实现多个按钮的颜色状态转换
2019/02/15 Javascript
微信小程序实现获取准确的腾讯定位地址功能示例
2019/03/27 Javascript
Vue+Node实现商品列表的分页、排序、筛选,添加购物车功能详解
2019/12/07 Javascript
在Python的web框架中配置app的教程
2015/04/30 Python
Python+微信接口实现运维报警
2016/08/27 Python
一篇文章搞懂Python的类与对象名称空间
2018/12/10 Python
python机器人运动范围问题的解答
2019/04/29 Python
python输出电脑上所有的串口名的方法
2019/07/02 Python
amazeui模态框弹出后立马消失并刷新页面
2020/08/19 HTML / CSS
C#如何进行LDAP用户校验
2012/11/21 面试题
总经理司机职责
2014/02/02 职场文书
中国梦演讲稿教师篇
2014/04/23 职场文书
2015年财务工作总结范文
2015/03/31 职场文书
师范生见习总结范文
2015/06/23 职场文书
小学英语教学反思范文
2016/02/15 职场文书
[有人@你]你有一封绿色倡议书,请查收!
2019/07/18 职场文书
2019年作为一名实习生的述职报告
2019/09/29 职场文书
浅谈Redis主从复制以及主从复制原理
2021/05/29 Redis
利用js实现简单开关灯代码
2021/11/23 Javascript
关于的python五子棋的算法
2022/05/02 Python