python学习笔记-面向对象编程

相比较于函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法

1.1类

类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用

  • 特征被称为属性
  • 行为被称为方法
    类就是负责创建对象的

1.2对象

对象就是类的实例化,拥有在哪个类中定义的属性和方法

类的命名满足大驼峰命名法:
1.每个单词的首字母大写
2.单词和单词之间没有下划线

对对象的特征描述= 属性
对对象的行为描述=方法
需求中没有涉及的属性和方法不需要考虑

1.3面向对象的基础语法

  • dir内置函数
    使用dir内置函数传入标识符或者数据,可以查看对象内的所有属性和方法
    例如
def demo()
dir(demo)
demo.__方法名__

提示__方法名__格式的方法是python提供的内置方法和属性
python学习笔记-面向对象编程_第1张图片

  • 定义简单的类
 class 类名:
 	def 方法1(self,参数列表)pass
 	def 方法2(self,参数列表):
 		pass

在类中定义方法,第一个参数必须是self,看到self暂时不考虑

对象变量=类名()

class Cat:
	def eat(self):
		print("吃鱼")
	def drink(self):
		print("喝水")
tom = Cat()
tom.eat()
tom.drink()

使用print输出对象变量,是能够输出这个变量引用的对象是有哪一个类创建的对象,以及在内存中的地址
每次通过Cat()新建的对象变量的地址都不一样,说明生成了不同的对象

  • 方法中的self参数
    哪一个对象调用的方法,self就是哪一个对象的引用
    使用self在方法内部输出每一只猫的名字
    在类封装的方法内部,self就表示当前调用方法的对象自己
    在调用方法时,程序员不需要传递self参数
    方法内部
    可以通过self.访问对象的属性
    可以通过self.调用其他的对象方法

class Cat:
	def eat(self):
		#哪一个对象调用的方法,self就是哪一个对象的引用,引用就是self形参存放的是对象的地址
		print("%s吃鱼" % self.name) # 在方法内调用属性的方法,个人理解,tom在调用eat方法的时候,self就是tom
	def drink(self):
		print("%s喝水" % self.name) # 在方法内调用属性的方法


tom = Cat() #tom=实例化的对象变量,用于引用
tom.name = 'Tom' #可以通过这样在外部为对象添加属性(用的少)
tom.eat()
tom.drink()

jerry = Cat()
jerry.name = 'Jerry'
jerry.eat()

  • 初始化方法
    当使用类名()创建对象时,会自动执行以下操作:
    1.为对象在内存中分配空间----创建对象
    2.为对象的属性设置初始值-----初始化方法__init__ 这个方法是对象的内置方法
    init方法是专门用来定义一个类具有哪些属性的方法
    以下是验证代码
class Cat():
    def __init__(self):
        print("这是一个初始化方法")
# 使用类名()创建对象,会自动调用初始化方法__init__
tom = Cat()
print(tom)

在初始化方法内部定义属性
在开发中,如果希望在创建对象的同时,就设置对象的属性,而不是默认属性,就可以通过以下三个步骤对__init__方法进行改造:
1.吧希望设置的属性值,定义成__init__方法的形参
2.在方法内部使用self.属性= 形参接受外部传递的参数
3.在创建对象时,使用类名(属性1,属性2…)调用

class Cat():
    def __init__(self,new_name):
        print("这是一个初始化方法")
        # self.属性名 = 属性的初始值
        # self.name = 'TOM'
        self.name = new_name
    def eat(self):
        print("%s 吃鱼" % self.name)
# 使用类名()创建对象,会自动调用初始化方法__init__,self是无需传入的参数
tom = Cat('TOM')
print(tom.name)
tom.eat()

lazy_cat = Cat('JERRY')
lazy_cat.eat()

  • 内置方法和属性
    del
    对象被内存销毁前,会被自动调用
class Cat:
    def __init__(self,new_name):
        self.name = new_name
        print("%s 来了" % self.name)
    def __del__(self):
        print("%s 走了" % self.name)
tom = Cat('TOM')
#tom是个全局变量,所有代码执行完成后被回收
print(tom.name)

tom.__del__()

print('1')

__str__方法,使用print输出对象变量,默认情况下,会输出这个变量引用的对象时由哪一个类创建的对象,以及在内存中的地址(十六进制表示的)
如果在开发中,希望使用print输出对象变量时,能够打印自定义内容,就可以用str这个内置方法了

