> 文章列表 > 【python基础】python面向对象

【python基础】python面向对象

【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