Python基础语法(七:类与对象)

不在压力与疲惫中沉浮,
不在良辰与美景中迷失。
不在奋斗与竞争中麻木,
不在辉煌与腾飞中失足。


一、Python中的类与对象

1.类与对象的概念

对象面向对象编程的 两个 核心概念

物以类聚,人以群分
人类
鸟类
植物类
超人类
.....
划分类的标准是?拥有共同的特性?动作?

类 英文单词: class
他们有相似点。共同之处

  • 是对一群具有 相同特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用
    • 特征 被称为 属性
      • 它是什么样的
什么是属性???
表示的是类/对象的特征。

特征是别人不具备的。

类属性(类变量):
这个类的特征,这个群体的特征, 别的类(别的群体)可能不具备
实例属性(实例变量) :
这个个体的特征,类当中的其他成员可能不具备。


类属性的获取:
类名.属性

类属性:可以先天定义也可以  后天学习(手工添加)

class Man:
    # 定义类属性
    gender = '男'
    power = "强"
    handsome = 'very very'


print(Man.power)  # Man类的power属性
print(Man.gender) # Man类的gender属性

# 后天学习(手工添加的)
Man.hello = 'hello world'
print(Man.hello)

# 实例属性的后天学习获取
yuz = Man()
# yuz.handsome = 'very very'
print(yuz.handsome)

kaishi = Man()
kaishi.handsome = '一丢丢'
print(kaishi.handsome)

# 类属性和实例属性:

# 类属性:所有的成员都是一样的。
# 实例属性:不是每个成员都一样


# 第二个区别:
#类属性,可以被实例、对象访问
# 实例属性, 不可以被类获取
print(Man.eye)

class Man:
    # 定义类属性
    gender = '男'
    power = "强"
    handsome = 'very very'


yuz = Man()
kaishi = Man()

print(yuz.gender)
print(kaishi.gender)

yuz.eye = '蓝色'
# AttributeError, 属性错误。
# print(kaishi.eye)
print(Man.eye)

  **行为** 被称为 **方法**
      - 它可以做什么
方法:表示类 、 对象的行为。
方法本质上是函数。

属性名称:名词。
方法:动词,

方法 vS 函数:
1, self
2, 放在类里面,缩进的。
3, 调用过程不一样。 方法需要加前缀,类名或者对象名。
函数前面要么不加,要么加的模块名。

# 对象.方法()
Man().drink()

# 实例方法,对象方法:
1, 第一个参数名称,规定是 self,
2,  实例方法在调用的时候,前缀是对象,不能是类

# 类方法:
1, 在方法的上面添加 @classmethod
2, 把实例方法当中的 self 改成 cls,

# 静态方法
静态方法表示: 方法的上面加上一个 @staticmethod
不需要用 self, cls 作为固定参数

是刚刚好放在一个类当中的普通函数而已。
除了放在类当中,和普通函数没什么区别。

没有实际作用,和类或者对象没有关系(联系),
为什么要用静态方法、为什么要把普通的函数放到类当中去??
方便管理

调用静态方法。
静态方法,(普通函数) 只需要在调用静态方法,前面加上类名或者对象名

类外面的普通函数:普通函数不需要加类,模块



实际使用当中:
实例方法: 98% , 实例方法占大多数情况。
不知道用什么方法,就用实例方法。

类方法:后面会有特殊情况

