# 面向对象

类是对象的抽象,对象是类的实列,在面向对象的世界中,一切皆为对象,对象都有属性和行为。

# 定义类

class Dog:

    def __init__(self,name):
        self.name = name
        self.tricks = []

    def add_trick(self,trick):
        self.tricks.append(trick)

# 创建和使用对象

kitty = Dog('kitty')

kitty.add_trick('play ball')

kitty.add_trick('roll over')

print(kitty,kitty.name,kitty.tricks)

# 访问可见性

在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头。

在实际开发中,我们并不建议将属性设置为私有的,因为这会导致子类无法访问。所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    test._Test__bar()
    print(test._Test__foo)


if __name__ == "__main__":
    main()

# 面向对象的支柱

面向对象的三大支柱:封装,继承和多态。

在Python中,类就是封装数据和方法的地方。封装的好处是隐藏了类的内部实现细节,仅对外提供必要的接口。这增加了数据的安全性,并允许我们更灵活地修改类的内部实现,而无需修改外部代码。

在Python中,可以通过私有属性和方法来实现封装。私有属性通常以下划线_开头,但这只是一个约定,并不是强制的。私有方法也是以下划线_开头。虽然Python没有严格的访问控制(如Java中的public、private、protected),但按照约定,外部代码应该避免直接访问和修改私有属性和方法。

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

使用 isinstance() 来检查一个实例的类型,使用 issubclass() 来检查类的继承关系。

# @property装饰器

我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便。

class Person(object):

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

    # 访问器 - getter方法
    @property
    def name(self):
        return self._name

    # 访问器 - getter方法
    @property
    def age(self):
        return self._age

    # 修改器 - setter方法
    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 16:
            print('%s正在玩飞行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大锤', 12)
    person.play()
    person.age = 22
    person.play()

    # 此处不会报错
    person.uncle = '白元芳'
    print(person.uncle)

    # 但在此处输出属性 name 时,报错
    person.name = '白元芳'  # AttributeError: can't set attribute

if __name__ == '__main__':
    main()

# __slots__魔法

Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用

class Person(object):

    # 限定Person对象只能绑定_name, _age和_gender属性
    __slots__ = ('_name', '_age', '_gender')

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

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 16:
            print('%s正在玩飞行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大锤', 22)
    person.play()
    person._gender = '男'
    # AttributeError: 'Person' object has no attribute '_is_gay'
    # person._is_gay = True

# 静态方法和类方法

在 Python 中,静态方法和类方法是类定义中的两种特殊方法。它们都与类相关,但调用和使用方式有所不同。

# 静态方法

  • 定义:静态方法是与类相关联的函数,但不需要访问类的任何状态(如实例变量或类变量)或执行与类相关的任何操作。它们类似于模块级别的函数,但可以通过类来组织。

  • 语法:使用 @staticmethod 装饰器来定义静态方法。

  • 调用:静态方法可以通过类名或实例来调用,但它们不会接收特殊的第一个参数(如 self 或 cls),因此无法直接访问类的状态或实例的属性。

class MyClass:  
    @staticmethod  
    def my_static_method():  
        print("This is a static method.")  
  
# 通过类名调用  
MyClass.my_static_method()  
  
# 通过实例调用(虽然不推荐,但也可以)  
instance = MyClass()  
instance.my_static_method()

# 类方法

  • 定义:类方法是与类本身关联的方法,而不是与类的实例关联。它们通常用于修改类的状态(如类变量)或执行与类相关的操作,而不是与实例相关的操作。

  • 语法:使用 @classmethod 装饰器来定义类方法。类方法接收一个特殊的第一个参数 cls,它引用类本身。

  • 调用:类方法可以通过类名或实例来调用,但通常通过类名来调用,因为它们通常与类的状态相关,而不是与特定的实例相关。

class MyClass:  
    class_variable = "This is a class variable."  
  
    @classmethod  
    def my_class_method(cls):  
        print(cls.class_variable)  
  
# 通过类名调用  
MyClass.my_class_method()  
  
# 通过实例调用(虽然不推荐,但也可以)  
instance = MyClass()  
instance.my_class_method()

静态方法:与类相关,但不与类或其实例的状态相关。可以通过类名或实例来调用,但不接收特殊的第一个参数。

类方法:与类本身相关,可以修改或访问类的状态。通过类名或实例来调用,但通常通过类名来调用。接收一个特殊的第一个参数 cls,它引用类本身。