欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python-面向对象

程序员文章站 2022-07-10 08:22:31
...

一.定义简单的类

1.定义简单的类

  • 方法定义格式和函数几乎一样
  • 区别在于第一个参数必须是self
class 类名:
     def 方法1(self,参数列表)
          pass
     def 方法2(self,参数列表)
       pass
  • 类名要符合大驼峰命名法

2.创建对象

对象变量 = 类名()
class Cat:
     def eat(self):
         print("小猫要吃鱼")
     def drink(self):
         print("小猫要喝水")

tom = Cat()
tom.eat()
tom.drink()
/*
小猫要吃鱼
小猫要喝水
*/

注意:在面向对象开发中,引用概念是同样适用的

class Cat:
     def eat(self):
         print("小猫要吃鱼")
     def drink(self):
         print("小猫要喝水")

tom = Cat()
tom.eat()
tom.drink()

print(tom)
num = id(tom)
print("%x" %num)
/*
小猫要吃鱼
小猫要喝水
<__main__.Cat object at 0x0000008C41F6F2B0>
8c41f6f2b0
*/
class Cat:
     def eat(self):
         print("小猫要吃鱼")
     def drink(self):
         print("小猫要喝水")

tom = Cat()


print(tom)
num1 = id(tom)
print("%x" %num1)

jim = Cat()
print(jim)
num2 = id(jim)
print("%x" %num2)

jery = tom
print(jery)
num3 = id(jery)
print("%x" %num3)
/*
<__main__.Cat object at 0x00000012E837FA90>
12e837fa90
<__main__.Cat object at 0x00000012E837FAC8>
12e837fac8
<__main__.Cat object at 0x00000012E837FA90>
12e837fa90
*/

3.方法中的self参数

  • 在python中,要给对象设置属性,非常容易,但不推荐使用(只需要在类外部代码中直接通过.设置一个属性即可)
  • 对象属性封装应该封装在类的内部
class Cat:
     def eat(self):
         # 哪一个对象调用的方法,self就是那一个对象的引用
         print("小猫%s要吃鱼" %self.name)
     def drink(self):
         print("小猫%s要喝水" %self.name)

tom = Cat()
tom.name="tom"
tom.eat()

jim = Cat()
jim.name="jim"
jim.drink()
/*
小猫tom要吃鱼
小猫jim要喝水
*/

4.初始化方法

  • 当使用类名()创建对象,会自动执行以下操作:
    • 为对象在内存中分配空间 --创建对象
    • 为对象的属性设置初始值 --初始化方法(init)
      就是_init_方法
  • 专门用来定义一个类具有哪些属性的方法,有点像java中的构造方法
class Cat:
    def __init__(self):
        print("初始化方法")


tom =Cat()
/*初始化方法*/

class Cat:
    def __init__(self):
        print("初始化方法")
        self.name="tom"

    def eat(self):
        print("小猫%s爱吃鱼" %self.name)

tom =Cat()
print(tom.name)
tom.eat()
/*
初始化方法
tom
小猫tom爱吃鱼
*/
  • 改造初始化方法
class Cat:
    def __init__(self,new_num):
        print("初始化方法")
        self.name=new_num

    def eat(self):
        print("小猫%s爱吃鱼" %self.name)

tom =Cat("tom")
print(tom.name)
tom.eat()

jim = Cat("jim")
print(jim.name)
jim.eat()
/*
初始化方法
tom
小猫tom爱吃鱼
初始化方法
jim
小猫jim爱吃鱼
*/

5.内置方法

_del_方法:对象被从内存中销毁前,会被自动调用

_str_方法:返回对象的描述信息,print函数输出使用像java中toString()方法


class Cat:
    def __init__(self,new_num):
        self.name=new_num
        print("%s来了" %self.name)
    def __del__(self):
        print("%s去了" %self.name)

tom = Cat("tom")
del tom
print("-"*50)
/*
tom来了
tom去了
--------------------------------------------------
*/
class Cat:
    def __init__(self,new_num):
        self.name=new_num
        print("%s来了" %self.name)
    def __del__(self):
        print("%s去了" %self.name)
    def __str__(self):
        return "我是小猫[%s]" %self.name

