一、面向对象编程
1.1 面向过程与面向对象
面向过程和面向对象都是一种编程方式,只不过再设计上有区别。
1.1.1 面向过程pop:
举例:孩子上学
1. 妈妈起床
2. 妈妈洗漱
3. 妈妈做饭
4. 妈妈把孩子叫起来
5. 孩子起床
6. 孩子洗漱
7. 孩子吃饭
8. 妈妈给孩子送学校去
最为典型就是我们的C语言编程。
1》导入各种外部库
2》设计各种全局变量
3》写一个函数
4》写一个函数
5》........
6》写一个main主函数作为程序入口部分
- 面向过程的编程思想将一个功能分解为一个一个小的步骤, 我们通过完成一个一个的小的步骤来完成一个程序
- 这种编程方式,符合我们人类的思维,编写起来相对比较简单
- 但是这种方式编写代码的往往只适用于一个功能, 如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码, 所以它可复用性比较低,并且难于维护
优点:简单直观、性能高效、代码简洁。
缺点:不易维护、不易扩展、代码重用性低。
1.1.2 面向对象oop:
举例:孩子上学
1》妈妈 送 孩子 上学 python、java、C++都是面向对象的编程方式。 以python为例
1》导入各种库
2》设计各种全局变量
3》设计你所需要的类——妈妈类、孩子类
4》main主函数可有可无
- 面向对象的编程思想,将所有的功能统一保存到对应的对象中 比如,妈妈功能保存到妈妈的对象中,孩子的功能保存到孩子对象中 。要使用某个功能,直接找到对应的对象即可
- 这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。
- 但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点
优点:模块化、安全性高、代码重用性高。
缺点:学习难度大、性能开销大、调试困难。
1.2 类 和 对象
目前我们所学的python中的内置类型都是对象——内置对象,内置对象有时候不能满足我们的需求,需要自定义一些对象。
10, 20, 30, -40, a=10, b=20等等等,都是整数,对其进行抽象——int类。
python 中一切都是对象。
类也是一个对象。
1.2.1 类的定义 与 实例化对象
语法格式1:
class ClassA:# 公共的属性def __init__(self):passdef fun1(self):passdef fun2(self):pass语法格式2:
class ClassA(object):# 公共的属性def __init__(self):passdef fun1(self):passdef fun2(self):pass实例化对象的语法:1》无参对象名 = 类名()2》有参对象名 = 类名(参数列表)
例举
# 设计类
class student:name = Noneage = Nonegander = None
# 创建对象
student1 = student()
# 给对象赋值
student1.name = '小明'
student1.age = 18
student1.gender = '男'
# 获取对象中的信息
print(student1.name,student1.age,student1.gander)
1.2.2 访问属性/方法
使用符号 . 进行访问
# 访问属性
对象名.属性
# 访问方法
对象名.方法名()
1.2.3 对象与类的关系【1】
- 对象拥有类的所有属性和方法
- 对象的属性和方法可以单独添加、删除、修改
- 对象与对象之间的属性和方法不可共享
- 对象不能独自创建,必须依托于类,类可以实例化N个对象
#创建一个闹钟类
class clock:id = Noneprice = Nonedef ring(self):import winsound #python内置模块是让电脑响 winsound.Beep(2000,3000)#频率和时间print(f'电脑编号{self.id},电脑价格{self.price}')
#闹钟1
clock1 = clock()
clock1.id =12344
clock1.price = 19.99
clock1.ring()#闹钟2
clock2 = clock()
clock2.id = 12345
clock2.price = 29.99
clock2.ring()
1.2.3 对象与类的关系【2】
from types import MethodTypeclass student:def __init__(self,name):self.name = namedef fun1(self):print(f'{self.name}会唱歌')s1 = student('刘')
s2 = student('坤哥')s1.fun1()#刘会唱歌
s2.fun1()#坤哥会唱歌def Ctrl(self):print(f'{self.name}会穿背带裤打篮球')s2.Ctrl=MethodType(Ctrl,s2)s2.Ctrl()#坤哥会穿背带裤打篮球
还可以使用以下函数的方式来访问属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
- delattr(obj, name) : 删除属性。
1.2.5 魔方方法——构造函数 与 析构函数
- __init__ 构造函数:完成对象的初始化工作,方便统一管理、调用类创建对象时,自动执行。
- __del__ 析构函数:删除对象时执行一些操作,自动执行。
- __str__ 打印方法:输出执行信息,自动执行。
class Animal:#构造函数def __init__(self,name,call):self.name = nameself.call = call#打印方法def __str__(self):return f'{self.call},你在{self.name}叫什么'#析构函数def __del__(self):print(f"{self.name}消音成功")dog = Animal('狗','汪汪汪')
cat = Animal('猫','喵喵喵')print(dog)
print(cat)
"""
汪汪汪,你在狗叫什么
喵喵喵,你在猫叫什么
狗消音成功
猫消音成功
"""
1.2.6 类属性/方法 与 实例对象属性/方法 与 静态方法
class Bank(object):"""定义了一个银行卡类,用于初始化、存钱、取钱"""total_money = 0def __init__(self, name, money):self.name = nameBank.total_money += money #改为self.def save(self, money):Bank.total_money += moneydef draw(self, money):Bank.total_money -= moneyb1 = Bank('张三', 1000)
print(b1.total_money)
b1.save(5000)
print(b1.total_money)
b1.draw(3000)
print(b1.total_money)b2 = Bank('李四', 8888)
print(b2.total_money)
b2.save(10000)
print(b2.total_money)
类方法、实例方法、静态方法
class student:#定义一个学生类grade = 'py24101'@classmethoddef clas_fun(cls):"""类方法中只能调用类属性和类方法"""print(cls.grade)def __init__(self,name,age):self.name = nameself.age = agedef fun1(self):"""实例方法中能调用类属性、实例属性"""print(f"实例方法中输出类属性{self.grade}, 输出实例属性{self.name}")@staticmethoddef sta_fun(x):print(f"{x}静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等")s1 = student('小明',18)
#调用类方法
#方法一
student.clas_fun()#py24101
#方法二
s1.clas_fun()#py24101#如何调用实例对象
#方法一
student.fun1(s1)#实例方法中输出类属性py24101, 输出实例属性小明
#方法二
s1.fun1() #实例方法中输出类属性py24101, 输出实例属性小明# 如何调用静态变量
#方法一
student.sta_fun(2)#2静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等
#方法二
s1.sta_fun(2) #2静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等
1.2.7 Python的内置类属性
- __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
- __doc__ :类的文档字符串
- __name__: 类名
- __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
- __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
class Student(object):"""定义一个学生类属性:名字 年龄方法:method_1 method_2"""name = '张三'age = 18def method_1(self):passdef method_2(self):passprint(Student.__dict__)
print(Student.__doc__)
print(Student.__name__)
print(Student.__module__)
print(int.__module__)
print(Student.__bases__)
"""
{'__module__': '__main__', '__doc__': '\n 定义一个学生类\n 属性:名字 年龄\n 方法:method_1 method_2\n ', 'name': '张三', 'age': 18, 'method_1': <function Student.method_1 at 0x0000023EBF1A4AE0>, 'method_2': <function Student.method_2 at 0x0000023EBF1A4C20>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>}定义一个学生类属性:名字 年龄方法:method_1 method_2Student
__main__
builtins
(<class 'object'>,)
"""
1.3 类的封装【私有属性与方法】
封装是类的三大特性之一。
封装指的是隐藏对象中一些不希望让外部所访问的属性或方法。
python中封装其实是通过设置访问权限来体现的,私有属性和私有方法是控制访问权限的组成部分。
1.3.1 私有属性
在类的内部使用,不希望外部直接访问的变量。
在python中,使用双下划线作为前缀来定义私有属性。
私有属性在类外不能访问
class bank:def __init__(self,name,pwd):self.name = nameself.__pwd = pwd# 为了在某些需要的时候,访问到私有属性,所以需要在类内部设置两个接口def get_pwd(self):return self.__pwddef set_pwd(self,newpwd):self.__pwd = newpwduser = bank("小明",'123456')print(user.name)#小明
# print(user.__pwd) 会报错
print(user.get_pwd())#123456
user.set_pwd('456789')
print(user.get_pwd()) #456789
1.3.2 私有方法
和私有属性是一样的。
class Bank(object):"""定义了一个银行卡类属性:name pwd密码【我不希望外部访问】"""def __init__(self, name, pwd):self.name = nameself.__pwd = pwddef __info(self):print(f"名字{self.name}, 密码{self.__pwd}")def get_info(self):self.__info()# Bank.__info() 报错
b1 = Bank('李四', '123456')
# b1.__info() 报错
b1.get_info()
1.3.3 属性装饰器
属性装饰器是实现把方法转为属性的装饰器。
作用:
- 把方法转为属性,便于操作属性
- 实现对属性的更改(验证)、查看、删除
class 类名:
def __init__(self,name):
self.name = name
@property
def 函数名(self):
return self.name
@函数名.setter
def 函数名(self,m)
self.name +=m
class bank:def __init__(self,name ='',money = 0): #可以在里面定义初始值self.name = nameself.__money = money@propertydef my_money(self):return self.__money@my_money.setterdef my_money(self,m):self.__money+=muser = bank('小明',1000)user.my_money = 900
print(user.my_money) #1900
1.4 类的继承
面向对象的编程带来的主要好处之一就是代码的重用,实现这种重用的方法之一就是通过继承机制。
通过继承创建的新类称之为【子类】或者【派生类】,被继承的类称之为【父类】、【基类】、【超类】。
1.4.1 继承语法格式
class 子类名(父类名列表):
pass
class Parent(object):"""定义父类"""par_attr = 100def __init__(self):print("初始化父类")def par_fun1(self):print("父类方法1")def par_fun2(self):print("父类方法2")class Child(Parent):"""定义子类"""child_attr = 666def __init__(self):print("初始化子类")def child_fun1(self):print("子类方法1")c1 = Child()
print(c1.child_attr)
c1.child_fun1()print(c1.par_attr)
c1.par_fun1()
c1.par_fun2()
1.4.2 多继承语法【明白即可,不建议乱用】
如果在继承的元组()里面有一个以上的类,就称之为多继承
class a:pass
class b:pass
class c:pass
class d(a,b,c):passD = d()
print(d.mro())#[<class '__main__.d'>, <class '__main__.a'>, <class '__main__.b'>, <class '__main__.c'>, <class 'object'>] 查顺序
print(d.__bases__) #(<class '__main__.a'>, <class '__main__.b'>, <class '__main__.c'>)查父类
。
1.4.3 继承重写父类方法
如果你的父类方法不能满足你得要求,你可以在之类中重写父类的方法。
# 重写
class Parent(object):def method(self):print(f"{self}的方法")class Child(Parent):def method(self):print("xxxxxxxxxx")print(f"子类重写父类ri{self}的方法")c = Child()
c.method()
这里列出了一些通用的功能,可以在自己的类重写:
__init__ ( self [,args...] )构造函数 | 简单的调用方法: obj = className(args) |
__del__( self ) 析构方法 | 简单的调用方法 : del obj |
__repr__( self ) 转化为供解释器读取的形式 | 简单的调用方法 : repr(obj) |
__str__( self ) 用于将值转化为适于人阅读的形式 | 简单的调用方法 : str(obj) |
__cmp__ ( self, x ) 对象比较 | 简单的调用方法 : cmp(obj, x) |
1.4.4 python继承特点
- 在子类中如果需要父类的构造方法,需要显式调用父类的构造方法,或者不重写父类的构造方法。__init__()
- 在子类中调用父类的方法,需要显式调用,且第一个参数self不能省略
不重写父类构造方法
class father:def __init__(self,x,y):self.x = xself.y = ydef sum(self):print(f'{self.x},{self.y}')class child(father):def fun(self):print(f'{self.x},{self.y}')stu = child(1,2)
stu.fun() #1,2
重写父类构造方法、里面显式调用父类构造方法
class father:def __init__(self,x,y):self.x = xself.y = yclass child(father):def __init__(self,x,y,z):father.__init__(self,x,y)self.z = zdef fun(self):print(self.x,self.y,self.z)
stu = child(1,2,3)
stu.fun() #1,2,3
用super().方法/成员变量
class father:def __init__(self,x,y):self.x = xself.y = yclass child(father):def __init__(self,x,y,z):super().__init__(x,y)self.z = zdef fun(self):print(self.x,self.y,self.z)
stu = child(1,2,3)
stu.fun() #1,2,3
1.4.5 运算符重载
在Python中,并没有像其他语言(如C++)中那样的内置机制来重载运算符。但是,你可以通过定义特定的方法来模拟运算符重载的行为。
以下是一些常见运算符以及它们对应的特殊方法:
加法:+ 对应 __add__
减法:- 对应 __sub__
乘法:* 对应 __mul__
除法:/ 对应 __truediv__
取模:% 对应 __mod__
幂运算:** 对应 __pow__
位运算:
位运算:>> 对应 __rshift__
位运算:& 对应 __and__
位运算:| 对应 __or__
位运算:^ 对应 __xor__
class a:def __init__(self,x):self.x = xdef __add__(self, other):return self.x + other.x
b = a(3)
c = a(4)
print(b+c) #7class d:def __init__(self,x,y):self.x = xself.y = ydef __add__(self, other):return self.x*other.y+self.y*other.xe = d(2,3)
f = d(4,5)
print(e+f)#22
1.5 类的多态
python中的多态也可以通过方法重写进行。
同一个方法,不同对象显式的结果不同
class Animal:def speak(self):pass
class Dog(Animal):def speak(self):print('汪汪汪')
class Cat(Animal):def speak(self):print('喵喵喵')def Animal_speak(animal:Animal):animal.speak()dog = Dog()
cat = Cat()Animal_speak(dog)#汪汪汪
Animal_speak(cat)#喵喵喵
1.创建学生类Person。
2.添加静态方法,showInfo:
(1)显示信息“龙的传人”;
3.添加类属性:country,国籍,默认值为“中国“。
4.添加类属性:nation,民族,默认值为“汉族“。
5.添加构造方法,添加如下对象属性:
(1)name,保存学生姓名,默认值为空字符串。
(2)age,保存学生年龄,默认值为0。
(3)birth,保存出生日期,默认值为空字符串。
(4)money,保存工资收入,私有权限,默认值为0。
6.添加类方法,获取两个类属性的值。
7.添加魔法方法,将所有属性用格式化字符串组合成一个字符串后返回。
(1)格式如下: 国籍:中国 民族:汉 姓名:XXX 年龄:XXX 出生日期:XXX
8.添加setName方法,修改对象属性name。
9.添加getName方法,获得对象属性name的值。
10.添加返回age值的方法getAge,利用属性装饰器修饰该方法,并对age值进行修改。 11.添加setBirth方法,修改对象属性birth。
12.添加getBirth方法,获得对象属性birth的值。
13.添加私有属性money的set和get方法。
14.添加对象方法info,输出当前对象的个人信息:
(1)格式如下:姓名—年龄—出生日期—存款
15.添加主程序入口,完成如下任务:
(1)调用静态方法: ①提示:通过对象调用 ②提示:通过类名调用;
(2)创建一个对象。
(3)修改对象的所有对象属性。
(4)通过对象方法获得对象的所有属性值,并显示。
(5)调用info显示对象信息。
(6)调用对象的打印方法,输出信息;
(7)再次修改所有对象的属性。
(8)再次调用对象的打印方法。
from tkinter.font import namesclass Person:country = '中国'nation = '汉族'@staticmethoddef showInfo():print('龙的传人')def __init__(self,name = '',age = 0,birth = '',money = 0):self.name = nameself.age = ageself.birth = birthself.__money = money@classmethoddef func(cls):print(cls.country,cls.nation)def __str__(self):return f' 国籍:{self.country} \n 民族:{self.nation} \n 姓名:{self.name} \n 年龄:{self.age} \n 出生日期:{self.birth}'def setName(self,name):self.name = namedef getName(self):print(self.name)@propertydef getAge(self):return self.age@getAge.setterdef getAge(self,newage):self.age = newagedef setBirth(self):return self.birthdef getBirth(self,birth):self.birth = birthdef set_money(self):return self.__moneydef get_money(self,money):self.__money = moneydef info(self):print(f'姓名:{self.name} 年龄:{self.age} 出生日期:{self.birth} 存款:{self.__money}')user = Person()
user.showInfo()
user.setName("张三")
user.getAge = 25
user.getBirth('1999-09-30')
user.get_money(20000)
user.info()
print(user)
user.setName('小明')
user.getAge = 19
user.getBirth('2005-07-30')
user.get_money(2000)
print(user)