Pyhton第6天之深入理解类

深入理解Python中的类

简介

在Python中,类是实现面向对象编程(OOP)的主要工具。它们允许我们创建自定义的数据结构,它包含了数据和对数据操作的方法。本文将帮助你理解Python中类的工作原理,以及如何有效地使用它们。

类的基本概念

定义一个新式类

在Python中定义一个类使用关键字class

class Person(object):
    # 定义两个方法
    def eat(self,food):
        print('吃', food)
    def sleep(self,t):
        print('每天至少睡',t,'小时')

创建实例

要使用类,我们需要创建它的实例:

实例对象后,会在内存中分配一块空间,这个空间就是实例对象的位置

tom = Person()

实例多个对象

实例多个对象会在内存中分配不同的空间,然后将地址引用给对象名。

a = Person()
b = Person()
c = Person()

print(a)
print(b)
print(c)

'''
输出
<__main__.MyClass object at 0x000002D374234E80>
<__main__.MyClass object at 0x000002D3745783D0>
<__main__.MyClass object at 0x000002D37433A5E0>
'''

当我们创建一个类的实例时,__init__方法会被自动调用,接受我们传递的参数(在这个例子中是"我是一个实例属性")。

访问属性和方法

创建实例后,我们可以访问其属性和方法:

tom.eat('饭')
tom.eat('海鲜')
tom.sleep(8)
'''
输出
吃 饭
吃 海鲜
每天至少睡 8 小时
'''

私有属性和方法

私有属性

在Python中,私有属性是指在类的内部使用的属性,它不应该被类的外部所访问。Python并没有真正的私有化支持,但是有一种约定可以使属性变得像是私有的,其方式是通过在属性名前加上双下划线(__)来实现。

定义属性时,没有任何修饰的都是公有属性,如果在属性或方法前,加上两个下划线,那么这个属性或方法,python解释器就会认为是私有的。

class Account(object):
    def __init__(self,name,balance):
        # 定义了两个公有属性,这两个属性在类的外部也是可以访问的
        # self.name = name
        # self.balance = balance
        # 因为公有的属性破坏程序的封装性,导致数据不安全,所以将属性定义私有的
        # 当一个类中的属性或方法,全部是私有时,这个类是无意义的(因为与外界完全隔离了)
        self.__name = name
        self.__balance = balance
    # 私有属性定义好后,可以保证数据 的访问安全
    # 但是还有需求去属性进行访问,可以通过公有接口方法进行间接 访问
    # 一般对私有属性会提供 一种 称为 存取器方法的公有方法
    # set/ get方法
    # set_属性名  get_属性名
    # 因为帐户名一旦确认后无需修改,所以可以不提供 set 方法
    # def get_name(self):
    def get_username(self):
        return self.__name
 # 给余额提供 存取方法
    def set_balance(self,new_balance):
        if isinstance(new_balance,int):
            #isinstance(对象,类型)检查对象是否属于某种类型
            self.__balance = new_balance
        else:
            print('不能存玉皇大帝的钱')

    def get_balance(self):
        return self.__balance
    # 定义一个查看信息的方法
    def show_info(self):
        # 在类的内部,访问对象的私有属性
        print(self.__name + ' 有 ', self.__balance, '元')
jack = Account('JackMa',9999999)
print(jack.get_username())
print(jack.get_balance())

jack.set_balance(88888888)
print(jack.get_balance())
jack.set_balance('十个亿')
money = jack.get_balance()
print(money)
'''
输出
JackMa
9999999
88888888
不能存玉皇大帝的钱
88888888
'''
私有方法

在Python中,私有方法是指那些不应该在类的外部被直接调用的方法。就像私有属性一样,Python通过在方法名前加上双下划线(__)来实现方法的私有化。这种命名约定会导致Python解释器对方法名进行“名称改写”(name mangling),就像私有属性一样。

私有方法主要用于类的内部逻辑,不应该被类的外部客户代码直接使用。它们通常用于辅助公共方法或被其他私有方法使用。