静态方法: 可以用普通函数代替,不是必须的。(管理方便。)
 """



class Man:
    # 定义类属性
    gender = '男'
    power = "强"
    handsome = 'very very'

    @staticmethod
    def tianqiyubao():
        print("天气预报:今天是晴天。")

    @classmethod
    def eat(cls):
        print("正在吃饭")
        return "hello world"

    def drink(self):
        """喝。。。"""
        pass

    def play_game(self):
        """玩游戏"""
        pass

# # 对象.方法()
# Man().drink()
#
# yuz = Man()
# yuz.drink()

# 行为是属于某一个人的。不能被类调用的
#  不 OK,  Man.drink()

# 打印函数的调用打印出来的是函数的返回值。
# def run():
#     pass
#
# print(run())


# print(Man.eat())
# print(Man().eat())


# 静态方法的使用
Man.tianqiyubao()
Man().tianqiyubao()

  • 就相当于建造房子时的施工图纸(blueprint),是一个模板,是负责创建**房子(对象)**的

对象 object: 东西
什么是对象 object
又被称为 实例 instance

  • 对象由类创建出来的一个具体存在,可以直接使用
  • 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的:
    • 属性
    • 方法
  • 对象 就相当于用 施工图纸 建造 的房子

在程序开发中,应该 先有类,再有对象

2. 类与对象的关系

  • 类是模板对象 是根据 这个模板创建出来的
  • 先有类,再有对象
  • 只有一个,而 对象 可以有很多个
    • 不同的对象 之间 属性 可能会各不相同
  • 中定义了什么 属性和方法对象 中就有什么属性和方法,不可能多,也不可能少

3.类的设计

在使用面相对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类!

类的设计要素

在程序开发中,要设计一个类,通常需要满足一下三个要素:

  • 类名
    • 满足大驼峰命名法
  • 属性
    • 这类事物具有什么样的特征
  • 方法
    • 这类事物具有什么样的行为

大驼峰命名法

  • 每一个单词的首字母大写

  • 单词与单词之间没有下划线

确定类名

名词提炼法 分析 整个业务流程,出现的 名词,通常就是找到的类

确定属性和方法

  • 对象的特征描述,通常可以定义成 属性
  • 对象具有的行为(动词),通常可以定义成方法
类的定义:
class 类名:
    类的组成部分

类的调用:
print(类名)
变量 = 类名
<class '__main__.Man'>
<__main__.Man object at 0x0000022ABEE74670>
看到有尖括号的,一般来说就是一个类 / 对象。

4. 定义类

  • Python 中要定义一个只包含方法的类,语法格式如下:
class 类名:

    def 方法1(self, 参数列表):
        pass
    
    def 方法2(self, 参数列表):
        pass
  • 方法 的定义格式和之前学习过的函数 几乎一样
  • 区别在于第一个参数必须是 self

创建对象

  • 当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量 = 类名()

self

使用 self 在方法内部输出每个人的名字

哪一个对象 调用的方法,方法内的 self 就是 哪一个对象的便利贴

  • 在类封装的方法内部,self 就表示 当前调用方法的对象自身

  • 调用方法时,程序员不需要传递 self 参数

  • 在方法内部

    • 可以通过 self. 访问对象的属性
    • 也可以通过 self. 调用其他的对象方法
  • Python 中要定义带属性的类,语法格式如下:

初始化方法

  • 当使用 类名() 创建对象时,会 自动 执行以下操作:

    • 为对象在内存中 分配空间 —— 创建对象

    • 为对象的属性 设置初始值 —— 初始化方法(init)

  • 这个 初始化方法 就是 __init__ 方法,__init__ 是对象的内置方法

__init__ 方法是 专门 用来定义一个类 具有哪些属性的方法

在初始化方法内部定义属性

  • __init__ 方法内部使用 self.属性名 = 属性的初始值 就可以 定义属性
  • 定义属性之后,再使用 Person 类创建的对象,都会拥有该属性

"""
什么是初始化??
要通过定义的类得到一个具体的对象。  生出来,造出来。

对象个体,初始化过程保证生出来是不一样的。
我们自己给东西进行出厂设置。

特定的方法中去控制:
__init__

实例属性的定义2:
1, 类外面:  对象名.属性
2, 类里面:  self.属性


__init__ 定义的形式参数 和  对象的实例化 a = Man() 的实际参数,是一一对应的。
1. 必须 return None
2. 传入的参数必须要设置成实例属性,才能被被对象访问到。


self: 在 **类里面** ,表示一个 **对象**   他自己。自我, this
cls, : 在 **类里面** ,表示一个 **类**   他自己。自我, this


实例方法当中,可不可以去定义实例属性。??

