Python的面向对象
1、什么是面向对象
面向对象称为OO,他通过将数据和功能封装在一个被称为‘对象’的实体中,来组织和管理代码。面向对象变成(OOP)具有四个特性,封装、继承、多态、抽象
优点:模块化、安全性高、代码重用性高
缺点:学习难度大、性能开销大、调试困难
2、类和对象
Python中的一切都是对象,类也是一个对象,Python 的内置类型也都是对象--内置对象,对象的抽象是类,类可以实例化若干个对象
2.1类的定义
语法格式1:
class ClassA:
# 公共的属性
def __init__(self):
pass
def fun1(self):
pass
def fun2(self):
pass
语法格式2:
class ClassA(object):
# 公共的属性
def __init__(self):
pass
def fun1(self):
pass
def fun2(self):
pass
实例化对象的语法:
1》无参
对象名 = 类名()
2》有参
对象名 = 类名(参数列表)
2.2类的属性
Python中类的属性分为两种,类属性和实例属性
2.2.1类属性
定义在类级别上的变量,与类本身相关联,不与任何特定实例相关联,所有实例共享同一个类属性的值,除非在某个实例改变他的值
2.2.2实例属性
实例属性是与类的特定实例相关联的变量。每个实例都有自己独立的实例属性,即使这些实例属于同一个类。实例属性通常在实例的构造方法(__init__
)中定义,使用self
关键字来引用当前实例。
class stu():
grade = 'py24101'
def __init__(self, name, age):
self.name = name
self.age=age
def study(self):
print(f'{self.name}爱学习')
def play(self):
print(f'{self.name}玩游戏')
s1=stu('张三',18)
print(stu.grade)
print(s1.grade,s1.name)
注意事项
-
类属性通常用于存储那些对类所有实例都相同的值。如果需要在实例之间共享数据,并且这些数据在实例的生命周期内不会改变,那么类属性可能是一个好的选择。
-
实例属性用于存储与特定实例相关的数据。它们使得每个实例都可以有自己的状态和行为。
-
当通过实例访问属性时,Python会首先查找实例属性。如果实例属性不存在,它会查找类属性。这意味着如果类属性和实例属性同名,实例属性会“隐藏”类属性。
-
尽量避免在实例方法中修改类属性,因为这可能会导致意外的行为,特别是当你有多个实例时。如果确实需要修改类属性的值,请确保你了解这样做的后果。
2.3对象和类的关系
-
对象拥有类的所有属性和方法
-
对象的属性和方法可以单独添加、删除、修改
-
对象与对象之间的属性和方法不可共享
-
对象不能独自创建,必须依托于类,类可以实例化N个对象
class Stu(object):
id = '1001'
name = '张三'
def fun1(self):
pass
# 实例化对象
s1 = Stu()
s2 = Stu()
# 对象的属性可以单独修改、添加、删除
s1.name = '李四'
s1.age = 18
del s1.age
print(s1.name)
# print(s1.age)
print(s2.name)
# print(s2.age)
还可以使用以下函数的方式来访问属性
-
getattr(obj, name[, default]) : 访问对象的属性。
-
hasattr(obj,name) : 检查是否存在一个属性。
-
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
-
delattr(obj, name) : 删除属性。
2.4魔方方法---构造函数与析构函数
-
__init__ 构造函数:完成对象的初始化工作,方便统一管理、调用类创建对象时,自动执行。
-
__del__ 析构函数:删除对象时执行一些操作,自动执行。
-
__str__ 打印方法:输出执行信息,自动执行。
class car():
def __init__(self,name,color):
self.name=name
self.color=color
def __str__(self):
return f"logo{self.name},color{self.color}"
def __del__(self):
print( f"{self.name}boom,go home")
c1=car('保时捷','red')
c2=car('xiaomisu7','white')
print(c1.name,c2.name)
print(c1)
print(c2)
2.5类方法、实例方法、静态方法
class Student(object):
"""
定义了一个学生类
"""
grade = 'py24101'
@classmethod#类方法
def cls_fun(cls):
"""类方法中只能调用类属性和类方法"""
print(f"班级名称是{cls.grade}")
def __init__(self, name, age):
self.name = name
self.age = age
def fun1(self):
"""实例方法中能调用类属性、实例属性"""
print(f"实例方法中输出类属性{self.grade}, 输出实例属性{self.name}")
@staticmethod#静态方法
def sta_fun(x):
print(f"{x}静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等")
s1 = Student('张三', 18)
# 如何调用类方法
Student.cls_fun()
s1.cls_fun()
# 如何调用实例方法
Student.fun1(s1)
s1.fun1()
# 如何调用静态方法
Student.sta_fun(3)
s1.sta_fun(3)
2.6Python的内置属性
-
__dict__ : 类的属性(包含一个字典,由类的数据属性组成)
-
__doc__ :类的文档字符串
-
__name__: 类名
-
__module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
-
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
3、封装
封装是类的三大特性之一。
封装指的是隐藏对象中一些不希望让外部所访问的属性或方法。
python中封装其实是通过设置访问权限来体现的,私有属性和私有方法是控制访问权限的组成部分。
3.1私有属性
class Bank(object):
"""
定义了一个银行卡类
属性:name pwd密码【我不希望外部访问】
"""
def __init__(self, name, pwd):
self.name = name
self.__pwd = pwd
# 为了在某些需要的时候,访问到私有属性,所以需要在类内部设置两个接口
def get_pwd(self):
return self.__pwd
def set_pwd(self, newpwd):
self.__pwd = newpwd
# print(Bank.__pwd)
b1 = Bank('张三', '123456')
print(b1.name)
# print(b1.__pwd)
print(b1.get_pwd())
b1.set_pwd('666888')
print(b1.get_pwd())
3.2私有方法
class Bank(object):
"""
定义了一个银行卡类
属性:name pwd密码【我不希望外部访问】
"""
def __init__(self, name, pwd):
self.name = name
self.__pwd = pwd
def __info(self):
print(f"名字{self.name}, 密码{self.__pwd}")
def get_info(self):
self.__info()
# Bank.__info() 报错
b1 = Bank('李四', '123456')
# b1.__info() 报错
b1.get_info()
3.3属性装饰器
把方法转为属性
class car():
def __init__(self, name, color):
self.name = name
self.color = color
self.__num = 20
@property
def num(self):
return self.__num
@num.setter
def num(self, x):
if not isinstance(x,int):
print('油量必须是数字')
else:
self.__num += x
@num.deleter
def num(self):
print("删除油量")
del self.__num
c1 = car('法拉利', 'red')
print(c1.name, c1.color, c1.num)
c1.num = 'win32'
print(c1.num)
del c1.num
4.类的继承
面向对象的编程带来的主要好处之一就是代码的重用,实现这种重用的方法之一就是通过继承机制。
通过继承创建的新类称之为【子类】或者【派生类】,被继承的类称之为【父类】、【基类】、【超类】
4.1语法格式
class Parent():
par_attr=100
def __init__(self):
print('初始化父类')
def par_fun(self):
print('父类方法一')
def par_dun(self):
print('父类方法二')
class Child(Parent):
chi_attr=10
def __init__(self):
print('初始化子类')
def chi_dun(self):
print('子类方法一')
def chi_fun(self):
print('子类方法二')
c1=Child()
c1.par_dun()
c1.chi_dun()
p1=Parent()
p1.par_dun()
4.2多继承
class A:
pass
class B:
pass
class C:
pass
class D(A,B,C):
pass
d1=D()
print(D.mro())
print(D.__bases__)
这里列出了一些通用的功能,可以在自己的类重写:
-
__init__ ( self [,args...] ) 构造函数 简单的调用方法: obj = className(args)
-
__del__( self ) 析构方法, 删除一个对象 简单的调用方法 : del obj
-
__repr__( self ) 转化为供解释器读取的形式 简单的调用方法 : repr(obj)
-
__str__( self ) 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj)
-
__cmp__ ( self, x ) 对象比较 简单的调用方法 : cmp(obj, x)
class Parent():
def __init__(self,x,y):
self.x=x
self.y=y
def add(self):
return self.x+self.y
class Child(Parent):
def __init__(self,x,y,z):
super().__init__(x,y)
self.z=z
def add(self):
return super().add()+self.z
c=Child(1,2,3)
print(c.add())
4.3运算符重载
在Python中,并没有像其他语言(如C++)中那样的内置机制来重载运算符。但是,你可以通过定义特定的方法来模拟运算符重载的行为。
以下是一些常见运算符以及它们对应的特殊方法:
加法:+ 对应 __add__
减法:- 对应 __sub__
乘法:* 对应 __mul__
除法:/ 对应 __truediv__
取模:% 对应 __mod__
幂运算:** 对应 __pow__
位运算:
位运算:>> 对应 __rshift__
位运算:& 对应 __and__
位运算:| 对应 __or__
位运算:^ 对应 __xor__
class op():
def __init__(self,x,y):
self.x=x
self.y=y
def __add__(self, other):
return (self.x+other.x)**2-self.y-other.y
o1=op(1,3)
o2=op(5,7)
print(o1+o2)
5.多态
class Animal(object):
name = '动物'
age = 0
def speak(self):
print("动物的声音")
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
a = Animal()
d = Dog()
c = Cat()
a.speak()
d.speak()
c.speak()
6.关于下划线说明
-
__foo__: 以双下划线开头双下划线结尾,定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的,自动。
-
_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import ···
-
__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。