'''
私有方法的使用
'''
class ThunderBird(object):

    # 实现一个初始方法,用来保存下载任务
    def __init__(self):
        self.__list = []

    # 实现一个公有的方法,用来添加任务
    def add_task(self,url):
        self.__list.append(url)
        # 在类的内部,直接 访问私有方法
        self.__download_data(url)
    # 核心代码 ,用来下载数据的算法
    def __download_data(self,url):
        print(f'通过地址 {url} 下载数据中。。。。')
# 测试
tb = ThunderBird()
# 通过一个公有方法,间接 访问的了对象的私有方法,下载数据
tb.add_task('http://www.dytt88.net/复联4.mp4')
# 通过地址 http://www.dytt88.net/复联4.mp4 下载数据中。。。。
# 私有方法在类的外部是不能拼接访问的。
# tb.__downoad_data('http://www.dytt88.net/复联4.mp4')
# 会报错AttributeError: 'ThunderBird' object has no attribute '__downoad_data'

继承

Python支持类的继承,允许我们创建新的类作为现有类的子类,继承其属性和方法,并可以添加新的属性和方法或覆盖现有的。

1、当发生继承后,子类会继承父类中的属性和方法,可以直接 使用

# 定义一个父类
class Phone(object):
    def __init__(self):
        self.name = '电话'
    # 定义一个打电话的方法
    def call(self,number):
        print(f'正在给 { number} 打电话')
# 定义一个子类
class iPhone(Phone):
    # 添加一个拍照方法
    def carmera(self):
        print('正在拍照')
# 当发生继承后,子类会继承父类中的属性和方法,可以直接 使用
iphonex = iPhone()
iphonex.call('13800138000')
iphonex.carmera()
print(iphonex.name)
dgd = Phone()
dgd.call('13800138000')
print(dgd.name)

'''
输出
正在给 13800138000 打电话
正在拍照
电话
正在给 13800138000 打电话
电话

'''

2、子类不能直接使用父类的私有属性和方法,可以通过访问父类的公有方法间接使用父类私有属性和方法。

class Father(object):
    def __init__(self):
        self.__money = 999
        self.name = 'tom'
    def __show(self):
        print('这个是父类中的一个私有方法')
    def display(self):
        print('这是一个父类中的公有方法')
        self.__show()
# 定义一个子类
class Son(Father):
    # 定义一个自己的方法
    def play(self):
        print('这是子类中玩的方法')
        # 在子类中不能直接使用父类中的私有方法
        # self.__show()
        # 通过继承得到的父类的公有方法,间接 执行父类的私有方法
        self.display()
s = Son()
s.play()
s.display()

3、子类初始化父类属性

# 父类
class Father(object):
    def __init__(self,name):
        print('Father Init Run ...')
        self.name = name
# 子类
class Son(Father):
    def __init__(self,name, age):
        # 因为子类提供了 init 方法后,那么在使用子类实例对象时,
        # 就会调用 子类自己 init 方法,
        # 那么就不会再调用 父类的init方法了,父类当中的属性就不会有绑定的机会
        # 所以这时是没有父类的属性的
        # 如果想父类中的属性可以得到,需要执行父类中的init方法
        # 父类名.init()
        Father.__init__(self, name)
        print('Son Init run ..')
        self.age = age
# 测试
s = Son('Tom', 12)
print(s.name)
print('age:', s.age)

4、子类重写父类中的方法

# 父类
class Father(object):
    # 实现一个治病
    def cure(self):
        print('父类是个老中医,使用中医古法治病')

class Son(Father):
    # 子类也是一个大夫,也有治病的功能
    def cure(self):
        # 直接使用 父类名.方法名 形式来引用父类的功能
        Father.cure(self)
        print('子类出国深造,学成以后,使用中西医结合方法治病')
s = Son()
s.cure()

多层继承

class A(object):
    def a(self):
        print('a function')
class B(A):
    def b(self):
        print('b function')
class C(B):
    # C类中重写了B类中的方法
    def b(self):
        B.b(self)
        print('b in C function')
    def c(self):
        print('c function')
class D(C):
    def d(self):
        print('d function')
# 测试
d = D()
d.a()
d.b()
d.c()
d.d()
'''
输出
a function
b function
b in C function
c function
d function
'''

多层继承属性初始化

class A(object):
    def __init__(self, a):
        self.a = a