"""

# def run():
#     pass

class Man:
    # 定义类属性
    gender = '男'
    power = "强"
    handsome = 'very very'

    def __init__(self,  name, face_shape='圆脸'):
        """对象的初始化过程。 让对象之间长得不太一样。"""
        # 定义, 在类里面,定义实例属性使用 self.属性 = ...
        self.face = face_shape
        self.name = name


    @staticmethod
    def tianqiyubao():
        print("天气预报:今天是晴天。")

    @classmethod
    def eat(cls):
        print("正在吃饭")
        print(cls.power)
        return "hello world"

    def drink(self, brand):
        """喝。。。"""
        print("{} 正在喝 {} 酒".format(self.name, brand))
        # self.play_game()
        self.eat()
        # 定义实例属性
        self.single = False

    def play_game(self):
        """玩游戏"""
        print("玩游戏")



yuz = Man('yuz', '方脸')

# print(yuz.face)
# print(yuz.name)
# yuz.drink('茅台')

# 整容的权利,可以后天改变属性
# yuz.face = "帅脸"
# print(yuz.face)


# 初始化以后 。 single 属性是后天定义的,
yuz.drink('五粮液')
print(yuz.single)
yuz.single = True
print(yuz.single)



# print(a)

5. __str__ 方法

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

注意:__str__ 方法必须返回一个字符串

二、身份运算符

身份运算符用于 比较 两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用

  • Python 中针对 None 比较时,建议使用 is 判断
运算符描述实例
isis 是判断两个标识符是不是引用同一个对象x is y,类似 id(x) == id(y)
is notis not 是判断两个标识符是不是引用不同对象x is not y,类似 id(a) != id(b)

is 与 == 区别

is 用于判断 两个变量 引用对象是否为同一个
== 用于判断 引用变量的值 是否相等

三、 类属性和实例属性

1.概念

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

  动态属性设置
class Phone:

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


phone = Phone('137')

# # 对象.属性
# print(phone.number)
#
# # 动态获取属性
# print(getattr(phone, 'number'))

# 动态获取不存在的属性
# print(phone.brand)
# 可以加上 default 参数,设置默认值。当没有该属性的属性,不会报错。
# 而是返回默认值。
# print(getattr(phone, 'brand', default='苹果'))

# 动态属性,属性名 == 变量

prop_name = 'brand'
# phone.prop_name
# phone.brand
print(getattr(phone, prop_name, '苹果'))
print(phone.brand)

# 设置 set 属性。
# print(phone.number)
# setattr(phone, 'number', '155')
# # phone.number = 155
# phone.color = '白色'
# print(phone.number)

四、类方法和静态方法

1.类方法

  • 类属性 就是针对 定义的属性
    • 使用 赋值语句class 关键字下方可以定义 类属性
    • 类属性 用于记录 与这个类相关 的特征
  • 类方法 就是针对 定义的方法
    • 类方法 内部可以直接访问 类属性 或者调用其他的 类方法

语法如下

@classmethod
def 类方法名(cls):
    pass
  • 类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法

  • 类方法的 第一个参数 应该是 cls

    • 哪一个类 调用的方法,方法内的 cls 就是 哪一个类的引用
    • 这个参数和 实例方法 的第一个参数是 self 类似
    • 提示 使用其他名称也可以,不过习惯使用 cls
  • 通过 类名. 调用 类方法调用方法时,不需要传递 cls 参数

  • 在方法内部

  • 可以通过 cls. 访问类的属性

  • 也可以通过 cls. 调用其他的类方法

在类方法内部,可以直接使用 cls 访问 类属性 或者 调用类方法

2.静态方法

  • 在开发时,如果需要在 中封装一个方法,这个方法:
    • 不需要 访问 实例属性 或者调用 实例方法
    • 不需要 访问 类属性 或者调用 类方法
  • 这个时候,可以把这个方法封装成一个 静态方法

语法如下

@staticmethod
def 静态方法名():
    pass
  • 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
  • 通过 类名. 调用 静态方法

4.总结

  • 实例方法 —— 方法内部需要访问 实例属性

  • 实例方法 内部可以使用 类名. 访问类属性

  • 类方法 —— 方法内部 需要访问 类属性

  • 静态方法 —— 方法内部,不需要访问 实例属性类属性

提问

如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?

答案

  • 应该定义 实例方法
  • 因为,类只有一个,在 实例方法 内部可以使用 类名. 访问类属性

五、继承

1.概念

  • 子类 拥有 父类 的所有 方法属性
  • 可以单继承和多继承

2.语法

class 类名(父类名):

    pass
  • 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
  • 子类 中应该根据 职责,封装 子类特有的 属性和方法

3.专业术语

  • Dog 类是 Animal 类的子类Animal 类是 Dog 类的父类Dog 类从 Animal继承
  • Dog 类是 Animal 类的派生类Animal 类是 Dog 类的基类Dog 类从 Animal派生

4.继承的传递性

  • C 类从 B 类继承,B 类又从 A 类继承
  • 那么 C 类就具有 B 类和 A 类的所有属性和方法

子类 拥有 父类 以及 父类的父类 中封装的所有 属性方法

提问: 哮天犬 能够调用 Cat 类中定义的 catch 方法吗?

5.方法的重写

  • 子类 拥有 父类 的所有 方法属性
  • 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发

应用场景

  • 父类 的方法实现不能满足子类需求时,可以对方法进行 重写(override)

重写 父类方法有两种情况:

  • 覆盖 父类的方法

  • 对父类方法进行 扩展

6.覆盖父类的方法

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

具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现

重写之后,在运行时,只会调用 子类中重写的方法,而不再会调用 父类封装的方法

7.对父类方法进行 扩展

  • 如果在开发中,子类的方法实现包含 父类的方法实现

    • 父类原本封装的方法实现子类方法的一部分
  • 就可以使用 扩展 的方式

    • 在子类中 重写 父类的方法

    • 在需要的位置使用 super().父类方法 来调用父类方法的执行

    • 代码其他的位置针对子类的需求,编写 子类特有的代码实现

"""继承。
父类  子类

