python中一切皆对象。

python中的类其实也是对象,可称为类对象。

  1. # 只是写了一个类,也可以查看该类的id和类型
  2. class Student:
  3. pass
  4. print(id(Student))
  5. print(type(Student))
  6. print(Student)
  7. 1767806514112
  8. <class 'type'>
  9. <class '__main__.Student'>

类的组成:

  • 类属性
  • 实例方法
  • 静态方法
  • 类方法
  1. class Student:
  2. native_place = '杭州' # 直接写在类中的变量,称为类属性
  3. def __init__(self, name, age):
  4. self.name = name # self.name称为实体属性,将局部变量的name赋给实体属性
  5. self.age = age
  6. # 实例方法
  7. def eat(self):
  8. print('eating...')
  9. # 静态方法
  10. @staticmethod
  11. def method():
  12. print('使用@staticmethod进行修饰,所以我是静态方法')
  13. # 类方法
  14. @classmethod
  15. def cm(cls):
  16. print('使用@classmethod进行修饰,所以我是类方法')
  17. # 在类之外定义的称为函数,在类之内定义的称为方法
  18. def drink():
  19. print('drinking...')

python 类与对象 - 图1clipboard1.png

Student类的对象会有一个类指针,指向Student类。

python 类与对象 - 图32.png

类属性、类方法、静态方法

  • 类属性:类内方法外的变量,被该类的所有对象所共享
  • 类方法:使用@classmethod修饰的方法,使用类名直接访问
  • 静态方法:使用@staticmethod修饰的方法,使用类名直接方法。静态方法和类方法的区别是,静态方法的参数列表中可以没有任何参数
  1. # 类属性 Demo
  2. stu1 = Student('John', 20)
  3. stu2 = Student('Mark', 21)
  4. print(stu1.native_place)
  5. print(stu2.native_place)
  6. Student.native_place = '深圳'
  7. print(stu1.native_place)
  8. print(stu2.native_place)
  9. 杭州
  10. 杭州
  11. 深圳
  12. 深圳
  1. # 类的对象Demo
  2. stu1 = Student('John', 20)
  3. print(id(stu1))
  4. print(type(stu1))
  5. print(stu1)
  6. print('------------------------------')
  7. print(id(Student))
  8. print(type(Student))
  9. print(Student)
  10. 2278326538096
  11. <class '__main__.Student'>
  12. <__main__.Student object at 0x0000021276D80F70>
  13. ------------------------------
  14. 2278325177088
  15. <class 'type'>
  16. <class '__main__.Student'>

调用实例方法的两种方式

  1. # 方式一
  2. stu1.eat()
  3. #方式二
  4. Student.eat(stu1)

第二种方式中,stu1 所对应的其实是实例方法定义中的 self 参数的位置。

动态绑定属性和方法

python 是动态语言,在创建对象后,可动态地绑定属性和方法。

动态绑定属性

  1. stu1 = Student('John', 20)
  2. stu1.gender = '男' # 动态绑定gender属性
  3. print(stu1.name, stu1.age, stu1.gender)
  4. # John 20 男

动态绑定方法

  1. def run():
  2. print('running...')
  3. stu1.run = run # 动态绑定run方法
  4. stu1.run()
  5. # running...

python 类与对象 - 图53.png
4.png

面向对象的三大特征

封装、继承、多态

封装:在 python 中没有专门的修饰符来让属性私有,如果不希望属性在类对象外部被访问,在属性名前加上两个“_”。

  1. class Student:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.__age = age # 不希望该属性在类外部被使用,在类内部可以使用
  5. def show(self):
  6. print(self.name, self.__age)
  7. stu = Student('John', 20)
  8. stu.show()
  9. print(stu.name)
  10. print(stu.__age) # 报错,不可访问

但在python中这些“私有”属性并不是严格不可访问。使用 dir() 可以查看对象的属性和方法:

  1. print(dir(stu))
  2. # ['_Student__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'show']

可以看到其中有一个 _Student__age 属性,其实这就是被“私有化”后的 age 属性,只是 __age 被改名为了 _Student__age。可以通过 _Student__age 访问属性 age

  1. print(stu._Student__age)
  2. # 20

继承:提升代码的复用性

  • 如果一个类没有继承任何类,则默认继承 object 类;
  • python 支持多继承;
  • 定义子类时,必须在其构造函数中调用父类的构造函数
  1. class Person(object):
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def info(self):
  6. print(self.name, self.age)
  7. class Student(Person):
  8. def __init__(self, name, age, stu_no):
  9. super().__init__(name, age)
  10. self.stu_no = stu_no
  11. class Teacher(Person):
  12. def __init__(self, name, age, teachOfYear):
  13. super().__init__(name, age)
  14. self.teachOfYear = teachOfYear
  15. stu = Student('张三', 20, '1001')
  16. teacher = Teacher('李四', 34, 10)
  17. stu.info() # 调用Person类的方法