class B(A):
    def __init__(self,a,b):
        A.__init__(self, a)
        self.b = b
class C(B):
    def __init__(self,a,b,c):
        B.__init__(self,a,b)
        self.c = c
class D(C):
    def __init__(self,a,b,c,d):
        C.__init__(self,a,b,c)
        self.d = d
# 测试
d = D(1,2,3,4)
print(d.a)
print(d.b)
print(d.c)
print(d.d)

多继承

多层基层:纵向

多继承:横向

# 定义一个父亲类
class Father(object):
    def func_fa(self):
        print('Father Function ...')
# 定义一个母亲类
class Mother(object):
    def func_mo(self):
        print('Mother function ...')
# 上面的两个类,有一个共同子类
class Son(Father, Mother):
    def play(self):
        print('Son play...')
# 测试
s = Son()
s.play()
s.func_fa()
s.func_mo()
'''
输出
Son play...
Father Function ...
Mother function ...
'''

多继承初始化问题

# 在这种 继承关系 上,这个共同的父类 Person 会被初台化多次,这是继承时的问题
lass Person(object):
    def __init__(self,aaa):
        print('Person Init ...')
        self.aaa = aaa
class Father(Person):
    def __init__(self,aaa, name):
        Person.__init__(self,aaa)
        print('Father Init ...')
        self.name = name
class Mother(Person):
    def __init__(self,aaa, age):
        Person.__init__(self,aaa)
        print('Mother Init ...')
        self.age = age
class Son(Father, Mother):
    def __init__(self,aaa, name,age, gender):
        Father.__init__(self,aaa, name)
        Mother.__init__(self,aaa, age)
        print('Son Init ...')
        self.gender = gender
# 测试
s = Son(1, 'Tom',12,'男')
print(s.aaa)
print(s.name)
print(s.age)
print(s.gender)
'''
输出
Person Init ...
Father Init ...
Person Init ...
Mother Init ...
Son Init ...
1
Tom
12
男
'''

多继承初始化问题解决


class Person(object):
    def __init__(self,aaa):
        print('Person Init ...')
        self.aaa = aaa
class Father(Person):
    def __init__(self,aaa, name,age):
        super(Father, self).__init__(aaa,age)
        print('Father Init ...')
        self.name = name
class Mother(Person):
    def __init__(self,aaa, age):
        super(Mother, self).__init__(aaa)
        print('Mother Init ...')
        self.age = age
class Son(Father, Mother):
    def __init__(self,aaa, name,age, gender):
        # 参数二是当前类的实例对象
        # 参数一是当前类名
        # 在参数二对象的所属类的mro关系 中找参数一的下一个类进行实始化
        super(Son, self).__init__(aaa,name,age)
        print('Son Init ...')
        self.gender = gender
# 测试
s = Son(1, 'Tom',12,'男')
print(s.aaa)
print(s.name)
print(s.age)
print(s.gender)

多继承传参问题解决

class Person(object):
    def __init__(self,aaa):
        print('Person Init ...')
        self.aaa = aaa
class Father(Person):
    def __init__(self,name,*args):
        super(Father, self).__init__(*args)
        print('Father Init ...')
        self.name = name
class Mother(Person):
    def __init__(self,age,*args):
        super(Mother, self).__init__(*args)
        print('Mother Init ...')
        self.age = age
class Son(Father, Mother):
    def __init__(self,gender,name,age,aaa):
        # 参数二是当前类的实例对象
        # 参数一是当前类名
        # 在参数二对象的所属类的mro关系 中找参数一的下一个类进行实始化
        super(Son, self).__init__(name,age,aaa)
        print('Son Init ...')
        self.gender = gender
# 测试
# s = Son(1, 'Tom',12,'男')
s = Son('男','Tom',12,1)
print(s.aaa)
print(s.name)
print(s.age)
print(s.gender)

使用Super简化格式

class Person(object):
    def __init__(self,aaa):
        print('Person Init ...')
        self.aaa = aaa
class Father(Person):
    def __init__(self,name,*args):
        # super(Father, self).__init__(*args)
        super().__init__(*args)
        print('Father Init ...')
        self.name = name