tom = Cat("tom")
print(tom)
/*
tom来了
我是小猫[tom]
tom去了
*/

二.私有属性和私有方法

  • 在定义属性或方法时,在属性名或方法名前增加两个下划线,定义的就是私有属性或方法

1.私有属性和私有方法

class student:
    def __init__(self,name):
        self.name=name
        self.__age=18
    def secret(self):
        print("%s的年龄有%d" %(self.name,self.__age))

stu1 = student("小明")

#访问不到 print(stu1.__age)
stu1.secret()
/*
小明的年龄有18
*/

2.伪私有属性和私有方法

  • 在Python,没有真正意义上的私有,可以说是伪私有
class student:
    def __init__(self,name):
        self.name=name
        self.__age=18
    def __secret(self):
        print("%s的年龄有%d" %(self.name,self.__age))

stu1 = student("小明")
print(stu1._student__age) #不推荐
#访问不到 print(stu1.__age) 
stu1._student__secret()
/*
18
小明的年龄有18
*/

三.继承

1.单继承

  • 子类拥有父类的所有方法和属性
class 类名(父类名)
          pass
class Animal:
     def eat(self):
         print("吃")
     def drink(self):
         print("喝")
     def sleep(self):
         print("睡")

class Dog(Animal):
     def bark(self):
         print("叫")

tom = Dog()
tom.eat()
tom.drink()
tom.sleep()
tom.bark()
/*
吃
喝
睡
叫
*/

2.继承传递性

  • B继承于A,C继承于B,那么C也继承于A
class Animal:
     def eat(self):
         print("吃")
     def drink(self):
         print("喝")
     def sleep(self):
         print("睡")

class Dog(Animal):
     def bark(self):
         print("叫")

class XiaoTianQuan(Dog):
     def fry(self):
         print("我会飞")

tom = XiaoTianQuan()
tom.fry()
tom.eat()
tom.drink()
tom.sleep()
tom.bark()

3.方法重写

  • 子类拥有父类所有方法和属性
  • 子类继承自父类,可以直接享受父类中已封装好的方法,不需要再次开发
  • 覆盖父类的方法
  • 对父类方法进行扩展
class Animal:
     def eat(self):
         print("吃")
     def drink(self):
         print("喝")
     def sleep(self):
         print("睡")

class Dog(Animal):
     def bark(self):
         print("叫")

class XiaoTianQuan(Dog):
     def fry(self):
         print("我会飞")
     def bark(self):
         print("叫的更神一样")

tom = XiaoTianQuan()
tom.bark()
/*
叫的更神一样
*/
class Animal:
     def eat(self):
         print("吃")
     def drink(self):
         print("喝")
     def sleep(self):
         print("睡")

class Dog(Animal):
     def bark(self):
         print("叫")

class XiaoTianQuan(Dog):
     def fry(self):
         print("我会飞")
     def bark(self):
         print("叫的更神一样")
         # 使用super().调用原本在父类封装的方法
         super().bark()

tom = XiaoTianQuan()
tom.bark()
/*
叫的更神一样
叫
*/
  • 调用父类方法的另外一种方式
父类名.方法(self):
class Animal:
     def eat(self):
         print("吃")
     def drink(self):
         print("喝")
     def sleep(self):
         print("睡")

class Dog(Animal):
     def bark(self):
         print("叫")

class XiaoTianQuan(Dog):
     def fry(self):
         print("我会飞")
     def bark(self):
         print("叫的更神一样")

         Dog.bark(self)

tom = XiaoTianQuan()
tom.bark()

四.私有属性和私有方法扩展

  • 私有属性、方法是对象的隐私,不对外公开,外界和子类都不能直接访问

  • 私有属性、方法通常用于做一些内部的事情

1.子类不能直接访问父类私有

class A:
    pass
    def __init__(self):
        self.num1=10
        self.__num2=20
    def __test(self):
        print("私有方法%d %d" %(self.num1,self.__num2))
