赞
踩
面向过程:
把完成某一个需求的所有步骤 从头到尾 逐步实现,根据开发需求,将某些 功能独立 的代码封装成一个又一个函数,最后完成的代码,就是顺序地调用不同的函数
面向对象:
是更大的封装,根据 职责 在一个对象中封装多个方法
类 是对一群具有 相同 特征 或者 行为的事物的一个统称,是抽象,不能直接使用
Class Person():
name = "xxx"
def __init__(self):
pass
Person.name
p1 = Person()
类名: 这类事物的名字,满足大驼峰命名法:首字母大写,单词之间没有下划线
属性: 这些事物具有什么样的特征
方法: 这类事物具有什么样的行为
(1)定义简单的类
格式:
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
#切记如果函数有参数,第一个参数必须是self
(2)对象的创建
对象变量 = 类名()
第一个面向对象程序:
需求
class Cat:
def eat(self):
pirnt("小猫爱吃鱼")
def drink(self):
print("小猫要喝水")
(3)构造方法
1.初始化方法
以前面的class类为例子:py中可以在类外部给类添加属性:
tom = Cat()
tom.name = "Tom"
tom.eat()
不建议使用
如果name 是方法 这样赋值就会失去 该方法,推导->一个类的属性应该放在什么地方?
2.构造方法
当使用 类名()创建对象时,会自动执行以下操作:
class Cat:
"""这是一个猫类"""
def __init__(self):
print("初始化")
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫要喝水")
tom = Cat()
就会自动输出: 初始化
3.在初始化方法内部定义属性
在__init__方法内部使用 self.属性名 = 属性的初始值,就可以定义属性,定义属性之后,在使用Cat类创建的对象都会拥有该属性
4.改造初始化方法–初始化的同时设置初始值
在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对 __init__方法进行改造
class Cat:
"""这是一个猫类"""
def __init__(self,name):
print("初始化")
self.name = name
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫要喝水")
5.析构方法
(1)del 对象被从内存中销毁的,会被自动调用
当使用 类名() 创建对象时,为对象 分配完空间后,自动调用 init 方法,当一个 对象被从内存销毁 前,会 自动 调用 __del__方法
应用场景:
__init__改造初始化方法,可以让创建对象更加灵活
__del__如果希望在对象被销毁前,再做一些事情,可以考虑一下__del__方法
生命周期:
一个对象从调用 类名() 创建,生命周期开始,一个对象的__del__方法一旦被调用,生命周期结束,在对象的生命周期内,可以访问属性,或者让对象调用方法
(2)str 返回对象的描述信息,print函数输出使用
6.方法中的self参数
在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self。其作用相当于java中的this,表示当前类的对象,可以调用当前类中的属性和方法。self 指向的是当前 调用类中方法的实例对象
7.四则运算符重载
四则运算加,减,乘,除(+,-,*,/)分别是通过调用 __ add __ , __ sub __ , __ mul __
和__truediv__方法完成重载的。当两个实例对象执行四则运算时,自动调用的是它们对应的方法
创建一个Employee()类
class Employee(object):
def __init__(self,name,age):
self.name = name
self.age = age
zs =Employee("张三",20)
ls = Employee("李四",26)
#想要实现求得二者的平均年龄
sum_age = (zs.age + ls.age)/2
print(sum_age)
//现在想优化加法 让其可以实现 zs + ls
class Employee(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __add__(self,other):
return self.age + other.age
sum_age = (zs + ls)/2
print(sum_age)
#这样即可
减法,除法,乘法依次类推
小测试:实现 a + b 返回的结果是 a - b,a - b 返回的结果是a + b 就是,重写__add__() 和 __sub__() class New_int(int): def __add__(self,other): return int.__sub__(self,other) def __sub__(self,other): return int.__add__(self,other) a = New_int(3) b = New_int(1) a + b = 2 a- b = 4 错误演示 class New_int(int): def __add__(self,other): return self+other def __sub__(self,other): return self-other a = New_int(3) b = New_int(1) a + b 这样会陷入无限递归 原因是: self+other这两个相加等于调用def __add__(self,other) class New_int(int): def __add__(self,other): return int(self)+int(other) def __sub__(self,other): return int(self)-int(other) 这样就可以了
反运算
a + b 当a 的__add__()函数不能正常用时
就会调用b的__radd__()函数
举个例子
class New_int(int):
def __radd__(self,other):
return __sub__(self,other)
a = New_int(3)
b = New_int(1)
a+ b = 4
1 + b = 0
__ rsub __()也是如此
索引和分片重载
以下是跟索引和分片相关的三个可重载方法:
__ getitem __ :索引,分片取值
__ setitem __:索引,分片赋值
__ delitem __:索引和分片删除
这三个方法都可以进行重载,具体方法如下
__getitem__方法
在对实例对象执行索引,分片或者for迭代操作取值时,会自动调用__getitem__方法。
例如:
class Company(object):
def __init__(self,boss,ls):
self.boss = boss
self.ls = ls
company = Company("刘备",["关羽","张飞","赵子龙","黄忠"])
想要输出列表中的某一个可用 company.ls[i]
这样显得不怎么方便
class Company(object):
def __init__(self,boss,ls):
self.boss = boss
self.ls = ls
def __getitem__(self,item): #item 是一个切片对象
return self.ls[item]
company[i] 即可输出第i个数据 #如果这里是下标,item就是下标
company[i:]#这里是切片的用法,所以 item 也是一个切片对象
其他的几个方法:
class Company(object):
def __init__(self,boss,ls):
self.boss = boss
self.ls = ls
def __getitem__(self,item): #item 是一个切片对象
return self.ls[item]
def __setitem__(self,key,value):
self.ls[key] = value
def __delitem__(self,key):
del self.ls[key]
company[i] = "内容"
del company[1]
删除和修改都可以使用这种简介方法来使用了
重写 __ str__ 方法
在 python 中,使用print输出对象变量,默认情况下,会输出这个变量引用的对象是由哪一个类创建的对象,以及在内存中的地址(十六进制表示)
如果在开发中希望使用 print 输出对象变量时,能够打印自定义的内容,就可以利用__str__这个内置方法了
注意:__ str__方法必须返回一个字符串
class Cat:
def __init__(self,new_name):
self.name = new_name
print("%s 来了" % self.name)
def __str__(self):
return "我是小猫:%s" % self.name
tom = Cat("Tom")
print(tom)
如果想要输出默认情况则可
print(repr(tom))
8.面向对象的封装
封装:
1.封装是面向对象编程的一大特点
2.面向对象编程的第一步 - - 将属性 和 方法 封装到一个抽象的类中
3.外界使用类创建对象,然后让对象调用方法
4.对象方法的细节 都被 封装 在类的内部
5.一个对象的属性可以是另一个类创建的对象
需求:士兵突击
士兵 许三多 有一把 AK47 士兵 可以 开火 枪 能够 发射 子弹 枪 装填 装填子弹 --增加子弹数 Soldier 类,属性:name ,gun 方法: __init__(self): fire(self): #1.判断 士兵是否有枪 2. 高喊口号 3.让枪装填子弹 4.让枪发射子弹 Gun 类 属性: model bullet_count 方法: __init__(self,model): add_bullet(self,count): shoot(self):
身份运算符:
身份运算符用于比较两个对象的内存地址 是否一致 --是否是对同一个对象的引用
在 python 中针对 None 比较时,建议使用 is
运算符 | 描述 | 实例 |
---|---|---|
is | is是判断两个标识符是不是引用同一个对象 | x is y. 类似 id(x) == id(y) |
is not | is not 是判断两个标识符是不是引用不同对象 | x is not y, 类似 id(x) != id(y) |
is 与 = = 区别:
is 用于判断两个变量 引用对象是否为同一个,== 用于判断引用变量的值 是否相等
意思就是:两个事物值相等但是其地址可以不一样
私有属性和私有方法
应用场景及定义方式
应用场景:
定义方式:
在 定义属性或方法时,在属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法
但是在python中是伪私有属性和私有属性(科普)
提示:在日常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法 python 中,并没有真正意义 的 私有
在给属性,方法命名时,实际上是对 名称 做了一些特殊处理,使得外界无法访问到
处理方式:在名称前面加上 _类名__名称
8.单继承
面向对象三大特征
(1)继承的概念,语法和特点:
继承的概率:子类拥有父类的所有方法 和 属性
e.g:
不使用继承:
编写 1.Animal 类 2.Dog 类 3.Cat 类 4.Chinese_garden_dog
Animal 的特性 吃,喝,睡…
Dog 的特性 吃,喝,睡…
Cat 的特性 吃,喝,睡…
…
可以发现这些类都具有一些相同的属性或者行为(方法),不使用继承就会造成这部分代码的累赘。
e.g: class Animal: def eat(self): print("吃") def drink(self): print("喝") def sleep(self): print("睡觉") class Dog(Animal): def bark(self): print("汪汪") class Cat(Animal): def bark(self): print("喵喵")
(2)继承的语法
class 类名(父类名):
pass
子类继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
子类中应该根据 职责,封装 子类特有的属性和方法
专业术语:
Dog 类是 Animal 类的子类,Animal 类是 Dog 类的父类,Dog 类从 Animal 类继承
Dog 类是 Animal 类的派生类,Animal 类是Dog 类的基类,Dog类从Animal 类派生
继承的传递性:
C类从B类继承,B类又从A类继承
那么C类就具有B类和A类的所有属性和方法
子类 拥有 父类以及 父类的父类 中封装的所有属性 和 方法
9.多继承
子类 可以拥有 多个父类,并且所有具有所有父类的属性和方法
语法格式:
class 子类名(父类名1,父类名2.....):
pass
注意事项:
如果 不同的父类 中存在同名的方法,子类对象 在调用方法时,会调用哪一个父类方法?
e.g: class A: def fun1(): print("A----fun1") def fun2(): print("A----fun2") class B: def fun1(): print("B----fun1") def fun2(): print("B----fun2") class C(A,B): pass c = C() c.fun1() c.fun2() class c(B,A): pass c = C() c.fun1() c.fun2()
在开发时,应该尽量避免这种容易产生混淆的情况!–如果父类之间存在同名的属性或者方法,应该 尽量避免 使用多继承
python 中的 MRO – 方法搜索顺序(知道)
python 中针对 类提供了一个内置属性 __mro__可以查看方法 搜索顺序
MRO 是 method resolution order,主要用于 在多继承时判断 方法,属性的调用路径
print(C. __ mro __)
在搜索方法时,是按照 __mro__的输出结果从左到右 的顺序查找的
如果在当前类中 找到方法,就直接执行,不再搜索
如果没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索
如果找到最后一个类,还没有找到方法,程序报错
新式类 和 旧式类
object 是 python 为所有对象提供的基类,提供有一些内置的属性和方法,额可以使用 dir 函数查看
新式类 : 以object 为基类的类,推荐使用 py3都是这样
旧式类: 不以object为基类的类,不推荐使用
10.重写父类方法与调用父类方法和属性
子类 拥有 父类的所有方法 和 属性
子类 继承自父类,可以直接享用父类中已经安排好的方法,不需要再次开发
当父类的方法实现不能满足子类需求时,可以对方法进行重写
重写父类方法两种情况
1.覆盖父类的方法
2.对父类方法进行 扩展
(1)覆盖:
具体实现方法,就相当于在子类中 定义了一个和父类同名的方法并且实现
(重写后,在运行时只会调用子类中重写的方法,而不会调用 父类封装的方法)
(2)扩展:
如果开发中,子类的方法实现 中 包含 父类方法的实现
父类原本封装的方法实现 是 子类方法的一部分
这里就可以使用 扩展 的方法
- 在子类中 重写 父类的方法
- 在需要的位置使用 super().父类方法,来调用父类方法的执行
- 代码其他的位置针对子类的需求,编写子类特有的代码实现
- 也可以 父类名.方法(self)
父类名.方式(self)#调用未绑定的父类的方法,可以通过父类.方法名调用,并且此时的self是子类的属性
super().父类方法#也可以通过super()函数调用,推荐使用super()函数,可以自动找到父类的属性,我们可以不用手动传参
11.多态
不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
-多态 可以 增加代码的灵活度
-以 继承 和 重写 父类方法为前提
-是调用方法的技巧,不会影响到类的内部设计
12.
类对象:就是类本身,支持两种操作:属性引用和实例化 ,上述的例子中 Person 就是类对象
实例对象:由类实例化出来的对象 唯一操作是属性引用,p1就是实例对象
类属性:就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本;对于公有的类属性,在类外可以通过类对象和实例对象访问
e.g:
class Tool:
count = 0 # 类属性
def __init__(self,name):
self.name = name
Tool.count += 1
-类属性 就是给 类对象 中定义的属性
-通常用来记录 与这个类相关的特征
-类属性不会用于记录 具体对象的特征
访问类属性有两种方式:
(1)类名.类属性:
(2)对象.类属性(不推荐)
e.g:
class Tool:
count = 0 # 类属性
@classmethod#类方法 , cls.属性, cls.类方法名
def show(cls):
print("数量"%cls.count)
def __init__(self,name):
self.name = name
Tool.count += 1
@staticmethod
def 静态方法名():
pass
通过 类名.调用静态方法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。