面向对象编程
(Object-oriented Programming,简称 OOP),是一种封装代码
的方法面向对象
:将模拟真实世界里的事物(对象 )和描述其特征(属性)的数据和函数代码块(方法)封装到一起(类)
类
:可以理解是一个模板
,通过它可以创建出无数个具体实例对象
:类并不能直接使用,通过类创建出的实例
(对象)才能使用属性
:类中的所有变量
称为属性方法
:类中的所有函数
通常称为方法class
关键字定义类属性
: 包含在类中的变量
方法
:包含类中的函数
class 类名:
'''
类说明
'''
类属性
类方法
对象
类的实例化
:创建类对象的过程对象名 = 类名(参数,...)
类对象名.变量名
对象名.方法名(参数)
类对象名.新变量名 = 新变量值
del 类对象名.变量名
def 方法名(self , [ parm, ...]):
pass
from types import MethodType # 导入模块
类对象名.方法名 = MethodType(方法名, 对象名) # 将方法和对象绑定
位置不同
,以及定义的方式不同
,类属性又可细分为以下 3 种类型
:
类属性
或类变量
self.变量名
的方式定义的变量,称为实例属性
或实例变量
变量名=变量值
的方式定义的变量,称为局部变量
同时共享类变量
,也就是说,类变量在所有实例化对象中是作为公用资源存在的通过类名修改类变量的值
,并且修改后,会影响所有的实例化的对象
类对象无法修改类变量的值
,通过类对象对类变量赋值,只会修改自己对象中的变量值class person :
name = "QWQ" # 类变量 :name
age = 18 # 类变量 :age
def info(self) :
print("%s age is %d"%( self.name, self.age))
jone = person()
jone.info() # 打印 :QWQ age is 18
jack = person()
jack.info() # 打印 :QWQ age is 18
person.name = "WXQ" # 通过类名改变类变量值, 改变了模子里面的值
person.age = 20
jone.info() # 打印 :WXQ age is 20
jack.info() # 打印 :WXQ age is 20
jone.name = "LNL" # 通过类对象改变类变量值
jone.age = 19
jone.info() # 打印 :LNL age is 19 , 对象中类变量发生改变
jack.info() # 打印 :WXQ age is 20 , 类中类变量值不会发生变化
self.变量名
的方式定义的变量,其特点:
调用方法的对象
只能通过对象名访问
,无法通过类名访问无法修改类变量的值
,更不会影响类的其它实例化对象class person :
def __init__(self) -> None:
self.name = "QWQ" # 实例变量
self.age = 18 # 实例变量
def info(self) :
self.tall = 178 # 实例变量
jone = person()
print("%s age is %d"%(jone.name, jone.age)) #打印 :QWQ age is 18,通过对象访问实例变量
# print(person.name) 无法通过类名访问实例变量
# print(jone.tall) 在info方法没用调用前,还不存在tall变量,无法调用
jone.info() # 调用info方法,创建了tall实例变量
print(jone.tall) # 打印 :178
jone.name = "WXQ" # 通过对象修改实例变量
jone.age = 20
jone.tall = 172
print("%s age is %d, tall is %d"%(jone.name, jone.age,jone.tall))
jack = person()
jack.info()
print("%s age is %d, tall is %d"%(jack.name, jack.age,jack.tall)) # 类中实例变量值没有改变
结果:
QWQ age is 18
178
WXQ age is 20, tall is 172
QWQ age is 18, tall is 178
变量名=值
的方式进行定义局部变量只能用于所在函数中
,函数执行完成后,局部变量也会被销毁class Calculate :
def count(self,money):
sale = 0.8*money # sale 为局部变量
print("优惠后的价格为:",sale)
clang = Calculate()
clang.count(100)
类方法
、实例方法
和静态方法
@classmethod
修饰的方法为类方法@staticmethod
修饰的方法为静态方法不用任何修饰
的方法为实例方法self
参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)类对象直接调用
class class_name():
def __init__(self) :
pass
def func(self): # 实例方法
pass
object_name = class_name() # 定义对象
object_name.func() # 调用实例方法
class_name.func(object_name) # 类名调用实例方法,需手动给 self 参数传值
cls
类本身
绑定给 cls
参数@classmethod
修饰符进行修饰class class_name():
@classmethod
def func(cls): # 类方法
pass
class_name.func() # 使用类名直接调用类方法
object_name = class_name() # 使用类对象调用类方法
object_name.func()
静态方法定义在类这个空间
(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中没有类或对象的绑定
,因此静态方法中无法调用任何类属性和类方法@staticmethod
修饰class person:
@staticmethod
def info(name,add): # 静态方法
print(name,add)
peron.info("QWQ",18) # 使用类名直接调用静态方法
jack = person() # 使用类对象调用静态方法
jack.info("jack",24)
初始化赋值
self
,其它参数个数无限class class_name :
def __init__(slef, parm1, parm2,...):
# self :新建的对象
slef.parm1 = parm1
slef.parm2 = parm2
__new__()
创建类的实例化对象时调用,相对于给实例化的对象申请一片内存,如果创建的类中没有写__new__()
,实际上执行时会调用object类中的__new__()
申请返回内存地址,也就是说我们使用的该方法实际是一种重写父类方法__new__()
方法是在类准备将自身实例化时调用执行__new__()
方法始终都是类的静态方法
,即使没有被加上静态方法装饰器return
返回该类的一个实例对象地址不可变的class
时(比如int, str, tuple), 提供一个自定义这些类的实例化过程的途径"""
示例1 :
"""
class int_define():
def __init__(self, value) :
self.value = abs(value)
class PositiveInterger_define(int_define):
def __init__(self, value):
super().__init__(value) # 通过super, 调用父类的构造方法
def __repr__(self) -> str:
return str(self.value)
i = PositiveInterger_define(-3)
print(i) # 打印结果为3
"""
示例2:
"""
class PositiveInterger(int) :
def __init__(self, value) :
super().__init__(value) # 同样试图用super()调用父类int的构造方法
def __repr__(self) -> str:
return str(self.value)
i = PositiveInterger(-3) # 程序报错,无法执行
"""
示例3:
"""
class PositiveInterger1(int) :
def __new__(cls, value) : # 通过__new__()才能达到想要的结果
return super().__new__(cls, abs(value))
i = PositiveInterger1(-3)
print(i)
__repr__()
: 类的实例化对象用来做 自我介绍
的方法,默认情况下,它会返回当前对象的 类名+object at+内存地址
,而如果对该方法进行重写,可以为其制作自定义的自我描述信息__str__()
: 在__str__
方法中添加 return+ 打印对象看到内容
,实现打印对象名时自动触发去调用出__str__
里面的内容# 示例1 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
QWQ = person("QWQ", 18)
print(QWQ) # 打印 :<__main__.person object at 0x000001F3E8864250>
# 示例2 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self): # 对父类object进行重写
return "{} age is {}".format(self.name, self.age)
QWQ = person("QWQ", 18)
print(QWQ) # 打印 : QWQ age is 18
# 示例3 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self): # 对父类object进行重写
return "{} age is {}".format(self.name, self.age)
QWQ = person("QWQ", 18)
print(QWQ) # 打印 : QWQ age is 18
垃圾回收
(简称GC)实现函数:如果之前创建的类实例化对象后续不再使用,通过__del__()
函数在适当位置手动将其销毁,释放其占用的内存空间class class_name:
def __init__(self):
pass
def __del__(self):
pass
c = class_name() # 创建对象
del c # 销毁对象
__del__()
方法,因此必须显式调用父类的 __del__()
方法,这样才能保证在回收子类对象时,其占用的资源能被彻底释放自动引用计数
(简称 ARC)的方式实现垃圾回收机制。其核心思想是:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。当对象的的计数器值为 0,则表明没有变量引用对象,即证明程序不再需要它,此时 才会自动调用 __del__()
方法将其回收。dir()
函数一样,__dir__()
方法用于查看对象拥有的所有的属性名和方法名,返回一个包含有所有属性名和方法名的有序列表dir()
函数的内部实现,其实是在调用参数对象 __dir__()
方法的基础上,对该方法返回的属性名和方法名做了排序__dir__()
方法和 dir()
函数输出的数据是相同,仅仅顺序不同对象名.__dir__()
__dict__
属性 : 用于查看类中包含哪些属性__dict__
,会输出该由类中所有类属性组成的字典__dict__
,会输出由类中所有实例属性组成的字典父类、子类互不影响
__dict__
属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改类名.__dict__
对象名.__dict__
类对象.属性
的方式访问类中定义的属性的方法,破坏了类的封装原则。正常情况下,类包含的属性应该是隐藏的,只允许通过类提供的方法来间接实现对类属性的访问和操作,因此python提供了许多类属性操作的高级方法class person :
def __init__(self,name):
self.name = name
# 直接用 对象名.属性 进行操作,破坏了类的封装性
QWQ = person("QWQ")
print(QWQ.name) # 调用属性
QWQ.name = 'LNL' # 修改属性
class person :
def __init__(self,name):
self.name = name
def getname(self) : # getter 方法
return self.name
def setname(self, name) : # setter 方法
self.name = name
def delname(self) : # del 方法
self.name = "xxx"
QWQ = person("QWQ")
print(QWQ.getname()) # 调用属性
QWQ.setname('LNL') # 修改属性
QWQ.delname()
类对象.方法(参数)
的方式来操作属性,python提供了 property()
函数属性名 = property(fget=None, fset=None, fdel=None, doc=None)
获取
该属性值的类方法设置
该属性值的方法删除
该属性值的方法说明
此函数的作用私有属性
,即使用 __属性名
(前面有 2 个下划线)class person:
def __init__(self,name): #构造函数
self.__name = name
def setname(self,name) : #设置 name 属性值的函数
self.__name = name
def getname(self): #访问nema属性值的函数
return self.__name
def delname(self) : #删除name属性值的函数
self.__name = "xxx"
name = property(getname, setname, delname, '姓名操作') #为name属性配置property()函数
print(person.name.__doc__) # 调取说明文档的 2 种方式
help(person.name)
QWQ = person("QWQ")
print(QWQ.name) # 调用 getname() 方法
QWQ.name = "LNL" # 调用 setname() 方法
del QWQ.name # 调用 delname() 方法
对象.属性
的方式操作操作类属性,除了使用 property() 函数,Python 还提供了 @property
装饰器@property
装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对()
小括号@property
def 变量名(self)
代码块
setter
装饰器 :@变量名.setter
def 变量名(self, value):
代码块
当构造函数__init__()中,属性没有加下划线,此时会先执行setter装饰器的设置函数,利用该特性可以在setter装饰器函数中添加判断条件
deleter
装饰器 :@变量名.deleter
def 变量名(self):
代码块
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
@area.setter
def area(self, value):
self.__area = value
@area.deleter
def area(self):
self.__area = 0
rect = Rect(30)
print("矩形的面积是:",rect.area) #直接通过方法名来访问 area 方法
rect.area = 90
print("修改后的面积:",rect.area)
del rect.area
print("删除后的area值为:",rect.area)
__get__()
、__set__()
、__delete__()
的方法
__get__
: 用于访问属性,格式:__set__(self, obj, type )
它返回属性的值,若属性不存在、不合法等都可以抛出对应的异常__set__
:将在属性分配操作中调用,格式 : __get__(self, obj, value)
不会返回任何内容__delete__
:控制删除操作,格式 : __delete__(self, obj)
不会返回内容class Score:
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Score must be integer')
if not 0 <= value <= 100:
raise ValueError('Valid value must be in [0, 100]')
self._score = value
def __get__(self, instance, owner):
return self._score
def __delete__(self):
del self._score
class Student:
math = Score()
chinese = Score()
english = Score()
def __init__(self, name, math, chinese, english):
self.name = name
self.math = math
self.chinese = chinese
self.english = english
def __repr__(self):
return "" .format(
self.name, self.math, self.chinese, self.english
)
QWQ = Student("QWQ", 10, 12, 13)
print(QWQ)
感谢阅读 若有错误 敬请见谅 !!!