8.1类与对象的基础运用
类是抽象的,对象是类的实例
8.1.1类的定义
class 类名:
属性名=属性值
def 方法名(self):
方法体
类名:
大驼峰命名法:首字母一般为大写
方法参数列表中的第一个参数是一个指代对象的默认参数self
class Car:
wheels=4
def drive(self):
print('行驶')
8.1.2对象的创建与使用
对象名=类名()
car=Car()
访问属性或调用方法的语法格式:
对象名.属性名
对象名.方法名()
print(car.wheels)
car.deive()
8.2类的成员
8.2.1 属性
属性根据声明方式有两类:类属性和实例属性。
- 类属性
类属性是声明在类內部、方法外部的属性。
例如上边的wheels。类属性可以通过类或对象进行访问,但是只能通过类进行修改。
- 实例属性
实例属性是在方法内部声明的属性,py支持动态添加实例属性。
(1)访问实例属性
实例属性只能通过对象访问。
对象名.属性名
(2)修改实例属性
对象名.属性名=修改后的值
(3)添加实例属性
对象名.属性名=添加的属性值
属性名好像可以重复
8.2.2方法
py中的方法有三种:
实例对象、类方法、静态方法
- 实例方法
实例方法定义在类內部,以self为第一个形参。实例方法中的self代表对象本身,他会在实例方法被调用的时候自动接收由系统传递的调用该方法的对象。
实例方法只能通过对象调用。
def drive(self):
print('我是实例方法')
2.类方法
类方法定义在类内部:
@classmethod
def 类方法名(cls):
方法体
类方法列表参数中的第一个参数是cls 代表类本身,他会在类方法被调用的时候自动接收由系统传递的调用该方法得类。
类方法可以由类和对象调用。
类方法可以修改属性
class Car:
whells=6
@classmethod
def stop(cls):
print('我是类方法')
cls.whells=7
car=Car()
print(car.whells)
print(Car.whells)
car.stop()
print(car.whells)
print(Car.whells)
3.静态方法
静态方法定义在类內部
@staticmethod
def 静态方法名():
方法体
静态方法可以通过类和对象调用。
静态方法内部不能直接访问属性或方法,但可以通过类名访问属性,或调用类方法。
class Car:
whells=6
@staticmethod
def test():
print('我是静态方法')
print(f'类属性的值是{Car.whells}')
car=Car()
car.test()
8.2.3私有成员
py默认成员是共有的。就是可以通过类或对象随意访问。
当属性名或方法名前边加“__”双下划线就代表当前的成员是私有的。
__属性名
__方法名
私有成员在类的外部不能直接访问,但是可以调用类的公共方法访问。
class Car:
__wheels=6
def _drive(self):
print('行驶')
def test(self):
print(f"轿车有{self.__wheels}轮胎")
self._drive()
car=Car()
print(car.test())
8.3特殊方法
8.3.1构造方法
在创建的时候负责对象的初始化。每个类默认有一个__init__()方法,如果显式的定义了__init__()方法那么创建对象的时候调用显式的构造方法,否则调用默认的。
构造方法分两种:
有参构造方法和无参构造方法。
当使用无参构造方法的时候,所有对象的值都有相同的初始值。
当使用有参构造方法时,所有对象的属性可以是不通的初值。
class Car:
def __init__(self):
self.color='红色'
def drive(self):
print(f"车的颜色是:{self.color}")
car_one=Car()
car_one.drive()
car_tow=Car()
car_tow.drive()
class Car:
def __init__(self,color):
self.color=color
def drive(self):
print(f"车的颜色是:{self.color}")
car_one=Car("红色")
car_one.drive()
car_tow=Car("蓝色")
car_tow.drive()
突然感觉这里的self和Java中的this差不多,都表示本类。
构造方法每次创建对象都会被加载,我是理解成构造对象时用的方法。
class Car:
def __init__(self,color):
self.color=color
print('构造方法被加载')
def drive(self):
print(f"车的颜色是:{self.color}")
car_one=Car("红色")
car_one.drive()
car_tow=Car("蓝色")
car_tow.drive()
8.3.2 析构方法
__del__()放法
是销毁对象时系统自动调用的特殊方法。每个类都有一个__del__()方法。如果一个类显式定义了析构方法,销毁对象的时候会调用显式的,如果没有显式定义,就会调用默认的。
class Car:
def __init__(self) -> None:
self.color='蓝色'
print('对象被创建')
def __del__(self):
print('对象被销毁')
car =Car()
print(car.color)
del car
print(car.color)
py会通过引用计数器销毁对象,当引用计数器为0时系统会销毁对象。
8.4封装
封装是面向对象的重要特性之一,它的基本思想是对外隐藏类的细节,提供用于访问类成员的公开接口。
类的外部无须知道实现细节,只需要使用公开接口便可以访问类的内容,故在一定程度上保证了类内数据的安全。
为契合封装思想,在定义类的时候需要满足2点要求:
将属性声明为私有属性
添加两个供外界调用的公有方法,分别用于设置或获取私有属性的值。
class Person:
def __init__(self,name) -> None:
self.name=name
self._age=1
#设置私有属性的方法
def set_age(self,new_age):
if 0<new_age<=120:
self._age=new_age
#获取私有属性的值
def get_age(self):
return self._age
person=Person('小明')
print(f'年龄为{person.get_age()}岁')
person.set_age(66)
print(f'年龄为{person.get_age()}岁')
8.5继承
8.5.1单继承
一个子类只能继承一个父类
class 子类名 (父类名)
和java一样,子类继承会自动拥有父类的公有成员,若在定义的时候不指明该类的父类,那么就会默认继承基类object
#继承
# 单继承
class Cat(object): #object写不写没啥意义
def __init__(self,corlor) -> None:
self.corlor=corlor
def walk(self):
print('走猫步~~~')
#定义继承Cat类的子类scottishFold
class ScottishFold(Cat): #创建一个类
pass
fold =ScottishFold("灰色") #创建一个对象
print(f"{fold.corlor}的折耳猫")
fold.walk()
和java一样父类的私有属性和方法 子类是不能访问的。
class Cat(object): #object写不写没啥意义
def __init__(self,corlor) -> None:
self._corlor=corlor
def _walk(self):
print('走猫步~~~')
#定义继承Cat类的子类scottishFold
class ScottishFold(Cat): #创建一个类
pass
fold =ScottishFold("灰色") #创建一个对象
print(f"{fold.corlor}的折耳猫")
fold.walk()
8.5.2多继承
class 子类名(父类名1,父类名2···)
#多继承
#定义一个表示房子的类House
class House:
def live(self):
print('供人类居住')
#定义一个汽车类
class Car:
def drive(self):
print('方便人类出行')
#定义一个表示房车的类,继承House和Car
class TouringCar(House,Car):
pass
tour_car=TouringCar()
tour_car.live()
tour_car.drive()
如果两个父类都有相同的方法,那么会调用先继承的类中的方法。
8.5.3重写
子类有时候感觉父类的方法不太合适,就可以更改,方法和java相似,只需要写一个名字相同的就好了,这样调用的时候就调用子类重写的方法了。如果重写后又想调用之前的方法了,就可以用
super().方法名()
py中好像不能有方法的多态,就是名字相同形参不同那种。py中这样写好像就是会只认识后边的方法。
?????????????????????????????????????????????
子类访问父类的方法就是可以用super().方法名。
然会就是
class Person():
def say(self):
print('666')
class Person2(Person):
def say(self):
print(999)
def say(self):
super().say()
p=Person2()
p.say()
如果我同时继承了多个父类,父类中有同名方法,我想调用某个父类的同名方法怎么办呢?
去博客了解了下发现有两种方法。
类名.方法名
super(类前边的类,self).方法名
class C1:
def test(self):
print('=========c1=======')
class C2:
def test(self):
print('=========c2=======')
class C3:
def test(self):
print('=========c3=======')
class C4(C1,C2,C3):
def test(self):
print('=========c4=======')
ctest=C4()
ctest.test()
class C1:
def test(self):
print('=========c1=======')
class C2:
def test(self):
print('=========c2=======')
class C3:
def test(self):
print('=========c3=======')
class C4(C1,C2,C3):
def test(self):
C1.test(self)
C2.test(self)
C3.test(self)
print('=========c4=======')
ctest=C4()
ctest.test()
class C1:
def test(self):
print('=========c1=======')
class C2:
def test(self):
print('=========c2=======')
class C3:
def test(self):
print('=========c3=======')
class C4(C1,C2,C3):
def test(self):
super(C4,self).test()
super(C1,self).test()
super(C2,self).test()
print('=========c4=======')
ctest=C4()
ctest.test()
8.6多态
#多态
class Cat:
def shout(self):
print('喵喵喵')
class Dog:
def shout(self):
print('汪汪汪')
def shout(obj):
obj.shout()
cat=Cat()
dog=Dog()
shout(cat)
shout(dog)
重点是第八行,其实是定义了一个方法,书上说接口,这个接口会接收一个对象,然后调用对象的某个方法。
8.7运算符重载
py中赋予了运算符的特殊方法,我们可以根据重写运算符的方法来达到便捷的目的。
举例:
class Calculator:
def __init__(self,number) -> None:
self.number=number
def __add__(self,other):
self.number=self.number+other
return self.number
def __sub__(self,other):
self.number=self.number-other
return self.number
def __mul__(self,other):
self.number=self.number*other
return self.number
def __truediv__(self,other):
self.number=self.number/other
return self.number
claculator=Calculator(10)
print(claculator+5)
print(claculator-5)
print(claculator*5)
print(claculator/5)