面向对象封装实例

外界使用类创建对象,然后让对象调用方法
对象方法的细节,封装在类的内部

小明爱跑步例子:None

私有属性和私有方法

实际开发中,对象的某些属性和方法可能只希望在对象内部使用,不希望外部使用
在定义属性或方法时,在前面加上两个下划线,定义的就是私有属性或者方法

class Women:
    def __init__(self,name):
        self.name = name
        self.__age = 11
    def __secret(self):
        print("%s 的年龄是 %d" % (self.name,self.__age))

xiaomei = Women('xiaomei')
#私有属性,在外界不能直接访问,在对象内部可以访问
#print(xiaomei.__age)
#私有方法同样在外界不能直接访问
#xiaomei.__secret()

## ```伪私有属性和私有方法

继承

**面向对象三大特性**
1.封装:根据职责将属性和方法封装到一个抽象的类中
2.继承实现代码的重用,相同的代码不需要重复的编写
3.多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

```python
# 继承的概念:子类拥有父类所有方法和属性
# 基本语句
# class 类名(父类):
# 子类中应该根据职责,封装子类特有的属性和方法

# 专业术语
# 继承具有传递性,子类拥有父类的父类的属性和方法

1.2方法的重写

当父类封装的方法不能满足子类的需求时,可以对方法进行重写

重写父类方法有两种情况:
1.覆盖父类的方法

如果在开发中,父类的方法实现和子类的方法实现完全不同,就可以用覆盖,在子类中重新编写父类的方法实现

如果在子类中,重写了父类的方法(与父类方法重名),在使用子类对象调用方法时,会调用子类中重写的方法

2.对父类方法进行扩展

如果在开发中,子类的方法实现中包含父类的方法实现
父类原本封装的方法实现是子类方法的部分
就可以使用扩展的方式
1.在子类中重写父类的方法,和第一种情况一样
2.在子类方法中需要的位置使用 super().父类方法 来调用父类方法
3.子类代码其他的位置针对子类的需求,编写子类特有的代码实现
关于super
●在Python 中super 是一个特殊的类
super()就是使用super 类创建出来的对象
●最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现

1.3父类的私有属性和私有方法

python学习笔记-面向对象编程_第2张图片
若父类的公有方法中包含了父类的私有属性和私有方法,那么子类是可以通过调用父类的公有方法访问到父类的私有属性和私有方法的

class A:
    def __init__(self):
        self.num1  = 100
        self.__num2 = 200
    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("%d" % self.num1)
        self.test()


b = B()
b.demo()
b.test()

多继承

概念:子类可以拥有多个父类,并且具有所有父类的属性和方法

语法
class 子类名(父类名1,父类名2…)
pass

应当避免 父类之间存在同名的属性和方法使用多继承

MRO – 方法搜索顺序

object是python为所有对象提供的基类,提供有一些内置属性和方法,可以使用dir函数查看
今后定义类的时候,如果没有父类,建议统一采用object作为基类

多态

不同的子类对象调用相同的父类方法,产生不同的执行效果

  • 可以增加代码的灵活度
  • 以继承和重写父类方法为前提
  • 是调用方法技巧,不会影响到类的内部设计

类属性

1.1 多个对象的方法在内存中只存有一份,在调用方法时,需要吧对象的引用传入到方法内部,也就是self,那么对象就可以在外部调用方法
实例属性,实例方法

1.2 类是一个特殊的对象—类对象
程序运行时,类同样会被加载到内存
类对象在内存中只有一份,一个类可以创建多个实例对象
除了封装实例的属性和方法,类对象还可以拥有自己的属性和方法

1.类属性
2.类方法
访问类属性和调用类方法的语法----类.
类属性和类方法由该类的所有对象共享,通过类名直接访问

类属性就是给类对象中定义的属性,通常用来记录与这个类相关的特性,类属性不会用于记录具体对象的特征

代码实例如下:

class Tool(object): # 类也是一个对象,也有自己的属性和方法
    # 使用赋值语句定义类属性,记录所有工具对象的数量
    count = 0 # 类属性
    def __init__(self,name):
        self.name = name # 实例属性

        # 让类属性值+1
        Tool.count += 1


toll1 = Tool('斧头')
print(Tool.count)

1.3 属性获取机制

python学习笔记-面向对象编程_第3张图片

类方法

@classmethod # 修饰器
def 类方法名(cls):
	pass

由哪一个类调用的方法,方法内的cls就是哪一个类的引用
通过类名. 调用类方法,调用方法时,和实例方法一样不需要传入self参数,在方法内部
1.可以通过 cls. 访问类的属性
2. 通过 cls. 调用其他类的方法

class Tool(object): # 类也是一个对象,也有自己的属性和方法
    # 使用赋值语句定义类属性,记录所有工具对象的数量
    count = 0 # 类属性

    @classmethod
    def show_tool_count(cls):
        print("工具对象的数量%d" % cls.count) #在类方法内部,要想访问类属性或者其他类方法,需要用cls引用

    def __init__(self,name):
        self.name = name # 实例属性

        # 让类属性值+1
        Tool.count += 1

tool1 = Tool("斧头")
tool2 = Tool('榔头')
Tool.show_tool_count()


类方法之—静态方法
●在开发时,如果需要在类中封装一 个方法,这个方法:
既不需要访问实例属性或者调用实例方法 也不需要访问类属性或者调用类方法
●这个时候,可以把这个方法封装成一个静态方法
语法如下:
@staticmethod
def 静态方法名();
pass

class Dog(object):

    @staticmethod
    def run():
        print('小狗要跑')

# 可以通过类名.静态方法    的方式调用静态方法---不需要创建对象也可以调用
Dog.run()

python学习笔记-面向对象编程_第4张图片

class Game(object):
    # 定义类属性只需要在class下面直接赋值语句
    top_socre = 0

    def __init__(self,player_name):
        self.player_name = player_name

    @staticmethod # 静态方法
    def show_help():
        print("帮助信息:让僵尸进入大门")

    @classmethod # 类方法
    def show_top_score(cls):
        print("历史最高分为:%d" % cls.top_socre)

    def start_game(self):
        print("%s进入游戏....." % self.player_name)


# 1.查看游戏的帮助信息
Game.show_help() # 静态方法,类方法都不需要创建对象,通过类名.方法的方式直接调用
# 2.查看历史最高分
Game.show_top_score()
# 3.创建游戏对象
game_player1 = Game("小明")
game_player1.start_game() # 实例方法需要先创建一个对象,然后让实例对象调用方法


案例小结
1.实例方法–方法内部需要访问实例属性,实例方法
实例方法内部可以使用类名.访问类属性,也可以访问类方法
2.类方法–方法内部只需要访问类属性
3.静态方法–方法内部,不需要访问实例属性和类属性

静态方法,类方法都不需要创建对象,通过类名.方法 的方式直接调用
实例方法需要先创建一个对象,然后让实例对象调用方法

单例设计模式

1.单个实例–目的:让类创建的对象,在系统中只有唯一一个实例
每次执行类名()返回的对象,内存地址是相同的,也就是不断创建同一个对象

2.__new__方法----object提供的类中的内置方法

使用类名()创建对象时,Python 的解释器首先会调用__new_ 方法为对象分配空间
new_是一个由object基类提供的内置的静态方法,主要作用有两个:
1.在内存中为对象分配空间

2.返回对象的引用(地址)
Python 的解释器获得对象的引用后,将引用作为第一个参数,传递给_ init_ 方法

3.__new__方法的重写

new方法重写的代码很固定!
重写__new__ 方法一定要return super().__new__(cls)
●否则Python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
●注意: new_是一个静态方法,在调用时需要主动传递cls参数

class MusicPlayer(object):

    def __new__(cls, *args, **kwargs):
        # 1. 创建对象时,new方法会被自动调用
        print("创建对象,分配空间")

        # 2. 为对象分配空间
        instance = super().__new__(cls) # 将cls参数传递给父类的new方法,才可以得到引用

        # 3. 返回对象的引用,类才会调用init方法,将引用传入self中
        return instance # 调用父类方法使用super().方法名

        # object.__new__(cls) 子类中调用父类方法 ----- 父类名.父类方法()

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

player = MusicPlayer()

print(player)


单例创建步骤:
1.定义一个类属性,初始值是None,用于记录单例对象的引用
2.重写__new__方法
3.如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
4.返回类属性中记录的对象引用

让初始化动作只执行一次的操作:

你可能感兴趣的:(学习用,python,pycharm)