继承如何表示:
class 子类名(父类名):
    pass


子类可以实现自己独有的方法。

子类可以覆盖父类的方法。 ==》 重写

super() 超继承: 使用父类当中的方法。

"""

class Phone:
    """手机"""

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

    def call(self, to, recorded=False):
        """打电话"""
        print(" {} 给 {} 打电话。。".format(self.number, to))

        if recorded:
            self.record()

    def record(self):
        """录音"""
        print("{} 正在录音".format(self.number))


class SmartPhone(Phone):
    """智能手机"""

    def __init__(self, number, brand):
        self.number = number
        self.brand = brand

    def watch_movie(self, name):
        print("正在看电影{}".format(name))


class Iphone(SmartPhone):
    # brand = '苹果'

    def __init__(self, number):
        super().__init__(number, '苹果')
        # self.number = number
        # self.brand = "苹果"

    def face_time(self):
        """录屏,直播"""
        print("{} 正在直播".format(self.number))

    def call(self, to, recorded=False, face=False):
        """打电话既可以录音,也可以facetime"""
        # print(" {} 给 {} 打电话。。".format(self.number, to))
        #
        # if recorded:
        #     self.record()

        super().call(to, recorded=False)

        if face:
            self.face_time()



# normal_phone = Phone('1')
# print(normal_phone.record())
#
# # 父类当中不能调用子类方法。
# # normal_phone.watch_movie("红海行动")
#
# smart_phone = SmartPhone("2")
# print(smart_phone.record())
# print(smart_phone.number)
# smart_phone.watch_movie('小偷家族')


# 当子类和父类具有同样的方法或者属性的时候。
# 父类还是用父类的, 子类不再有父类的,而是用自己的。
# normal = Phone("1")
# smart = SmartPhone(2, '华为')

# 重写例子2
iphone = Iphone('苹果5')
iphone.call('开始', face=True)

# smart = SmartPhone("123", '华为')
# smart.call('李三', face=True)

8.关于 super

  • Pythonsuper 是一个 特殊的类
  • super() 就是使用 super 类创建出来的对象
  • 最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
       # super默认会调用第一个父类的方法(适用于单继承 或者只想使用第一个父类的方法)
    
          # 02 方式 适用于新式类
          # 格式: super(子类类名, self).父类方法名()
    
    
    
    

总结

类的命名:大驼峰命名: 两个单词的首字母大写。
class PerfectManHelp

函数的命名:下划线命名:perfect_man_help

变量命名:下划线命名.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值