class Mother(Person):
    def __init__(self,age,*args):
        # super(Mother, self).__init__(*args)
        super().__init__(*args)
        print('Mother Init ...')
        self.age = age
class Son(Father, Mother):
    def __init__(self,gender,name,age,aaa):
        # 参数二是当前类的实例对象
        # 参数一是当前类名
        # 在参数二对象的所属类的mro关系 中找参数一的下一个类进行实始化
        # super(Son, self).__init__(name,age,aaa)
        super().__init__(name,age,aaa)
        print('Son Init ...')
        self.gender = gender

# 测试
# s = Son(1, 'Tom',12,'男')
s = Son('男','Tom',12,1)
print(s.aaa)
print(s.name)
print(s.age)
print(s.gender)

类的继承书写顺序会影响MRO顺序

class A(object):
    pass
class B(A):
    pass
class C(A):
    pass
# class D(B,C):
# (<class '__main__.D'>, < class '__main__.B' >, < class '__main__.C' >, < class '__main__.A' >, < class 'object' > )
class D(C,B):
# (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
    pass

多重继承时,方法查找顺序遵循MRO顺序

class A(object):
    def show(self):
        print('A _ Show Run ...')
    def info(self):
        print('A - Info run ...')
class B(A):
    def show(self):
        print('B _ Show Run ...')
class C(A):
    def show(self):
        print('C _ Show Run ...')
    def info(self):
        super().info()
        A.info(self)
        print('C - Info run ...')
class D(B,C):
    def show(self):
        super().show()
        A.show(self)
        print('D _ Show Run ...')
d = D()
d.show()
d.info()
'''
输出
B _ Show Run ...
A _ Show Run ...
D _ Show Run ...
A - Info run ...
A - Info run ...
C - Info run ...
'''

多态性

多态性是OOP的一个核心概念,它允许我们编写可以与多种类型的对象一起工作的函数或方法,只要这些对象都有一个公共的接口(比如相同名称的方法)。

python中多态不考虑对象中具体类型的情况下使用对象中的方法。

class Father(object):
    def cure(self):
        print('老中医使用中医治病')
class Son(Father):
    def cure(self):
        print('小大夫使用中西医结合治病')
class Dog(object):
    def bark(self):
        print('Won won ...')
class AnimalDoctor(object):
    def cure(self):
        print('我是个兽医,主要给动物治病,但是也能给人凑合治一下')

# 病人类
class Person(object):
    # 需要一个大夫给他治病
    def need_doctor(self,doctor):
        doctor.cure()
# 测试
p = Person()
p.need_doctor(Father())
p.need_doctor(Son())
# p.need_doctor(Dog())
p.need_doctor(AnimalDoctor())
'''
输出
老中医使用中医治病
小大夫使用中西医结合治病
我是个兽医,主要给动物治病,但是也能给人凑合治一下
'''

类和实例属性

类属性与实例属性之间有重要的区别。类属性是属于类的,被所有实例共享。而实例属性仅属于特定的实例。

实例属性和方法

class Cat(object):
    def __init__(self,name):
        # 定义一个实例 属性
        self.name = name
    # 定义了一个实例方法
    def info(self):
        print(self.name)
    def show(self):
        print('Show Run :')
        self.info()
# 测试
tom = Cat('Tom')
# 使用实例属性
print(tom.name)
# 使用实例方法
tom.info()
tom.show()
# Python中万物皆对象
# print(Cat.name)
Cat('tom').show()
# 结论:
# 为什么类名不能调用 实例 对象属性和实例对象方法呢?
# 因为类对象存在时,不一定有实例对象存在
# 实例属性和实例 方法只能由实例对象调用

类对象和属性

class ClassRoom(object):
    # 当定义一个类属性时,相当于这个类中的全局变量
    # 该类的所有对象都 可以使用该 类属性
    # 可以在所有的对象间进行数据共享
    center_kong_tiao = '格力空调'
    # 实例方法
    def show(self):
        print('实例方法中去访问类属性:')
        print(ClassRoom.center_kong_tiao)
