python中一切皆对象。
python中的类其实也是对象,可称为类对象。
# 只是写了一个类,也可以查看该类的id和类型class Student:passprint(id(Student))print(type(Student))print(Student)1767806514112<class 'type'><class '__main__.Student'>
类的组成:
- 类属性
- 实例方法
- 静态方法
- 类方法
class Student:native_place = '杭州' # 直接写在类中的变量,称为类属性def __init__(self, name, age):self.name = name # self.name称为实体属性,将局部变量的name赋给实体属性self.age = age# 实例方法def eat(self):print('eating...')# 静态方法@staticmethoddef method():print('使用@staticmethod进行修饰,所以我是静态方法')# 类方法@classmethoddef cm(cls):print('使用@classmethod进行修饰,所以我是类方法')# 在类之外定义的称为函数,在类之内定义的称为方法def drink():print('drinking...')

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

类属性、类方法、静态方法:
- 类属性:类内方法外的变量,被该类的所有对象所共享
- 类方法:使用@classmethod修饰的方法,使用类名直接访问
- 静态方法:使用@staticmethod修饰的方法,使用类名直接方法。静态方法和类方法的区别是,静态方法的参数列表中可以没有任何参数
# 类属性 Demostu1 = Student('John', 20)stu2 = Student('Mark', 21)print(stu1.native_place)print(stu2.native_place)Student.native_place = '深圳'print(stu1.native_place)print(stu2.native_place)杭州杭州深圳深圳
# 类的对象Demostu1 = Student('John', 20)print(id(stu1))print(type(stu1))print(stu1)print('------------------------------')print(id(Student))print(type(Student))print(Student)2278326538096<class '__main__.Student'><__main__.Student object at 0x0000021276D80F70>------------------------------2278325177088<class 'type'><class '__main__.Student'>
调用实例方法的两种方式
# 方式一stu1.eat()#方式二Student.eat(stu1)
第二种方式中,stu1 所对应的其实是实例方法定义中的 self 参数的位置。
动态绑定属性和方法
python 是动态语言,在创建对象后,可动态地绑定属性和方法。
动态绑定属性
stu1 = Student('John', 20)stu1.gender = '男' # 动态绑定gender属性print(stu1.name, stu1.age, stu1.gender)# John 20 男
动态绑定方法
def run():print('running...')stu1.run = run # 动态绑定run方法stu1.run()# running...
面向对象的三大特征
封装、继承、多态
封装:在 python 中没有专门的修饰符来让属性私有,如果不希望属性在类对象外部被访问,在属性名前加上两个“_”。
class Student:def __init__(self, name, age):self.name = nameself.__age = age # 不希望该属性在类外部被使用,在类内部可以使用def show(self):print(self.name, self.__age)stu = Student('John', 20)stu.show()print(stu.name)print(stu.__age) # 报错,不可访问
但在python中这些“私有”属性并不是严格不可访问。使用 dir() 可以查看对象的属性和方法:
print(dir(stu))# ['_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:
print(stu._Student__age)# 20
继承:提升代码的复用性
- 如果一个类没有继承任何类,则默认继承
object类; - python 支持多继承;
- 定义子类时,必须在其构造函数中调用父类的构造函数
class Person(object):def __init__(self, name, age):self.name = nameself.age = agedef info(self):print(self.name, self.age)class Student(Person):def __init__(self, name, age, stu_no):super().__init__(name, age)self.stu_no = stu_noclass Teacher(Person):def __init__(self, name, age, teachOfYear):super().__init__(name, age)self.teachOfYear = teachOfYearstu = Student('张三', 20, '1001')teacher = Teacher('李四', 34, 10)stu.info() # 调用Person类的方法
多继承:
class 子类名(父类1, 父类2, ...):pass

多态:提高代码的可扩展性和可维护性
方法重写
class Person(object):def __init__(self, name, age):self.name = nameself.age = agedef info(self):print(self.name, self.age)class Student(Person):def __init__(self, name, age, stu_no):super().__init__(name, age)self.stu_no = stu_nodef info(self): # 重新Person的info方法super().info() # 调用父类的info()方法print(self.stu_no)class Teacher(Person):def __init__(self, name, age, teachOfYear):super().__init__(name, age)self.teachOfYear = teachOfYearstu = Student('张三', 20, '1001')teacher = Teacher('李四', 34, 10)teacher.info()print('------------')stu.info() # 调用Person类的方法# 李四 34# ------------# 张三 20# 1001
object类
- object类是所有类的父类,因此所有类都有object类的属性和方法
- dir() 可查看指定对象的所有属性
- object中有一个
__str__方法,用于返回对于对象的描述。
class Student:passstu = Student()print(stu) # 好比是调用了Student中的__str__方法# <__main__.Student object at 0x0000018E9340E0D0>
重写 __str__ 方法:
class Student:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self): # 重写return f"我的名字是{self.name}, 今年{self.age}岁"stu = Student('John', 20)print(stu) # 默认调用了Student中的__str__方法# 我的名字是John, 今年20岁
类的特殊属性
__dict__:获取类对象或实例对象所绑定的所有属性和方法的字典。
class A:passclass B:passclass C(A, B):def __init__(self, name):self.name = namex = C('John')print(x.__dict__)print(C.__dict__)print(x.__class__) # 输出对象所属的类print(C.__bases__) # 输出类的父类print(C.__base__) # 输出类的父类列表中的第一个父类print(C.__mro__) # 输出类的层次结构print(A.__subclasses__()) # 查看该类的子类# {'name': 'John'}# {'__module__': '__main__', '__init__': <function C.__init__ at 0x000002857BBFD940>, '__doc__': None}# <class '__main__.C'># (<class '__main__.A'>, <class '__main__.B'>)# <class '__main__.A'># (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) 表示C继承自A和B,又继承自object,如下图# [<class '__main__.C'>]
类的特殊方法
__add__() __len__()
a = 20b = 30print(a + b) # 本质:两个整数类型的对象相加# 50
实际上,上面的代码在底层执行了下面的操作:
print(a.__add__(b)) # 50
class Student:def __init__(self, name):self.name = namedef __add__(self, other): # 重写__add__,使得两个Student对象能相加return self.name + other.namedef __len__(self): # 重写__len__,使得能调用len(stu1)return len(self.name)stu1 = Student('张三')stu2 = Student('李四')print(stu1 + stu2)print(stu1.__add__(stu2))x = [1, 2, 3]print(len(x))# 上面的代码本质上是执行了下面的代码print(x.__len__())print(len(stu1)) # 使用重写后的__len__()# 张三李四# 张三李四# 3# 3# 2
导入模块
import 模块名称 as 别名
from 模块 import 变量/函数/类
if __name__ == '__main__'
每个模块的定义中都包括一个记录模块名称的变量 __name__ 。
包
包含__init__.py 文件的目录称为包。
包和目录的区别:目录里通常不包含 __init__.py 文件。
import package1.module_A # 导入包中的模块print(package1.module_A.a) # 调用包中模块的属性

