python面向对象笔记
一、封装(属性/私有方法/公有方法/静态方法/构造函数...)
# 定义一个类
class Animal:
# 私有成员(用_开头的约定为私有成员 - 注:仅仅是君子协定)
_age = 0 # 构造函数
def __init__(self, name):
# 建议所有私有成员在这里初始化(不管是已定义的,还是"动态"添加的)
self.name = name # 动态添加的私有成员
self._age = 1 # 已经定义好的私有成员 # 静态方法
@staticmethod
def eat():
print("Animal can eat food") # 公有方法
def to_string(self):
return "name:" + self.name # 私有方法(用_开头的约定为私有方法 - 注:仅仅是君子协定)
def _some_method(self):
return "this is a private method of :" + self.name # setter示例
def set_age(self, age):
if age < 0 or age > 100:
print("age is invalid!")
self._age = age # getter示例
def get_age(self):
return self._age def run(self):
print(self._some_method())
print("I am running") def test(self):
print("test1") # 注:这样会覆盖上面的test(self版本)
def test(self, hello):
print("test2:" + hello) animal = Animal("A new animal")
print(animal.to_string()) # 方法调用
animal.eat() # 静态方法调用1(不推荐)
Animal.eat() # 静态方法调用2
print("animal._age=" + str(animal.get_age()))
animal.set_age(10) # 调用setter
print(animal.get_age()) # 调用getter,输出10
animal.run() # 公有方法里调用私有方法
animal._age = 30 # 直接修改私有成员(不推荐)
animal._age2 = 40 # 注意:这里实际上给实例animal"动态"添加了一个_age2属性
print(animal.get_age()) # 这里输出的仍然是10
print("_age2:" + str(animal._age2)) # 这里输出的动态添加的_age2属性值
print(animal.test("hi"))
#print(animal.test()) # 这里会报错,因为test(self,hello)这个版本要求hello参数有值
print(animal._some_method()) # 直接调用私有方法(不推荐)
输出:
name:A new animal
Animal can eat food
Animal can eat food
animal._age=1
10
this is a private method of :A new animal
I am running
30
_age2:40
test2:hi
None
this is a private method of :A new animal
几个要点:
1、约定大于配置:比如构造函数约定为__init__;私有方法/成员约定为"_"开头(注:只是君子协定,硬要调用的话,外部是可以直接调用的);实例方法约定第1个参数为self
2、重载的处理,不象java里要定义多个方法签名,python里就一个版本,但是通过可变参数来实现(后面还要细讲)
3、动态语言,实例在运行过程中,可随时动态添加属性
另外注意:不要轻易使用__(二个连续的下划线)做为方法或变量的前缀或后缀,"__XXX__"在python里通常有特定含义,如果使用"__"开头的变量或写法,可能会遇到各种奇葩问题。
二、重载
传统的OOP语言,比如java,重载只能是定义多个不同方法签名的method,来实现重载,但是python可以做得更简单,用参数默认值就可以变相实现。
# 定义一个类
class Calculator:
# 加法
def add(self, a=0, b=0, c=0, d=0):
print("args:", a, b, c, d)
return int(a) + int(b) + int(c) + int(d) cal = Calculator()
print(cal.add(1, 2))
print(cal.add(1, 2, 3))
print(cal.add(1, "2", 3, "4")) print("\n") cal = Calculator #注意这里,如果漏了(),结果会大不同
print(cal.add(1, 2))
输出:
args: 1 2 0 0
3
args: 1 2 3 0
6
args: 1 2 3 4
10 args: 2 0 0 0
2
注意:16行,如果漏了(),cal = Calculator,实际上只是cal只是相当于类Calculator的别名,这样调用add(1,2)时,类似于静态方法调用,1会认为是第一个参数self,所以输出就成了2.
如果不确定参数个数,还可以这么做:
# 定义一个类
class Calculator:
# 约定:*参数,表示参数个数不限定
def add(self, *args):
result = 0
for arg in args:
result += int(arg)
return result cal = Calculator()
print(cal.add(1, 2, 3))
print(cal.add("1", 2, "3"))
输出:
6
6
三、继承
3.1 基本示例
class Fruit:
def __init__(self, name):
print("Fruit constructor...")
self.name = name def to_string(self):
print("Fruit to_string...")
return "name:" + self.name # 抽象方法
def get_color(self):
print("Fruit get_color...")
raise NotImplementedError class RedApple(Fruit):
def __init__(self, name):
print("Apple constructor...")
# 调用父类的构造函数
Fruit.__init__(self, name) def get_color(self):
return self.name + " is red" fruit = Fruit("unknown")
print(fruit.to_string())
# print(fruit.get_color()) # 报错,因为没实现
print("\n") redApple = RedApple("red apple")
print(redApple.get_color())
print(redApple.to_string()) print("\n")
print("1、redApple is instance of RedApple ? ", isinstance(redApple, RedApple))
print("2、redApple is instance of Fruit ? ", isinstance(redApple, Fruit))
print("3、fruit is instance of Fruit ? ", isinstance(fruit, Fruit))
print("4、fruit is instance of RedApple ? ", isinstance(fruit, RedApple))
print("5、RedApple is subclass of Fruit ? ", issubclass(RedApple, Fruit))
print("6、Fruit is subclass of Fruit ? ", issubclass(Fruit, Fruit))
print("7、Fruit is subclass of RedApple ? ", issubclass(Fruit, RedApple))
输出:
Fruit constructor...
Fruit to_string...
name:unknown Apple constructor...
Fruit constructor...
red apple is red
Fruit to_string...
name:red apple 1、redApple is instance of RedApple ? True
2、redApple is instance of Fruit ? True
3、fruit is instance of Fruit ? True
4、fruit is instance of RedApple ? False
5、RedApple is subclass of Fruit ? True
6、Fruit is subclass of Fruit ? True
7、Fruit is subclass of RedApple ? False
注:抽象方法是通过抛出未实现的异常来实现的。如果想类似java定义抽象类,把__init__方法抛出未实现异常就行。
3.2 多继承
python支持多继承,这点与java有很大区别
class P1:
def a(self):
print("P1-a") def b(self):
print("P1-b") def x(self):
print("P1-x") class P2:
def a(self):
print("P2-a") def b(self):
print("P2-b") def y(self):
print("P2-y") # 多继承示例
class S1(P1, P2):
def a(self):
print("S1-a") class S2(P2, P1):
def a(self):
print("S2-a") s1 = S1()
s1.a()
s1.b() # P1-b
s1.x()
s1.y() print("\n") s2 = S2()
s2.a()
s2.b() # P2-b
s2.x()
s2.y() print("\n") print("s1 isinstance of P1:", isinstance(s1, P1))
print("s1 isinstance of P2:", isinstance(s1, P2))
print("s1 isinstance of S1:", isinstance(s1, S1))
print("s1 isinstance of S2:", isinstance(s1, S2))
输出:
S1-a
P1-b
P1-x
P2-y S2-a
P2-b
P1-x
P2-y s1 isinstance of P1: True
s1 isinstance of P2: True
s1 isinstance of S1: True
s1 isinstance of S2: False
注意多承继的顺序,如果“爸爸们”之间有重名方法,将会按照继承顺序,谁在前面,就调用谁的。eg:def S(A,B) 子类S继承自A,B,如果A,B中都有方法x,调用S.x时,因为A排在B的前面,所以调用到的就是A.x方法。从上面的输出就可以得到印证。
3.3 接口、abc模块、属性
3.1中抽象类/方法是通过抛出异常来实现的,有点粗暴,下面介绍一种更优雅的方法,python内置的abc模块
from abc import * # 接口示例
class IRun(ABC):
# 抽象方法
@abstractmethod
def run(self):
pass class Animal(ABC):
# 抽象属性
@property
@abstractmethod
def name(self):
pass class Dog(Animal, IRun):
def __init__(self, name):
self._name = name; # 属性的getter
@property
def name(self):
return self._name # 属性的setter (注:每个property都会生成一个对应的@xxx.setter)
@name.setter
def name(self, value):
self._name = value # 接口的方法实现
def run(self):
print(self.name + " is running") dog1 = Dog("a")
dog1.run()
dog2 = Dog("b")
dog2.run()
print(isinstance(dog1, IRun))
print(id(dog1), id(dog2), id(dog1) == id(dog2)) # 判断2个实例是否相等
输出:
a is running
b is running
True
4314753736 4314753792 False
最后送一波福利: https://github.com/faif/python-patterns 这是python实现的所有设计模式,对oop感兴趣的推荐研究。
python面向对象笔记的更多相关文章
- Python 面向对象笔记
Python 面向对象课程笔记 前言 Python 面向对象 正文 基本概念 什么是对象: 万物皆对象 对象是具体物体: 拥有属性 拥有行为 封装零散为整体 OOP(Object Oriented P ...
- python 面向对象-笔记
1.如何创建类 class 类名: pass class bar: pass 2.创建方法 构造方法,__init__(self,arg) obj = 类('a1') 普通方法 obj = 类(‘xx ...
- python学习笔记六 初识面向对象上(基础篇)
python面向对象 面向对象编程(Object-Oriented Programming )介绍 对于编程语言的初学者来讲,OOP不是一个很容易理解的编程方式,虽然大家都知道OOP的三大特性 ...
- python学习笔记15(面向对象编程)
虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程. 一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界 ...
- [Python学习笔记][第六章Python面向对象程序设计]
1月29日学习内容 Python面向对象程序设计 类的定义与使用 类定义语法 使用class关键词 class Car: def infor(self): print("This is ca ...
- Python学习笔记【第十一篇】:Python面向对象高级
isinstance(obj,cls)和issubclass(sub,super) class Person(object): def __init__(self, name, age, sex, n ...
- [Python]面向对象近期笔记-super
Python面向对象高级 直接调用父类方法 class A: def __init__(self): print("hello") class B(A): def __init__ ...
- OpenCV之Python学习笔记
OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
- Python学习笔记基础篇——总览
Python初识与简介[开篇] Python学习笔记——基础篇[第一周]——变量与赋值.用户交互.条件判断.循环控制.数据类型.文本操作 Python学习笔记——基础篇[第二周]——解释器.字符串.列 ...
随机推荐
- OCM_第五天课程:Section2 —》AGENT 的安装 、GC 的使用
注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...
- 利用HTML5开发Android
● Android设备多分辨率的问题 Android浏览器默认预览模式浏览 会缩小页面 WebView中则会以原始大小显示 Android浏览器和WebView默认为mdpi.hdpi相当于mdpi的 ...
- 目标检测-yolo
论文下载:http://arxiv.org/abs/1506.02640 代码下载:https://github.com/pjreddie/darknet 1.创新点 端到端训练及推断 + 改革区域建 ...
- CentOS 上安装 nodejs v11.0.0
下载 nodejs 淘宝 nodejs 镜像地址:https://npm.taobao.org/mirrors/node wget 命令下载: wget https://npm.taobao.org/ ...
- 2018-2019-2 网络对抗week1 Kali安装 20165333陈国超
Kali安装 安装过程是按照网上的教程装的,链接点击[https://blog.csdn.net/KNIGH_YUN/article/details/79949512] 安装成功的截图 主要说一下安装 ...
- 《剑指offer》-数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 最开始的思路 ...
- 几种常见SQL分页方式效率比较
分页很重要,面试会遇到.不妨再回顾总结一下: 一:创建测试环境,(插入100万条数据大概耗时5分钟). create database DBTestuse DBTest 二:--创建测试表 creat ...
- JAVA代码设置selector不同状态下的背景
Selector设置button点击效果(详细)以及常见问题https://www.jianshu.com/p/a0ddba6d7969 Android 代码动态设置TextView的背景.颜色Sel ...
- J 判断二叉树每个结点的权值是否关于根节点完全对称
如果二叉树每个结点的权值关于根节点完全对称 就输出Yes Sample Input 27 //结点1 2 3 //结点1的左孩子是结点2 右孩子是结点32 4 53 6 74 0 05 0 06 0 ...
- Delphi自动适应屏幕分辨率的属性
https://www.cnblogs.com/zhangzhifeng/category/835602.html 这是个困惑我很长时间的问题,到今天终于得到解决了. 话说Delphi有个很强的窗体设 ...