文章目录
一、面向对象
面向对象是基于万物皆对象这个哲学观点。在Python中,一切皆对象
面向对象只是一种思想,并不是一门编程语言,也不会绑定编程语言
面向过程和面向对象的优缺点
面向过程:
优点:性能比面向对象高,比如单片机、嵌入式开发等一般采用面向过程开发,因为性能是最重要的因素
缺点:没有面向对象易维护,易复用,易扩展,开销比较大,比较消耗资源
面向对象:
优点:易维护,易复用,易扩展【由于面向对象有封装,继承,多态的特性,可以设计出低耦合的系统,使
得系统更加灵活,更加易于维护】
缺点:性能比面向过程低
1.类和对象
1.1 概念
类:一个具有特殊功能的实体的集合【群体】,是抽象的
对象:在一个类中,一个具有特殊功能的实体,能够帮忙解决特定的问题【对象也被称为实例】,是具体的
两者之间的关系:类用于描述某一类对象的共同特征,而对象则是类的具体存在
1.2 类的定义和对象的创建
格式:
class 类名():
类体
说明:
a.Python中使用class关键字定义类
b.类名只要是一个合法的标识符即可,但是要求:遵循大驼峰命名法 ,如:KeyError,ValueError,NameError,IndexError…….
c.尽量使用单个或多个有意义的单词连接而成
d.通过缩进来体现类体的存在
e.类体一般包含两部分内容:对类的特征描述和行为描述
# 一、类的定义
# 1.基本语法
# a.函数
# 函数的声明和实现
def func():
print("ok") # 函数体
print(func) # 函数本身:<function func at 0x102587f70>
func() # 调用函数:执行函数
# b.类
# 类的声明和实现
class Func():
pass # 类体
print(Func) # 自定义类:<class '__main__.Func'>
Func() # 创建对象
"""
注意:
a.同一个py文件中可以定义多个类,但是,在实际项目开发中,如果需求较为复杂,类的定义建议一个py文件定义一个类
b.当一个函数定义完毕,则需要手动调用,否则无法执行
当一个类定义完毕,当类被加载的时候,其中的类体也会被加载
"""
# 二、创建对象/类的实例化
# 语法:对象名 = 类名(....),目前为空
mc1 = MyClass1()
print(mc1) # <__main__.MyClass1 object at 0x10726bdc0>
print(type(mc1)) # <class '__main__.MyClass1'>
"""
注意:
a.创建对象的过程,本质上就是定义变量的过程,该变量中存储的是创建出来的对象的地址
b.打印对象的时候,默认的情况下,打印的是该对象在内存空间中的地址,
但是,像int,str,list。。。常用的数据类型,系统已经处理过了,所以直接打印结果
c.一个普通的类,可以创建无数个对象,每个对象在内存空间中拥有独立的地址
d.对象名 = 类名(....)表示创建对象,但是该代码执行一次,则表示创建一个新的对象
"""
2.类中的成员/类体
2.1 成员函数的定义和访问
# 一、类中成员函数的定义
# 1.类的定义
class Person():
# 2.多个对象共同的特征:变量
# 3.多个对象共同的行为:函数
"""
说明:
a.self:自身,自己,在面向对象的函数中,self表示当前对象
b.哪个对象调用函数,则该函数中的self表示就是哪个对象
c.当调用函数的时候,self不需要手动传参,系统会自动完成传参,传递的是当前对象,只需要关注自定义的参数即可
d.在Python中,self并不是一个关键字,只要是个合法的标识符即可,但是,为了表示当前对象,一般使用self
"""
# 实例函数/对象函数,特点:第一个形参必须是self,只能由对象调用
def run(self):
print("running",id(self))
def eat(self,sth):
print("eating" + sth)
# 二、类中成员函数的访问
# 注意1:类和函数相似,会引入新的作用域,所以在类中定义的函数在类的外面无法直接调用
# 注意2:行为主要是由对象执行的,所以类中的函数需要调用,可以通过对象调用,语法:对象.函数(实参)
p1 = Person()
print("p1~~~~~~",id(p1))
p1.run()
2.2 动态绑定属性和限制绑定
# 类中多个对象共同的特征:变量,也被称为属性
# 通过动态绑定的属性被称为对象属性或实例属性
# 1.对象属性的动态绑定
# 语法:对象.属性 = 值
class Person():
def show(self):
print(f"姓名:{self.name},年龄:{self.age},身高:{self.height}")
# 创建对象
p1 = Person()
# 动态绑定属性
p1.name = '张三'
p1.age = 18
p1.height = 170
print(p1.name,p1.age,p1.height)
# 调用实例函数
p1.show()
p2 = Person()
# 注意1:给一个对象动态绑定的属性,另一个对象未绑定的情况下无法访问
# print(p2.name) # AttributeError: 'Person' object has no attribute 'name'
# 注意2:不同的对象绑定了同名的属性,当一个对象的属性值发生改变时,对另一个对象的属性没有影响
print(p1.name,p2.name)
p1.name = 'jack.张'
print(p1.name,p2.name)
# 2.限制绑定对象的属性
class People():
# 给系统属性__slots__定义一个元组,元组的元素就是允许绑定的属性字段名称
# 注意1:为了限制当前类创建的对象只能绑定指定的属性
# 注意2:如果只需要限制一个属性,则书写元素的时候,注意添加逗号,如: __slots__ = ("name",)
__slots__ = ("name", 'age', 'height')
def show(self):
print(f"姓名:{self.name},年龄:{self.age},身高:{self.height}")
p2 = People()
p2.name = '李四'
p2.age = 10
p2.height = 180
# p2.hobby = 'dance' # AttributeError: 'People' object has no attribute 'hobby'
p2.show()
3.构造函数
"""
先创建对象,然后使用直接赋值【动态绑定属性】方式给对象绑定属性,可以使用,但是代码比较繁杂,一般情况下,很多类倾向于将对象创建为有初始状态的,常规用法中,在类中可以定义一个函数,名称为__init__,该特殊的函数被称为构造函数,主要用于给对象的数据做出初始化
强调:构造函数包括__new__和__init__
注意:在Python中,以__xxx__方式命名的函数被称为魔术函数/魔术方法,这类函数在使用的时候无需手动调用,在进
行某个操作的时候会自动调用
构造函数,也被称为构造器,指的是当创建对象的时候,被自动调用的函数
"""
语法:
def __new__(cls,*args,**kwrags):
pass
def __init__(self):
pass
*******************************
class Person1():
__slots__ = ('name','age','address')
def __init__(self,name,age):
print("init被调用了~~~~~",id(self),name,age)
# 动态绑定属性
self.name = name
self.age = age
self.address = '北京' # 默认值
def show(self):
print(f"姓名:{self.name},年龄:{self.age}")
p1 = Person1('张三',10)
# print(id(p1))
print(p1.name,p1.age)
p1.show()
"""
总结:
a.p1 = Person1()表示创建对象,当创建对象的时候,会自动调用__init__,__init__中的self表示当前对象
b.如果需要给对象动态绑定属性,为了代码的可读性和后期的可维护性,一般将动态属性的绑定书写在__init__中
c.在__init__中动态绑定属性,如果需要创建对象的时候传参,则设置形参,如果不需要传参,则可以直接定义
d.当给__init__设置了和属性相关的参数之后,当创建对象的时候,一定要注意参数的匹配
例如:p1 = Person1('张三',10)
def __init__(self,name,age)
将'张三'和10会自动传参给name和age
"""
# 构造函数的工作原理
class Animal():
__slots__ = ('name','age')
def __new__(cls, *args, **kwargs):
print("new~~~~~~~")
# super().__new__(cls)表示创建对象
return super().__new__(cls)
def __init__(self,name,age):
print("init~~~",id(self))
self.name = name
self.age = age
a = Animal("大黄",4)
print(a) # <__main__.Animal object at 0x1043e6cd0>
print(id(a))
"""
总结:
a.真正意义上,构造函数包含__new__和__init__
b.在实际开发中,常用__init__,因为__new__在类中没有定义,当创建对象的时候仍然会自动调用
c.__new__:表示创建对象,该函数的返回值就是创建出来的对象
例如:a = Animal("大黄",4),a指向__new__的返回值
__init__:表示初始化对象,系统会自动将__new__的返回值【创建的对象】会自动传参给__init__中的self,
同时,将需要初始化的值传参给__init__中的其他参数,完成对象初始化的过程
d.构造函数中,当创建对象的时候,都是先调用__new__,然后才调用__init__
"""
4.类属性和实例属性
"""
类属性【类的字段】和实例属性【对象属性,对象的字段】的区别
1.定义位置不同:类属性直接定义在类中,实例属性定义在__init__中或在类的外面直接动态绑定定义
2.访问方式不同:类属性可以通过类名或对象访问,而实例属性只能通过对象访问
3.访问优先级不同:当类属性和实例属性重名时,通过对象访问,优先访问的是实例属性
4.在内存中出现的时机不同:类属性优先于实例属性出现在内存中,类属性随着类的加载而出现,实例属性是对象创建
完毕之后才会出现
5.使用场景不同:类属性用于表示多个对象共享的数据,实例属性表示每个对象特有的数据
"""
# 1.定义位置:类属性直接定义在类中,实例属性定义在__init__中或在类的外面直接动态绑定定义
class Person():
# 类属性:直接定义在类中
num = 13
data = "abc"
def __init__(self,name,age):
# 实例属性:给对象动态绑定
self.name = name
self.age = age
self.num = 66
p = Person('jack',23)
# 实例属性:给对象动态绑定
p.hobby = 'dance'
# 2.访问方式:类属性可以通过类名或对象访问,而实例属性只能通过对象访问
# a.类属性
print(Person.num)
print(p.num)
# b.实例属性
print(p.name)
# 3.访问优先级不同:当类属性和实例属性重名时,通过对象访问,优先访问的是实例属性
print(p.num) # 66
del p.num # 因为优先访问实例属性,所以删除的是实例属性
print(p.num) # 13
# 注意1:对象.属性 = 值,该语法都表示给当前对象动态绑定属性,或给指定对象修改实例属性,
# 哪怕类属性和实例属性同名,也表示实例属性
# p.data = 'hello' # 并不是修改类属性,而是给p对象动态绑定了一个data实例属性
print(Person.data) # abc
print(p.data) # hello
# 注意2:如果需要修改类属性,则必须通过类名访问,语法:类名.类属性 = 值
Person.data = 'xyz'
print(Person.data) # xyz
print(p.data) # xyz
# 5.使用场景不同:类属性用于表示多个对象共享的数据,实例属性表示每个对象特有的数据
class Student():
# 类属性
school_name = '1000phone'
def __init__(self,name,hobby):
# 实例属性
self.name = name
self.hobby = hobby
5.内存中的对象
不同对象访问同一个类属性,访问的是同一份内存空间,通过 类名.属性 = 值 修改类属性,一旦被修改所有对象访问到的结果都会随着修改
不同对象的同名的实例属性,在内存中是不同的内存空间,一个发生修改,对另一个没有任何影响
6.析构函数
"""
析构函数__del__调用的时机:当对象被销毁的时候
"""
class Person():
def __init__(self):
print("构造函数被调用了")
def __del__(self):
print("析构函数被调用了~~~~~")
# 1.当对象被定义为全局变量,当程序结束之后,__del__会被自动调用
# print("start")
# p1 = Person()
# print("over")
"""
start
构造函数被调用了
over
析构函数被调用了~~~~~
"""
# 2.当对象被定义为局部变量,当函数调用完毕,__del__会被自动调用
# def func():
# p1 = Person()
# print("start")
# func()
# print("over")
"""
start
构造函数被调用了
析构函数被调用了~~~~~
over
"""
# 3.当对象被del删除,则__del__会被自动调用
print("start")
p1 = Person()
del p1
print("over")
"""
start
构造函数被调用了
析构函数被调用了~~~~~
over
"""