python 10天快速教程 Day7
2020-07-16 本文已影响0人
XaviSong
本节重点
- 面向对象介绍
- 简单类与对象
- 魔法方法
- 继承、super
- 私有属性与私有方法
一、面向对象介绍
- 面向过程:直观理解就是完成某个功能,通过流程控制按照步骤执行,程序清楚实现的细节。
- 面向对象:调用你的对象,通过对象的方法去完成这个功能。程序不清楚实现细节
二、简单类与对象
1、类与对象的关系
- 以手机为例:
- 类:iphone X的图纸(只有一张)
- 对象:syp的iphoneX,dsy的iphoneX,这些都是。(可以有多台)
2、类的创建
使用class关键字,创建属性与方法。使用新式类的创建形式:class + 类名 + (继承自的父类)。
self,类中的方法中参数,指调用这个方法的对象,说明这个方法要有对象来调用,不能直接使用。
示例:
class Player(object): # 新式类的创建方式
# 属性
country = "France"
# 方法
def show(self):
print("我来自法国")
1、通过类创建对象:
player1 = Player()
print(player1) # 内存中开辟了一块空间,空间中存的是对象的内存地址
'''
<__main__.Player object at 0x000002BF92338390>
'''
2、通过对象查看属性:
print(player1.country)
'''
France
'''
3、通过对象调用类方法:
player1.show()
'''
我来自法国
'''
4、查看继承自哪个父类:
print(Player.__base__)
'''
<class 'object'>
'''
5、动态为类添加属性:
Player.wage = 100000
Player.age = 18
print(Player.wage,Player.age)
'''
100000 18
'''
三、类的魔法方法
定义:
类中某些固定名称的方法,在当前需要完成某个功能的操作时,类自行调用,无需对象显式调用。
固定名称:
双下划线开头,双下划綫结尾。如:
__new__,__init__,__str__,__del__等
1、__ new __方法:
当前对象创建的时候就会调用。创建对象时先调用new,然后调用init进行初始化,表示对象创建完成
class Student(object):
def __new__(cls,*args):
print("new一个对象")
print(args) #必须返回父类的new方法(相当于创建对象)
return object.__new__(cls)
def __init__(self,name,age):
super().__init__()
self.name = name
self.age = age
print("初始化完毕")
stu = Student("syp",18)
'''
new一个对象
('syp', 18)
初始化完毕
'''
2、__ init __方法:
根据类创建当前对象时,自动调用这个方法进行初始化,在__ new __之后。
示例:
class Player(object):
# 属性
def __init__(self):
self.country = "France"
print("自行调用")
# 方法
def show(self):
print("我来自法国")
p1 = Player()
'''
自行调用
(对象一创建,自动调用,会直接打印出上行内容)
'''
print(p1.country) # 实例属性已经初始化
'''
France
'''
3、__ str __ 、__ del __方法
__ str __: 当使用print打印通过该类创建的对象时调用。
__ del __:对象释放自动调用,程序退出或手动删除一个对象时都会调用(原则:引用计数为0时调用)
示例:
import time
class Player(object):
# init方法中定义实例属性
def __init__(self,country,name,age):
self.country = country
self.name = name
self.age = age
print(self.country,self.name,self.age)
# str方法定义print该对象时的信息
def __str__(self):
return "%s来自于%s联赛,现年%d岁"%(self.name,self.country,self.age)
# del方法
def __del__(self):
print("对象释放完毕")
p1 = Player("法国","内马尔",27)
p2 = Player("法国","姆巴佩",19)
time.sleep(3)
print(p1)
'''
法国 内马尔 27
法国 姆巴佩 19
内马尔来自于法国联赛,现年27岁
对象释放完毕
对象释放完毕
'''
4、__ del __结合引用计数理解:
引用计数:内存地址的使用次数
p1 = Player("法国","内马尔",27) # 内存中开辟一块空间,引用计数0->1
p3 = p1 # 引用计数1->2
del p1 # 这里不调用del,因为引用计数还是1
time.sleep(3)
print("程序退出")
'''
法国 内马尔 27
程序退出
对象释放完毕 (退出之后才调用del)
'''
四、继承、super
继承的好处:子类可以复用父类的方法属性。避免冗余代码,基类(父类)中可以放一些重复的代码。反之,父类不可以使用子类的属性与方法。
(1)单继承示例:
class Player(object):
# init方法中定义实例属性
def __init__(self,country,name,age):
self.country = country
self.name = name
self.age = age
def show(self):
print(self.country,self.name,self.age)
# 定义明星球员类
class starplayer(Player):
pass
s1 = starplayer("法国","内马尔",27) # 使用Player父类的属性
s1.show() # 使用player父类方法
(2)多继承示例:
类的继承顺序,影响调用哪个父类方法。通过类名调用mro()方法,找到继承链条,沿链条向上查找方法。
class A(object):
def show(self):
print("我是A类")
class B(object):
def show(self):
print("我是B类")
# 定义一个多继承的类C,继承自A,B
class C(A,B):
pass
# 类的继承顺序,影响调用哪个父类方法
c = C()
c.show()
# 查看类的继承顺序,沿链向上找,没有就一直向上,最终还没有就报错
print(C.mro())
'''
我是A类
[<class '__main__.C'>, <class '__main__.A'>, <class'__main__.B'>, <class 'object'>]
'''
(3)重写父类方法:
子类继承父类,但是父类方法难以满足子类,可以重写进行覆盖。调用时先从子类找,子类没有就遵循mro原则,向上父类、父类的父类查找(就近原则)。
# 父类
class Father(object):
def run(self):
print("在运行")
# 子类
class Son(Father):
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print("%s 在运行"%self.name)
son = Son("syp",19)
son.run()
'''
syp 在运行
'''
(4)super调用父类方法:
示例:
# 父类
class Father(object):
def run(self):
print("在运行")
# 子类
class Son(Father):
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
# Son表示要去mro链条中获取Son的下一个类
# self表示你要找的是当前类的继承链
print(self.__class__.mro())
super(Son,self).run()
def soccer(self):
print("我在踢足球")
son = Son("syp",19)
son.run()
'''
[<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>]
(Son的下一个是Father,所以去调用Father的run方法)
'''
多继承的情况也是一样的,继承链不分叉,想调用哪个父类的方法,按照super参数按照类型链传就可以了
class A(object):
def show(self):
print("我是A类")
class B(object):
def show(self):
print("我是B类")
# 定义一个多继承的类C,继承自A,B
class C(A,B):
def show(self):
super().show() # 默认去本链的父类,等价于super(C,self).show()
c = C()
c.show()
'''
我是A类
'''
# 如果这样写super参数
class C(A,B):
def show(self):
super(A,self).show()
c = C()
c.show()
'''
我是B类
'''
(5)init方法中的super:
示例:
class Father(object):
def __init__(self,name):
print("father")
self.name = name
# 子类
class Son(Father):
def __init__(self):
print("son")
s = Son()
print(s.name) # 报错,因为init被重写,并没有继承name属性
super的作用
想继承、就要调用父类的init方法
# 父类
class Father(object):
def __init__(self,name):
print("father")
self.name = name
# 子类
class Son(Father):
def __init__(self):
super(Son,self).__init__("syp")
s = Son()
print(s.name)
'''
father
syp
'''
五、私有属性与私有方法
- 私有属性:在属性名前加上双下划线,那么定义的属性就为私有属性
- 私有方法:在方法名前加上双下划线,那么定义的方法就是私有方法
外部访问不了
示例:
class Person(object):
def __init__(self,name,age):
self.name = name # 公有属性
self.__age = age # 私有实例属性
def show(self):
pass
def __wage(self):
print("1000000")
p = Person("syp", 19)
print(p.age)
p.__wage()
'''
报错,提示person没有属性age,没有__wage方法
'''
注意:以下代码是添加了同名公有属性,不是访问私有属性
# 动态添加
p.__age = 20
print(p.__age)
查看对象中的属性、方法信息
print(p.__dict__)
'''
{'name': 'syp', '_Person__age': 19, '__age': 20}
私有属性有前缀_Person
'''
print(Person.__dict__)
'''
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002335E2A0C80>, 'show': <function Person.show at 0x000002335E2A0488>, '_Person__wage': <function Person.__wage at 0x000002335E2A0F28>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
打印方法所在的内存地址
'''
注意:在python中没有真正的私有方法与私有属性
硬访问:
根据刚才我们看到的前缀,配合前缀使用就可以访问私有的属性和调用私有方法
p._Person__age = 18
print(p.__dict__)
'''
19
'''
p._Person__wage()
'''
1000000
'''