Python面向对象、类属性、类方法

1,104 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

8. 类属性[理解]

  • 实例==对象

  • 实例对象就相当于java中的没有static修饰的对象,类对象就相当于java中的static所修饰的对象

  • 对象(实例对象): 1.通过class定义的类创建的, 即通过类实例化来的, 又称为实例, 实例对象 2.实例对象定义的属性称为是 实例属性. 通过实例对象(self) 定义的属性都是实例属性 3.实例属性: 每个实例对象中都存在一份,并且值可能是不一样的

  • 类(类对象): 1.通过class定义的,又称为 类对象, 是python解释器在创建类的时候自动创建的 2.作用: 1. 通过类对象,去定义实例对象 2. 类对象可以保存一些属性信息,称为类属性 3.类属性的定义: 在类内部,方法外部定义的变量就是类属性 4.类属性,字内存中只有一份

如何确定一个属性是该定义为实例属性还是类属性? 先假设这个属性为实例属性,查看这个属性值对于不同的实例对象, 属性值是否都一样,并且需要同时变化. 如果是, 则可以定义为类属性 如果不是,则可以定义为实例属性

class Dog(object):
    # 定义类属性, 类名
    class_name = '狗类'
    name = '222'

    def __init__(self, name, age):
        # 定义的都是实例属性
        self.name = name
        self.age = age


# 创建Dog 类对象
dog = Dog('萨摩耶', 2)
print(dog.__dict__)  # 打印dog对象具有的属性

# 类名.__dict__  查看类对象具有的属性
print(Dog.__dict__)

# 访问类属性
# 类名.类属性
print(Dog.class_name)

# 修改类属性  类名.类属性 = 属性值
Dog.class_name = 'Dog类'

print(Dog.class_name)

# 补充, 注意: 如果不存在和实例属性名相同的类属性.则可以使用实例对象访问类属性的值
# 如果存在重名,则使用实例属性访问的一定是实例属性,不是类属性
print(dog.name)

在这里插入图片描述

9. 类方法

  • 类方法和java中c++中用static修饰的静态成员函数相似。

  • 实例方法: 类中默认定义的方法,就是实例方法, 第一个参数为self,表示实例对象

  • 类方法: 使用 @classmethod 装饰的方法,称为类方法, 第一个参数是cls,代表的是类对象自己

  • 什么情况定义为实例方法,什么情况定义为类方法? 1.如果在方法中使用了实例属性, 那么该方法必须定义为实例方法 2.前提:不需要使用实例属性. 需要使用类属性,可以将这个方法定义为类方法

class Dog(object):
    class_name = '狗类'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def play(self):  # 实例方法
        print(f"小狗{self.name} 在快乐的拆家....")

    # def get_class_name(self):  # 是实例方法, 因为没有使用实例属性,所以可以定义为类方法
    #     return Dog.class_name

    @classmethod
    def get_class_name(cls):  # cls 是类方法的默认形参,在调用的时候,不需要手动传递,python解释器会自动传递
        return cls.class_name


dog = Dog('二哈', 2)
dog.play()
print(dog.get_class_name())   # 对象.类方法()

# 类名.类方法()
print(Dog.get_class_name())

10. 静态方法[掌握]

  • 实例方法: 类中默认定义的方法,就是实例方法, 第一个参数为self,表示实例对象
  • 类方法: 使用 @classmethod 装饰的方法,称为类方法, 第一个参数是cls,代表的是类对象自己
  • 静态方法: 使用 @staticmethod 装饰的方法,称为静态方法, 对参数没有特殊要求,可以有,可以没有
  • 什么情况定义为实例方法,什么情况定义为类方法, 什么情况下静态方法? 1.如果在方法中使用了实例属性, 那么该方法必须定义为实例方法 2.前提:不需要使用实例属性. 需要使用类属性,可以将这个方法定义为类方法 3.前提:不需要使用实例属性,同时也不需要使用类属性, 此时可以将这个方法定义为静态方法
class Dog(object):
    class_name = '狗类'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def play(self):  # 实例方法
        print(f"小狗{self.name} 在快乐的玩耍....")

    @staticmethod  # 定义静态方法
    def show_info():
        print('这是一个Dog类')


