【python基础】python面向对象
Python面向对象
面向过程 vs 面向对象
类的组成
语法
class 类名(object):# 代码
class class_name():pass
class class_name:pass
新式类:直接或者间接继承object类,在python3中,所有类默认继承object类。
旧式类:python2,已经过时
创建对象
示例;
class Dog(object):def play(self):print('dog')dog = Dog() # 创建对象
dog.play() # 调用方法
添加属性
# 添加属性,不存在就添加,存在就修改
dog.name = '黄色'
# 获取属性
print(dog.name)
类内部操作属性
需要使用self,作为类方法的第一个形参,再通过对象调用方法的时候,不需要手动传递实参,是python解释器自动将调用该方法的实参传递给self,所以self代表的是对象
self是形参,可以任意修改,但是没必要
class Dog(object):def play(self):print(f'小狗的名字是:{self.name}')dog = Dog()
dog.name = '大黄'
dog.age = 12
dog.play()
# 小狗的名字是:大黄
类的构造函数
在python的类中,有一类函数,将在特定的情况下,会自动调用,格式是两个下划线
__init__()
调用时机:在创建对象后,就会立即调用
作用用来给对象添加属性,给对象一个初始值代码的业务需求,每创建一个对象,都需要执行的代码可以写在'__init__'
class Dog(object):def __init__(self, name, age):print('创建调用了__init__')self.name = nameself.age = agedog = Dog('阿黄', 12)
print(dog.name, dog.age)
# 创建调用了__init__
# 阿黄 12
__str__()
调用时机:1.print打印对象,会自动调用__str__2.str(对象) 类型转换,将自定义转化为字符串的时候,会自动调用
应用:1.打印对象的时候,输出属性的信息2,将对象转换为字符串对象
注意点:只有self 一个参数,返回一个字符串
class Dog(object):def __init__(self, name, age):print('创建调用了__init__')self.name = nameself.age = agedef __str__(self):return f'{self.name} : {self.age}'dog = Dog('阿黄', 12)
print(dog)
# 创建调用了__init__
# 阿黄 : 12
__del__() # 析构函数
调用时机:1。对象在内存中被删除销毁的时候会自动调用代码运行结束,引用计数为0的时候会自动调用
应用场景:引用计数:py中的内存管理机制,指的是,一块内存被多少变量在引用一般很少使用
class Dog(object):def __init__(self, name, age):print('创建调用了__init__')self.name = nameself.age = agedef __str__(self):return f'{self.name} : {self.age}'def __del__(self):print('__del__')dog = Dog('阿黄', 12)
print(dog)
#创建调用了__init__
# 阿黄 : 12
# __del__
继承
描述的类与类之间的所属关系
基本语法
class 类B(类A):pass
称为 B 是 A 的子类
特点:B可以调用A的属性和方法
优点:代码复用
class Animal(object):def __init__(self):print('A __init__')def play(self):print('A: play')class Dog(Animal):def __int__(self):print('B: __init__')dog = Dog()
dog.play()
# A __init__
# A: play
分类
单继承:一个类有单个父类
多继承:一个类有多个父类
多层继承:dog–>animal->object类似于这样的,称为多重继承。
重写方法
定义:子类定义和父类名称相同的方法
重写特点:
重写后,子类优先调用子类自己的方法。
class Dog(object):def play(self):print('Dog: play')class Puppy(Dog):def play(self):print('Puppy: play')puppy = Puppy()
puppy.play()
# Puppy: play
子类调用父类的方法
- 方法一;
class Dog(object):def play(self):print('Dog: play')class Puppy(Dog):def play(self):print('Puppy:play')puppy = Puppy()
Dog.play(puppy)# 需要手动传递实参给self形参,也可以在类内方法内使用
# Dog: play
- 方法二
super(类A,self).方法名(参数) ,会调用A中父类的方法
class Dog(object):def play(self):print('Dog: play')class Puppy(Dog):def play(self):print('Puppy:play')super(Puppy, self).play()puppy = Puppy()
puppy.play()
# Puppy:play
# Dog: play
- 方法三 是方法二的简写
class Dog(object):def play(self):print('Dog: play')class Puppy(Dog):def play(self):print('Puppy:play')super().play()puppy = Puppy()
puppy.play()
# Puppy:play
# Dog: play
继承中的init
class Dog(object):def __init__(self, name):self.age = 0self.name = namedef __str__(self):print('名字为%s 年龄为%d' % (self.name, self.age))class Puppy(Dog):def __init__(self, name, gender):super().__init__(name) # 需要先调用父类的构造方法self.gender = gender # 再写自己的def __str__(self):print('名字为%s 性别是:%s' % (self.name, self.gender))puppy = Puppy('大黄', '雄性')
puppy.__str__()
# 名字为大黄 性别是:雄性
多继承
如果一个类有多个父类,这样的称为多继承
class Dog(object):def play(self):print('Dog play')def eat(self):print('Dog eat')class Puppy(object):def walk(self):print('Puppy walk')class C(Dog, Puppy):passc = C()
c.play()
c.walk()
# 两个父类都存在相同的方法,会调用继承时第一个父类的方法
# Dog play
# Puppy walk
# 类名.__mro__ 可以查看当前继承顺序链。
print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.Dog'>, <class '__main__.Puppy'>, <class 'object'>)
# 指定调用哪个方法,可以使用方法一和二
Dog.eat(c)
# Dog eat
super(A,self).方法(参数)
私有属性
封装的意义:
- 将属性和方法放到一起作为一个整体,然后通过实例化对象来处理
- 隐藏内部的实现细节,只需要和对象及其属性和方法交互就行
- 对类的属性和方法增加访问权限控制
私有权限:在属性名和方法名前面加上两个下划线__
访问权限控制:
- 私有 __加上两个下划线
不能在类外面通过对象直接访问,只能在类内部访问
保证数据的相对安全
想要访问私有属性,可定义方法来访问
class Bank(object):def __init__(self, money):# 私有属性时修改属性的名字,在创建的时候会自动修改属性名# 修改方法:属性名前面加上__self.__money = moneyself.money = moneydef cost(self, price):self.__money -= pricedef showMoeny(self):print(self.__money)person = Bank(1024)
person.showMoeny() # 1024
# 通过__dict__可以查看成员属性信息
print(person.__dict__)
# {'_Bank__money': 1024, 'money': 1024}
私有方法
在方法函数名加上两个__,就成为了私有方法
class Dog(object):def get(self):print('get')def __get(self):print('__get')dog = Dog()
dog.get() # get
dog.__get() # 报错
类属性
对象(实例对象):类实例化成立对象
实例对象的属性是实例属性,通过实例对象(self)定义的属性都是实例属性、
实例属性:每个实例对象都存在一份,并且值可能是不一样的
类(类对象):通过class定义的,是python解释器在创建类的时候自动创建的
作用:
- 通过类对象,去定义实例对象
- 类对象可以保存一些属性信息,称为类属性
- 类属性的定义:在类的内部,方法外部定义的变量就是类属性
- 类属性,在内存中只有一份
如何确定一个属性被定义成实例属性还是类属性?
先假声这个属性为实例属性,查看这个属性对于不同的实例对象,属性值是否都一样,并且需要同时变化
如果不是,就要定义成类属性
class Dog(object):# 定义了类属性class_name = '狗'def __init__(self, name, age):self.name = nameself.age = agedog = Dog('阿黄', 12)
print(dog.__dict__)
print(Dog.__mro__)
# {'name': '阿黄', 'age': 12}
# (<class '__main__.Dog'>, <class 'object'>)
访问类属性
类名.类属性
print(Dog.class_name)
# 狗
修改类属性
类名.类属性 = 属性值
Dog.class_name = '大狗'
print(Dog.class_name)
# 大狗
注意:如果不存在和实例属性相同的类名属性,则可以使用实例对象访问类属性的值
如果存在,使用实例对象访问的也一定是实例属性,可以修改
print(Dog.class_name)
dog.class_name = 'zhangdan'
print(dog.class_name)
# 大狗
# zhangdan
静态方法
使用@staticmethod装饰的方法,称为静态方法,对参数没有要求
前提:
- 不需要使用实例属性,需要使用类属性,可以将这个方法定义为类方法
- 不需要使用实例属性,不需要需要使用类属性,可以将这个方法定义为静态方法
class Dog(object):# 定义了类属性class_name = '狗'def __init__(self, name, age):self.name = nameself.age = age@staticmethoddef play(): # 静态方法print('Dog play')dog = Dog('阿黄', 12)
# 调用方法
dog.play()
Dog.play()
# Dog play
# Dog play
- 如果传参,需要手动传参
多态
概念
在需要使用父类对象方法的地方,也可以传入子类对象,得到不同的结果
实现步骤:
- 子类继承父类
- 子类重写父类的同名方法
- 定义一个共同的方法,参数为父类对象,在方法中调用子类和父类的同名方法
class Dog(object):def play(self):print('Dog play')class Puppy(Dog):def play(self):print('Puppy play')def play_which(self):self.play()# 创建Dog类
dog = Dog()
play_which(dog)
# 创建Puppy类
puppy = Puppy()
play_which(puppy)
# Dog play
# Puppy play