1.面向对象的概念
- 1.1python是一门面向对象的编程语言
- 面向对象就是指所有的操作都是通过对象来进行的
- 面向过程,就是把事件分为诺干步骤,通过对每个步骤的抽象来完成程序,其优点是符合人类的逻辑思维,易于编写,而往往适用单个任务,多种任务代码复用率低。
- 1.2面向对象关注的是对象,不关注过程,将所以的功能统一保存到对象中,要使用功能就去找相关的对象。其优点是易于阅读,方便维护,容易复用,但编写不符合正常的逻辑思维,相对困难。
2.类(Class)
- 2.1python中内置对象int()、str()、list()等,有时我们要在python中建立自定义的对象,这时候我们就要用到类。
- 通过Jerry老师的讲解,我理解类就是在python中定义了一种新的数据类型,所以通过我们自定义类实例化的对象,都属于这个类型。
char = 'I love learning python!' class MyClass: pass mc = MyClass() mc.name = 'Tom' print(id(str),type(str),str)#1853144624 <class 'type'> <class 'str'> print(id(char),type(char),char) #73204128 <class 'str'> I love learning python! print(id(MyClass),type(MyClass),MyClass)#97961864 <class 'type'> <class '__main__.MyClass'> print(id(mc),type(mc),mc)#4318952 <class '__main__.MyClass'> <__main__.MyClass object at 0x0041E6E8>
- 通过上面的例子可以充分说明我们建立的类和str都是一个class 'type'的类型,而它们的实例都是以它们为类型。变量char的类型为class 'str',而变量mc的类型为class 'main.MyClass'。
- isinstance()以前用来判断输入是否是整数
isinstance(a,int)
,实际上它是用来判断对象a是不是int类的实例,所以要判断一个对象是不是类的实例就用isinstance。
a = 1 class MyClass(): pass mc = MyClass() mc2 = MyClass() mc3 = MyClass() mc4 = MyClass() # isinstance() 用来检测一个对象是否是一个类的实例 返回值是布尔类型 isinstance(a,int)#Ture isinstance(mc3,MyClass)#Ture isinstance(a,MyClass)#False
- 2.2类的语法
class 类名([父类]): 代码块
- 2.3类的定义
- 类和对象都是对现实生活中事物的抽象
- 事物(对象)一般包含数据(属性)和行为(方法)。
- 在类的代码块中一般定义变量和函数,变量会成为该类实例的公共属性,所有实例都可以通过实例名.属性名来访问;函数会成为该类实例的公共方法,所有实例都可以通过实例名.方法名()来访问。
class Students():
def __init__(self,name,age):
'''
:param name: 姓名
:param age: 年龄
:param curriculum:学习课程,默认为空字符
'''
self.name = name
self.age = age
self.curriculum = ''
def choose_curriculum(self,*args):
'''
记录学生选的课程
:param args: 可以输入一个或者多个课程名
:return: 课程字符串self.curriculum
'''
for course in args:
if self.curriculum == '':
self.curriculum = course
else:
self.curriculum += f'、{course}'
return self.curriculum
def show_information():
'''
打印学生信息
'''
s1 = Students('郭靖',28)
s1.choose_curriculum('降龙十八掌','九阴真经')
s2 = Students('张无忌',16)
s2.choose_curriculum('九阳神功')
print(f'姓名:{s1.name},年龄:{s1.age},学习科目:{s1.curriculum}。')
print(f'姓名:{s2.name},年龄:{s2.age},学习科目:{s2.curriculum}。')
if __name__ == "__main__":
show_information()
3.参数self
- 3.1属性和方法
- 类中的属性和方法都是公共的,任务该类的实例都可以访问。
- 实例中的属性和方法查找流程,先从实例中查找,如果有则直接返回结果,如果在实例中查找不到时,再查找该实例的类中公共的属性或方法,如果有则返回公共属性或方法,如果还找不到,报错。
- 实例和类中都可以保存属性和方法,公共的属性和方法放在类里,独特的属性和方法放在实例中,一般情况方法放在类中,属性放在实例中。
- 3.2self参数
- 在调用方法时,解释器会自动为方法传递实例给方法的第一个位置参数,因此,在定义方法时,必须要多定义一个位置形参来接收实例,一般情况下我们定义这个形参为self。
- self总是指调用时类的实例。
class A:
n = 8
def n_factorial(a):
r = 1
temp = a.n
while temp > 0:
r *= temp
temp -= 1
print(f'{a.n}的阶乘为{r}')
a = A()
a.n_factorial() #运行结果为8的阶乘为40320
4.特殊方法
- 4.1__init__()方法就是一个特殊方法,调用时机是实例化类时调用此方法,用来定义属性。我的理解是可以用参数传递的方式使我们的每个实例对象的属性个性化。
- 4.2类的特殊方法的学习方法。
- 在什么时机调用特殊方法。
- 了解特殊方法的作用。
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
p = Person('Tom',23)
print(p.name,p.age) #Tom 23
p.name = 'jack'
print(p.name,p.age) #jack 23
5.封装
- 5.1封装的原因
为了数据更安全,主要的是联合开发时告诉同事哪些属性可以变,哪些属性不会变。 - 5.2封装的方法,隐藏属性名,通过getter()和setter()两个方法来获取和修改属性。
- getter()是获取对象中指定的属性
- setter()是用来设置对象中指定的属性
- 属性名,是隐藏属性,实际上是系统改名为类名属性名,我们一般不用这种方法,一般用属性名来告诉别人这个属性是私有的,不要随意更改。
class Fish():
def __init__(self,name,color='金黄色',genre='金鱼'):
self.hidden_name = name
self.__color = color #隐藏属性
self._genre = genre #一般写法
def get_name(self):
return self.hidden_name
def set_name(self, name):
self.hidden_name = name
def get_color(self):
return self.__color
def set_color(self,color):
self.__color = color
def get_genre(self):
return self._genre
def set_genre(self,genre):
self._genre = genre
def speak(self):
print(f'{self.__color}的{self.hidden_name}是{self._genre}')
f1 = Fish('小金')
ff1.speak() #金黄色的小金是金鱼
f1.hidden_name = '金金'
print(f1.get_name()) #金金
f1.speak() #金黄色的金金是金鱼
f1.set_name('小斑')
f1.set_color('红色')
f1.set_genre('东星斑鱼')
f1.speak() #红色的小斑是东星斑鱼
- 5.3装饰器property
- 将方法调用形式改为属性调用形式,这个可以来指明你查看和修改的是属性。
class Fish():
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
@name.deleter
def name(self):
del self._name
f = Fish('小金')
print(f.name)#小金
f.name = '小黑'
print(f.name)#小黑
del f.name
#print(f.name)#'Fish' object has no attribute '_name'
f.name = '小红'
print(f.name)#小红
另外一种使用方法name = property(get_name,set_name,del_name)
,第一种方法你的方法名必须保持一致,这样对于方法命名规则就会有所破坏,要保持命名方法的规则可以用第二种方法,当然在一般情况下单独用@property用的比较多,而setter和deleter用的比较少,所以在一般情况就用@property就可以了。
- 5.4封装的思考
- 封装的作用在独立开发中,可能还看不出来,相反增加了类的复杂度。但是在联合开发中封装却可以避免不必要的bug出现。
- 封装可以在setter方法设置属性时过滤掉不希望出现的错误设置或者进行数据类型判断,同理在输出数据时也可是进行一些优化和操作。
6.继承(object)
- 6.1继承是类的三大特性之一,它使类与类之间产生了关系,有了这个关系看,才有了多态的特性,同时提高了代码的复用性。
- 6.2通过继承使一个类拥有其他类的属性和方法,通常便是方法,在定义类时类名后面的括号内填写父类名,例如:
class B(A): pass
,B是A的子类,A是B的父类或者超类,B继承了A中所以的属性和方法。所有类都是object的子类。
class A(object):
name = '葫芦娃'
def speak(self):
print('我是%s,很高兴认识你!!!'%self.name)
class B(A):
pass
b = B()
b.speak() #我是葫芦娃,很高兴认识你!!!
b.name = '钢铁侠'
b.speak() #我是钢铁侠,很高兴认识你!!!
- 6.3方法的重写,就是在子类中含有和父类相同的方法名时,通过子类实例调用该方法时,直接调用子类的方法,不调用父类方法,这一特性叫做方法重写或覆盖。实例调用方法的顺序是先从实例化的类里找,如果没有则去父类找,如果没有则去父类的父类里找,以此类推,直到object里名都没有找到就报错。(就近原则)
class A(object):
def speak(self):
print('A..........')
class B(A):
def speak(self):
print("B.............")
class C(B):
def speak(self):
print("C.............")
c = C()
c.speak() #C.............
- 6.4super()可以获取当前类的父类,通过super()返回对象调用父类方法时,不需要传递self的参数
class Animal():
def __init__(self,name):
self.name = name
def run(self):
print('%s跑起来了!!!'%self.name)
def sleep(self):
print('%s在睡觉!!!'%self.name)
class Dog(Animal):
def __init__(self,name,age):
super().__init__(name)
self.age = age
def eat(self):
print('%s正在吃骨头!!!'%self.name)
def run(self):
print('狗在跑!!!')
d = Dog('泰迪',3)
d.eat()#泰迪正在吃骨头!!!
d.run()#狗在跑!!!
d.sleep()#泰迪在睡觉!!!
- 6.5多重继承,一个类继承了多个类的属性和方法。python中允许多类继承,在定义类时括号内可以写多个类,如果多个父类里面有方法重名,先从第一个父类开始找,第一个没有找到再找第二个,以此类推,就是排前面的父类方法覆盖拍后面的父类方法。一般情况下要避免使用多重继续,这会使程序复杂化。
class A():
def speak(self):
print('A...........')
class B():
def speak2(self):
print('B...........')
class C(A,B):
pass
c=C()
c.speak() #A...........
c.speak2() #B...........
7.多态
- 7.1多态是面向对象三大特性之一,就是一个对象有多种形态去呈现。差了下百度,多态指同一操作作用与不同类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,将得到不同的结果。
class Person:
def __init__(self,name,age):
self._name = name
self.age = age
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class Pets:
def __init__(self,name):
self._name =name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
class C:
name ='超人'
p1=Person('张三',23)
p2=Pets('喵喵')
p3=C()
def speak(obj):
print(f'大家好,我是{obj.name}。')
speak(p1)#大家好,我是张三。
speak(p2)#大家好,我是喵喵。
speak(p3)#大家好,我是超人。
- 7.2多态我的理解就是同一件事情让不同的类去做,结果是多样的,举个不恰当的例子,就是一群动物赛跑,发令枪一响,动物们都开始跑了,鸟是用飞的,乌龟是爬的,兔子是用跳的。每个对象都用它自己的逻辑结构去完成同一件事,都得到它自己想要的结果。
-7.3面向对象三大特性- 封装:保证数据的安全性。隔离设计者和使用者
- 继承:确保了对象的扩展性。扩展时只要新类继承旧类就可以
- 多态:保持了程序的灵活性。一个功能可以给多个对象使用。
8.类的属性和方法
- 8.1类属性
- 实例属性,实例可以访问,类无法访问。
- 类属性,实例和类都可以访问。如果在实例中重新定义类属性,实例中的对应类属性改变,类属性本身没有变化。
- 魔法方法init定义的属性是实例属性。
class A:
name = 1
def __init__(self):
self.age = 26
print(A.name) #1
a = A()
print(a.name) #1
a.name = 'Marry'
print(a.name,A.name)#Marry 1
print(a.age) #26
print(A.age) #AttributeError: type object 'A' has no attribute 'age'
- 8.2类方法
- 类中定义的方法一般都是实例方法。
- 类方法的定义格式,在定义前加装饰器
@classmethod
,同时方法中默认拥有cls形参,cls代表的是这个类。实例和类都可以调用。 - 类的静态方法,格式一般为
@staticmethod
,该方法没有默认形参,不能使用该类的任何属性和方法,一般情况为工具方法,放置一些没有具体类的方法。实例和类都可以调用静态方法。
class A:
def __init__(self):
self.age = 26
@classmethod
def speak(cls):
print('我是类方法',cls)
@staticmethod
def tools():
#print('我是静态方法',self.name)#无法使用该类的属性和方法
print('我是静态方法!')
a =A()
a.speak()#我是类方法 <class '__main__.A'>
A.speak()#我是类方法 <class '__main__.A'>
a.tools()#我是静态方法!
A.tools()#我是静态方法!