class B(A):
    def demo(self):
        #在子类对象方法中不能直接访问父类私有属性 print("访问父类的私有属性 " %self.__num2)

        #在子类对象方法中不能直接访问父类私有方法 self.__test()
        pass
    
b= B()
print(b)

#  不能直接访问私有属性 print(b.__num2)
# 不能直接访问私有方法 b.test()

2.子类间接访问父类私有

class A:
    pass
    def __init__(self):
        self.num1=10
        self.__num2=20
    def __test(self):
        print("私有方法%d %d" %(self.num1,self.__num2))

    def test(self):
        print("公有方法: %d" %(self.__num2))
        self.__test()
class B(A):
    def demo(self):
        #在子类对象方法中不能直接访问父类私有属性 print("访问父类的私有属性 " %self.__num2)

        #在子类对象方法中不能直接访问父类私有方法 self.__test()
        self.test()

b= B()
b.demo()
/*
公有方法: 20
私有方法10 20
*/

五.多继承

  • 子类可以拥有多个父类,并且具有所有父类的属性和方法
  • 孩子会继承自己父亲和母亲的特性
class 子类名(父类名1,父类名2...)
         pass
class A:
    def test(self):
        print("a")
class B:
    def demo(self):
        print("b")
class C(A,B):
     pass
c = C()
c.demo()
c.test()
/*
b
a
*/
  • 开发时,尽量避免父类之间存在同名属性或者方法,尽量避免使用多继承
class A:
    def test(self):
        print("a self")

    def demo(self):
            print("a demo")
class B:
    def demo(self):
        print("b demo")

    def test(self):
        print("b self")
class C(A,B):#这里继承顺序改下输出就是B类中的两个方法了,具体,后面会说
     pass
c = C()
c.demo()
c.test()
/*
a demo
a self
*/

  • Python中的MRO–方法搜素顺序
  • 针对类提供了一个内置属性__mrg__可以查看方法搜索顺序
class A:
    def test(self):
        print("a self")

    def demo(self):
            print("a demo")
class B:
    def demo(self):
        print("b demo")

    def test(self):
        print("b self")
class C(B,A):
     pass
c = C()
# 从左往右找 找到就输出
print(C.__mro__)
  • 新式类和旧式(经典)类
    Object是python为所有对象提供的基类
    新式类:以object为基类的类,推荐使用
    经典类:不以以object为基类的类,不推荐使用

六.多态

  • 不同的子类对象调用相同父类方法,产生不同执行结果
class Dog(object):
    def __init__(self,name):
           self.name=name
    def game(self):
        print("%s蹦蹦跳跳的玩耍" %self.name)

class XiaoTianQuan(Dog):
    def game(self):
        print("%s飞上天去玩" %self.name)


class Person:
    def __init__(self,name):
        self.name=name
    def game_with_dog(self,dog):
        print("%s和%s一起玩耍" %(self.name,dog.name))
        dog.game()

#wangcai = Dog("旺财")
wangcai = XiaoTianQuan("飞天旺财")
xiaoming = Person("小明")
xiaoming.game_with_dog(wangcai)
/*
小明和飞天旺财一起玩耍
飞天旺财飞上天去玩
*/

七.类属性和类方法

1.类属性

  • 类属性就是给类对象中定义的属性
  • 通常用来记录与这个类相关的特征
  • 类属性不会用于记录具体对象的特征
class Tool(object):
    count = 0
    def __init__(self,name):
        self.name=name
        Tool.count+=1

tool1 = Tool("斧头")
tool2 = Tool("扫把")
tool3 = Tool("拖把")
print(Tool.count)
/*
3
*/
  • 如果使用对象.类属性 = 值 赋值,只会给对象添加一个属性,而不会影响类属性的值
class Tool(object):
    count = 0
    def __init__(self,name):
        self.name=name
        Tool.count+=1

tool1 = Tool("斧头")
tool2 = Tool("扫把")
tool3 = Tool("拖把")
tool3.count = 99
print(tool3.count)
print(Tool.count)
/*
99
3
*/