cr901 = ClassRoom()
print(cr901.center_kong_tiao)
cr902 = ClassRoom()
print(cr902.center_kong_tiao)
cr903 = ClassRoom()
print(cr903.center_kong_tiao)
# cr901.center_kong_tiao = '海尔空调'
ClassRoom.center_kong_tiao = '海尔空调'
print(cr901.center_kong_tiao)
print(cr902.center_kong_tiao)
print(cr903.center_kong_tiao)
cr901.show()

魔法方法

在Python中,有许多内置的方法名有特殊的意义,这些方法名通常以双下划线(__)开始和结束。它们也被称为魔法方法或特殊方法。这些方法可以让我们重载或者定义对象的操作。

__init__() 方法:

在Python中,__init__方法是一个特殊的方法(有时称为‘魔法方法’),在创建类实例对象时被自动调用。

作用:

初始化实例的属性(起到一个传递参数的作用)

class Myclass(object):
    def __init__(self,value):
        self.my_attribute = value
    def my_method(self):
        return self.my_attribute

# 创建一个类的实例
my_instance = MyClass(10)
# 调用实例的方法
print(my_instance.my_method())  # 输出: 10
__init__方法特点:

        1、__init__方法不是一个构造函数,它在类实例化对象后运行,用来初始化实例对象属性;

        2、第一个参数self是实例对象的引用,确保在方法内部访问实例对象的属性和其他方法

self 不是Python的关键字或强制性的,它只是一个按照惯例使用的变量名。你可以使用其他变量名,但强烈建议遵循这个约定,因为它对于其他Python程序员来说是最易读和理解的。

        3、__init__方法可以有任意数量的参数,这些参数在创建类实例对象时传入。

        4、__init__方法可以是空的,也可以不写但通常被用来设置实例的初始化状态(传参)。

        5、如果你有一个继承链,__init__ 方法需要调用基类的 __init__ 方法,以确保基类也被正确初始化。这可以通过使用 super() 函数实现。

__str__()方法

在Python中,__str__()方法是一个特殊的方法,用于定义一个对象的“正式”字符串表示,当你使用print()函数或str()函数将对象转换为字符串时,Python解释器会调用这个方法。它通常应该返回一个友好易读的字符串,让用户能够理解对象的状态。

作用:

格式化字符串

class Cat(object):
    def __init__(self,name, age, height):
        self.username = name
        self.age = age
        self.height = height
    def __str__(self):
        print('String Run ..',self.username)
        # print(self.username, self.age, self.height)
        s = f'姓名:{self.username}年龄:{self.age}身高:{self.height}'
        return s
tom = Cat('Tom',1,'50cm')
print(tom)
'''
输出
姓名:Tom年龄:1身高:50cm
'''
_str__()方法特点:

        1、_str__()方法必须有一个返回值而且返回值必须是字符串。

        2、如果需要将实例对象的信息按照一定的格式进行显示,可以在这里进行修饰。

        3、修饰完,可以将这个格式化字符串返回,让str()方法执行时,得到该对象转换后的字符串类型。   

__del__()方法

在Python中,__del__ 方法是一个特殊方法,它被称为析构器(destructor)。这个方法在对象即将被删除时被自动调用。通常情况下,这发生在Python的垃圾回收器决定从内存中删除一个对象时,或者当对象的引用计数降到0时。

__del__ 方法的主要用途是确保对象释放分配给它的资源。例如,如果对象持有文件、网络连接或数据库连接等资源,__del__ 方法可以确保这些资源在对象不再使用时被正确关闭。

class Cat(object):
    def __init__(self,name):
        self.name = name
    def __del__(self):
        # 要在这个方法中将当前对象持有的其它对象手动销毁
        del self.name
        print('del run ...')
tom = Cat('tom')
# 执行下面的代码 时,会自动 调用  __del__ 方法,将这个对象销毁,回收对象内存资源
del tom
print('over')
 __dict__ 是一个魔法属性,用来保存当前对象的所有的成员

结论

Python中的类是创建自定义数据结构的强大工具,它支持继承、多态性和封装等OOP特性。通过理解类如何工作,你可以写出更加模块化、可重用和易于维护的代码。记住,类应该简单而且一目了然,最好每个类只负责一件事情。掌握了Python中的类,将有助于你在面向对象编程的世界中进行更深入的探索。

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值