dog = Dog('萨摩耶', 2)
dog.play()
# 对象.方法名()
dog.show_info()
# 类名.方法名()
Dog.show_info()

11. 多态[理解]

  • 在需要使用父类对象的地方,也可以传入子类对象,得到不同的结果 ---- 多态
  • 实现步骤: 1.子类继承父类 2.子类重写父类中的同名方法 3.定义一个共同的方法, 参数为父类对象.在方法中调用子类和父类同名的方法
"""
在需要使用父类对象的地方,也可以传入子类对象,得到不同的结果 ---- 多态
实现步骤:
1. 子类继承父类
2. 子类重写父类中的同名方法
3. 定义一个共同的方法, 参数为父类对象.在方法中调用子类和父类同名的方法
"""


# 1. 定义Dog类
class Dog(object):
    def __init__(self, name):
        self.name = name

    def play(self):
        print(f'小狗{self.name} 在玩耍.......')


# 2. 定义哮天犬类,继承Dog类
class XTQ(Dog):
    # 3. 重写 play方法
    def play(self):
        print(f'{self.name} 在天上追云彩.....')


# 4. 定义一个共同的方法,
def play_with_dog(obj_dog):
    obj_dog.play()


# 创建Dog类对象@
dog = Dog('萨摩耶')
play_with_dog(dog)

# 创建一个XTQ类的对象
xtq = XTQ('黄鹂鸟')
play_with_dog(xtq)

12. 鸭子类型

  • 鸭子类型(duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定

  • “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”我们并不关心对象是什么类型,到底是不是鸭子,只关心行为

  • 鸭子类型在动态语言中经常使用,非常灵活,使得python不想java那样专门去弄一大堆的设计模式。

  • 与 duck typing 相对应的风格是 normal typing,后者由对象类型决定了对象的特性。以下对比说明二者区别:

  • 一方面,以 形象化的表述 为例:在使用 normal typing 的语言中,可以编写一个 “鸭子动作” 函数,它能够接受一个类型为 “鸭子” 的对象,并调用它的 “叫”、“跑” 等方法。在运行前,需要进行对象是否确实为 “鸭子” 等类型检查。相应地,在使用 duck typing 的语言中,也可以编写一个 “鸭子动作” 函数,它能够接受一个任意类型的对象,并调用它的 “叫”、“跑” 等方法。换言之,只要传入对象具有正确的 “叫”、“跑” 等方法,就都可以被函数正常接受和调用。但如果这些需要被调用的方法不存在,那么将引发一个运行时错误。

  • 另一方面,以结合语言的表述 为例:C、C++和java属于 normal typing,在 编译阶段进行静态检查,函数定义和传参类型不一致就报错。相应地,Python 属于 duck typing,对象的类型不重要,只要对象具有类型 duck 的方法和属性,那么它就会被当做类型 duck 来使用 (因此经常能够混用类型)。Python 没有静态检查类型匹配情况,只有运行时找不到相应属性和方法时才报错。

  • 此外,如果只了解C、Java、C++ 等静态语言,可能对鸭子类型的理解并不深刻,因为静态语言中,对象的特性取决于其父类。而动态语言则显著有别,例如 Python 的迭代器 (iterator),任何支持迭代协议 (同时实现·__iter____next__方法) 的对象都可称之为迭代器,但对象本身是什么类型都不受到限制,甚至可以为任何自定义类。

# 1. 定义DOg类
class Dog(object):
    def __init__(self, name):
        self.name = name

    def play(self):
        print(f'小狗{self.name} 在玩耍.......')


# 2. 定义哮天犬类,继承Dog类
class XTQ(Dog):
    # 3. 重写 play方法
    def play(self):
        print(f'{self.name} 在天上追云彩.....')


class Cat(object):
    def __init__(self, name):
        self.name = name

    def play(self):
        print(f'小猫{self.name} 被撸中...')


# 4. 定义一个共同的方法,
def play_with_dog(obj_dog):
    obj_dog.play()


# 创建Dog类对象@
dog = Dog('萨摩耶')
play_with_dog(dog)

# 创建一个XTQ类的对象
xtq = XTQ('黄鹂鸟')
play_with_dog(xtq)


cat = Cat('布偶')
play_with_dog(cat)