2.类方法

@classmethod
def 类方法名(cls):
        pass
  • 类方法需要用修饰器@classmethod来标识,告诉解释器这是一个类方法
  • 类方法第一个参数是 cls
  • 通过类名,调用类方法,调用方法时,不需要传递cls参数
  • 在方法内部
    * 可以通过 cls,访问类属性
    * 也可以通过cls,调用其他的类方法
class Tool(object):
    count = 0
    @classmethod
    def show_tool_count(cls):
        print(cls.count)
    def __init__(self,name):
        self.name=name
        Tool.count+=1

tool1 = Tool("1")
tool2 = Tool("2")
tool3 = Tool("3")
Tool.show_tool_count()
/*
3
*/

3.静态方法

  • 既不需要方法实例属性或者调用实例方法
  • 也不需要访问类属性或者调用类方法
    这个时候,可以把这个方法封装成一个静态方法
@staticmethod
def 静态方法名():
      pass
class Dog(object):
    @staticmethod
    def run():
    #不需要访问类属性/实例属性
        print("我要跑")

Dog.run()
/*
我要跑
*/

八.单例

1.单例设计模式

  • 设计模式是前人工作的总结和提炼

  • 使用设计模式是未来可重用代码,让代码更容易被他人理解、保证代码可靠性

  • 单例设计模式
    目的:让类创建的对象,在系统中只有唯一的一个实例
    每一次执行类名()返回的对象,内存地址是相同的

  • 单例应用场景
    音乐播放对象,回收站对象,打印机对象等等

2.__new__方法

  • 使用类名()创建对象时,python的解释器首先会调用__new__方法为对象分配空间

  • __new__ 是一个由object基类提供的内置的静态方法

  • 作用为:在内存中为对象分配空间;返回对象的引用

  • Python解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法

  • 重写__new__方法一定要return super().__new__(cls)方法

  • 否则Python解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法

  • __new__是一个静态方法,在调用时需要主动传递cls参数

class MusicPlayer(object):
    # *元组 **字典
    def __new__(cls, *args, **kwargs):
        print("创建对象,分配空间")

    def __init__(self):
        print("播放器初始化")

player = MusicPlayer()
print(player)
/*
创建对象,分配空间
None
*/
class MusicPlayer(object):
    # *元组 **字典
    def __new__(cls, *args, **kwargs):
        print("创建对象,分配空间")
        instance = super().__new__(cls)
        return  instance
    def __init__(self):
        print("播放器初始化")

player = MusicPlayer()
print(player)
/*
创建对象,分配空间
播放器初始化
<__main__.MusicPlayer object at 0x000000CB2A6E2E80>
*/

3.python中的单例

class MusicPlayer(object):
            pass

player1 = MusicPlayer()
player2 = MusicPlayer()
print(player1)
print(player2)
/*
<__main__.MusicPlayer object at 0x0000007F1A5E2E80>
<__main__.MusicPlayer object at 0x0000007F1A62F0F0>
*/
class MusicPlayer(object):
    instance = None
    # *元组 **字典
    def __new__(cls, *args, **kwargs):

        if cls.instance is None:

            cls.instance = super().__new__(cls)

        return cls.instance


player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)
/*
<__main__.MusicPlayer object at 0x000000DAC5CFF048>
<__main__.MusicPlayer object at 0x000000DAC5CFF048>
*/
  • 在每次使用类名()创建对象时,Python解释器都会自动调用两个方法
__new__分配空间
__init__对象初始化

在上面对__new__方法改造,每次都会得到第一次被创建对象的引用,但是初始化方法还会被再次调用

class MusicPlayer(object):
    instance = None

    init_flag = False
    # *元组 **字典
    def __new__(cls, *args, **kwargs):

        if cls.instance is None:

            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        if self.init_flag:
            return
        print("初始化方法")
        self.init_flag = True

player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)
/*
初始化方法
<__main__.MusicPlayer object at 0x000000010257F048>
<__main__.MusicPlayer object at 0x000000010257F048>
*/
相关标签: python 面向对象