Python面向对象

面向对象3要素

  • 封装
    组装:将数据和操作组装到一起
    隐藏数据:对外只暴露一些接口,通过接口访问对象。
  • 继承
    多复用,相同功能通过继承来避免重复造轮子
    多继承少修改,使用继承来改变特性,体现个性化
  • 多态
    面向对象编程最灵活的地方,动态绑定。

类的定义

class ClassName:
语句块

  • 必须使用class关键字

  • 类名建议大驼峰

  • 类定义完成后,就产生了一个类对象,绑定到ClassName上

  1. class MyClass
  2. '''A example class'''
  3. x = 'abc' # 类属性
  4. def foo(self):
  5. return 'My Class' # 类方法foo
  6. a = MyClass()

类对象及类属性

  • 类对象,类的定义就会生成一个类对象
  • 类的属性,类定义中的变量和类中定义的方法都是类的属性,如上例
  • 类变量,x是MyClass的变量
  • MyClass中,x、foo(也可称方法)都是类的属性,doc也是类的属性
  • foo是method方法对象,不是普通的函数对象function了,必须至少有一个参数,且第一个参数必须是self。self指代当前示例本身
  • a = MyClass()表示实例化,实例化后会得到一个对象,就是实例对象

init方法

MyClass()实际上调用的是init(self)方法,可以不定义,如果没有定义会在实例化后隐式调用,主要作用是对示例进行初始化

  1. class MyClass:
  2. def __init__(self):
  3. self.name = 'tom'
  4. print(self.name)
  5. a = MyClass() #会调用__init__

初始化函数可以多个参数,单第一个位置必须是self
注意:init()方法不能有返回值,也就只能是None

实例的特殊属性

实例变量是每一个实例自己的变量,是自己独有的,类变量是类的变量,是类的所有实例共享的属性和方法

  • __name__:对象名
  • __class__:对象的类型
  • __dict__:对象的属性的字典
  • __qualname__:类的限定名
  1. class Person:
  2. x = 'abc'
  3. def __init__(self):
  4. self.name = 'tom'
  5. self.age = 18
  6. print(self.name, self.age)
  7. def show(self, x, y):
  8. self.name = x
  9. self.age = y
  10. print(self.name, self.age)
  11. a = Person()
  12. print(a.__class__, Person.__class__, sep='\n')
  13. # a.__class__: <class '__main__.Person'> 实例的__class__为类的方法
  14. # Person.__class__: <class 'type'> 类的__class__为类的类型
  15. print(a.__class__.__qualname__, Person.__qualname__, sep='\n')
  16. # a.__class__.__qualname__:Person 实例本身并没有__qual_name__属性
  17. # Person.__qualname__:Person 返回类的限定名
  18. print(a.__class__.__name__, Person.__name__, sep='\n')
  19. # a.__class__.__name__: Person 实例本身并没有__name__属性
  20. # Person.__name__: Person 返回类的名称
  21. print(a.__dict__, Person.__dict__, sep='\n')
  22. # a.__dict__:{'name': 'tom', 'age': 18} 返回实例的属性
  23. # Person.__dict__:{'__module__': '__main__', 'x': 'abc', '__init__': <function Person.__init__ at 0x000001AA057AB840>...} # 返回类属性

总结:

  • 是类的属性,也是这个类所有实例的,所有实例都可以访问到,是实例的,就是这个实例自己的,通过类访问不到

  • 类变量是属于类的变量,这个类的所有实例都可以共享这个变量

  • 实例可以动态的给自己增加一个属性,实例.__dict__[变量名]实例.变量名都可以访问到

  • 实例的同名变量会隐藏这类变量,或者说覆盖了这个类的变量

  • 实例属性的查找顺利

    • 指的是实例使用.来访问属性,会先找自己的__dict__,如果没有,通过属性class找到自己的类,在去找类的__dict__
    • 如果实例使用__dict__[变量名]访问变量,将不会按照上面的查找顺序找变量了。

装饰一个类(不是类装饰器)

def add_name(name):
# 装饰器,增加类的属性
    def wapper(cls):
        cls.Name = name
        return cls
    return wapper

@add_name('Tom')
class Person:
    age = 18

print(Person.age, Person.Name)
# 本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象

类方法和静态方法

class Person:
    @classmethod
    def classs_method(cls):
        print('class = {0.__name__} ({0})'.format(cls))
        cls.Height = 180

    @staticmethod
    def static_method(): # 无需传入self或cls参数
        print(Person.Height)

Person.classs_method()
print(Person.__dict__)

Person.static_method()
  • 类方法

    • 在类定义中,使用@classmethod装饰器修饰的方法
    • 至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
    • 通过cls可以直接操作类的属性,但无法通过cls操作类的实例(此时的cls相当于是从模板中复制了一个实体,所以根本不知道类中有多少其他的实例)
  • 静态方法

    • 在类定义中使用@staticmethod装饰器修饰的方法
    • 调用时,不会隐式传入参数
    • 静态方法,只是表明这个方法属于这个名词空间,函数归在一起,方便组织管理

属性装饰器

一般的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter和setter来读取设置属性

类中变量以__开头,在被访问的时候会被解释器隐藏。如下例中__his就不可直接访问,如需访问需使用_Person__his

class Person:
    def __init__(self, chi, eng, his):
        self.__chi = chi
        self.__eng = eng
        self.__his = his

    @property  # 装饰器,后面跟的函数名就是以后的属性名,实现的就是getter功能,有了它表示为只读属性
    def chiense(self):
        return self.__chi

    @chiense.setter  # 装饰器,与属性名同名,且接受2个参数,第一个是self,第二个是要赋予的值,有了它表示可写
    def chinese(self, value):
        self.__chi = value


student1 = Person(80, 90, 100)
print(student1.chinese)  # getter功能
student1.chinese = 100  # setter功能
print(student1.chinese)

# property装饰器必须在前,stter、deleter装饰器在后
# property装饰器能通过简单的方式,把对方法的操作变成对属性的访问,起到一定的隐藏效果