多继承:

  1. class 子类名(父类1, 父类2, ...):
  2. pass

python 类与对象 - 图85.png
多态:提高代码的可扩展性和可维护性

方法重写

  1. class Person(object):
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def info(self):
  6. print(self.name, self.age)
  7. class Student(Person):
  8. def __init__(self, name, age, stu_no):
  9. super().__init__(name, age)
  10. self.stu_no = stu_no
  11. def info(self): # 重新Person的info方法
  12. super().info() # 调用父类的info()方法
  13. print(self.stu_no)
  14. class Teacher(Person):
  15. def __init__(self, name, age, teachOfYear):
  16. super().__init__(name, age)
  17. self.teachOfYear = teachOfYear
  18. stu = Student('张三', 20, '1001')
  19. teacher = Teacher('李四', 34, 10)
  20. teacher.info()
  21. print('------------')
  22. stu.info() # 调用Person类的方法
  23. # 李四 34
  24. # ------------
  25. # 张三 20
  26. # 1001

object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法
  • dir() 可查看指定对象的所有属性
  • object中有一个__str__方法,用于返回对于对象的描述。
  1. class Student:
  2. pass
  3. stu = Student()
  4. print(stu) # 好比是调用了Student中的__str__方法
  5. # <__main__.Student object at 0x0000018E9340E0D0>

重写 __str__ 方法:

  1. class Student:
  2. def __init__(self, name, age):
  3. self.name = name
  4. self.age = age
  5. def __str__(self): # 重写
  6. return f"我的名字是{self.name}, 今年{self.age}岁"
  7. stu = Student('John', 20)
  8. print(stu) # 默认调用了Student中的__str__方法
  9. # 我的名字是John, 今年20岁

类的特殊属性

__dict__:获取类对象或实例对象所绑定的所有属性和方法的字典。

  1. class A:
  2. pass
  3. class B:
  4. pass
  5. class C(A, B):
  6. def __init__(self, name):
  7. self.name = name
  8. x = C('John')
  9. print(x.__dict__)
  10. print(C.__dict__)
  11. print(x.__class__) # 输出对象所属的类
  12. print(C.__bases__) # 输出类的父类
  13. print(C.__base__) # 输出类的父类列表中的第一个父类
  14. print(C.__mro__) # 输出类的层次结构
  15. print(A.__subclasses__()) # 查看该类的子类
  16. # {'name': 'John'}
  17. # {'__module__': '__main__', '__init__': <function C.__init__ at 0x000002857BBFD940>, '__doc__': None}
  18. # <class '__main__.C'>
  19. # (<class '__main__.A'>, <class '__main__.B'>)
  20. # <class '__main__.A'>
  21. # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) 表示C继承自A和B,又继承自object,如下图
  22. # [<class '__main__.C'>]

python 类与对象 - 图106.png

类的特殊方法

__add__() __len__()

  1. a = 20
  2. b = 30
  3. print(a + b) # 本质:两个整数类型的对象相加
  4. # 50

实际上,上面的代码在底层执行了下面的操作:

  1. print(a.__add__(b)) # 50
  1. class Student:
  2. def __init__(self, name):
  3. self.name = name
  4. def __add__(self, other): # 重写__add__,使得两个Student对象能相加
  5. return self.name + other.name
  6. def __len__(self): # 重写__len__,使得能调用len(stu1)
  7. return len(self.name)
  8. stu1 = Student('张三')
  9. stu2 = Student('李四')
  10. print(stu1 + stu2)
  11. print(stu1.__add__(stu2))
  12. x = [1, 2, 3]
  13. print(len(x))
  14. # 上面的代码本质上是执行了下面的代码
  15. print(x.__len__())
  16. print(len(stu1)) # 使用重写后的__len__()
  17. # 张三李四
  18. # 张三李四
  19. # 3
  20. # 3
  21. # 2

导入模块

  1. import 模块名称 as 别名
  1. from 模块 import 变量/函数/类

if __name__ == '__main__'

每个模块的定义中都包括一个记录模块名称的变量 __name__

包含__init__.py 文件的目录称为包。

包和目录的区别:目录里通常不包含 __init__.py 文件。
7.png

  1. import package1.module_A # 导入包中的模块
  2. print(package1.module_A.a) # 调用包中模块的属性