一、类(class)
1.1 类的简介
- 目前所有学习的对象都是Python内置的对象。
- 对象是类的实例(instance)。
- 我们自定义类都需要使用大写字母开头,使用大驼峰命名法来对类命名。
- 使用 isinstance()函数来检查对象是否是某个类的实例。
class MyClass():
pass
mc = MyClass()
print(isinstance(mc, MyClass))
1.2 对象的创建流程
- 类也是一个对象,是用来创建对象的对象。
- 类是type类型的对象,定义类实际上就是定义了一个type类型的对象。
- 创建对象的流程:
- 创建一个变量mc。
- 在内存中创建一个新对象。
- 将对象的id赋值给变量mc。
1.3 类的定义
- 类和对象都是对现实生活中的内容中的抽象。
- 实际上所有是事物都由两部分构成:
- 数据(属性)
- 行为(方法)
- 定义语法
class 类名([ 父类 ]):
公共的属性...
# 初始化方法
def __init__(self,....):
...
# 其他方法
def method(self,...):
...
- 在类的代码块中,我们可以定义变量和函数
- 变量会称为该类实例的公共属性,所有该类实例都可以通过 对象.属性 的形式访问;
- 函数会称为该类实例的公共方法,所有该类实例都可以通过 对象.方法名 的形式调用。
- 注意:
- 方法调用时,第一个参数由解析器自动传递,所有定义方法时至少要定义一个形参self。
1.4 属性和方法
- 实例为什么能访问到类中的属性和方法:
- 类中定义的属性和方法都是公共的,任何实例都可以访问。
- 属性和方法查找的流程
- 当调用一个对象的属性时,解析器会先在当前对象中寻找是否由该属性:
- 如果有,直接返回当前对象的属性。
- 如果没有,则区当前对象的类中寻找:
- 如果有,返回类对象的属性值,
- 如果没有,报错。
- 当调用一个对象的属性时,解析器会先在当前对象中寻找是否由该属性:
- 类对象和实例对象中都可以保存属性(方法)
- 如果这个属性(方法)是所有实例共享的,则应该将其保存到类对象中
- 如果这个属性(方法)是某个实例独有,则应该保存早实例对象中
class Person():
name = ""
def say_hello(self):
print("你好我是 %s" % self.name)
p1 = Person()
p2 = Person()
p1.name = "Tom"
p2.name = "Jerry"
p1.say_hello()
p2.say_hello()
# 输出结果
# 你好我是 Tom
# 你好我是 Jerry
- self 表示调用方法的实例对象本身。(*类似于Java中的this*)
1.5 类的特殊方法__init__
- 在类中可以定义一些特殊方法(魔术方法)。
- 特殊方法都是以__(双下划线)开头,__(双下划线)结尾的方法。
- 特殊方法不需要自己手动调用,会在特殊的时刻自动调用。
- 比如__init__(self ,...) 在对象创建后自动调用,去初始化属性。(*类似于Java中的构造器*)
class Person():
# 构造方法
def __init__(self, name):
print("调用__init__方法")
self.name = name
def say_hello(self):
print("你好我是 %s" % self.name)
p1 = Person("Tom")
- p1=Person() 创建对象的流程
- 创建变量p1
- 在内存中创建一个Person类的新对象
- __init__(self) 方法执行
- 将对象id赋值给变量p1
1.6 练习
# 自定义一个表示狗的类
# 属性:name、age、gender、height
# 方法:eat()、run()
class Dog():
def __init__(self, name: str, age: int, gender: str, height: int):
self.name = name
self.age = age
self.gender = gender
self.height = height
def run(self):
print(self.name, "running")
def eat(self):
print(self.name, "eating")
d1 = Dog("旺财", 2, "boy", 8)
d1.run()
d1.eat()
二、封装
2.1 简介
- 面向对象的三大特性之一,确保对象数据的安全性。
- 让内部的数据无法直接被外部访问或修改,增加数据的安全性。
2.2 隐藏类中的属性
- 可以为对象的属性使用双下划线开头,__属性名
- 双下划线开头的属性是对象的隐藏属性,隐藏属性只能在类内部访问没无法通过对象。
- 其实隐藏属性只不过是Python自动为属性改了一个名字
- 实际上是将名字修改为了 _类名__属性名
class Dog():
def __init__(self, name: str):
self.__name = name
def set_name(self, name: str):
self.__name = name
def get_name(self):
return self.__name
d1 = Dog("旺财")
print(d1.get_name())
d1._Dog__name = "小白"
print(d1.get_name())
# 输出结果
# 旺财
# 小白
- 所以__开头的属性,实际上在外部依然可以访问 。防君子不防小人。
- 一般情况下我们会将一些私有属性(不被外部访问的属性)以_开头。
2.3 property装饰器
- getter方法装饰器:@property,把get方法,转换成对象的属性。
- 使用property装饰的方法名,跟属性名必须一样。
- setter方法装饰器:@属性名.setter
- @property必须写在@属性名.setter 之前,否则会报错。
class Dog():
def __init__(self, name: str):
self._name = name
# property装饰器,用来将一个get方法,转换成对象的属性
@property
def name(self):
return self._name
@name.setter
def name(self, name: str):
self._name = name
d1 = Dog("旺财")
print(d1.name)
d1.name = "小白"
print(d1.name)
# 输出结果
# 旺财
# 小白
三、继承
3.1 简介
- 面向对象的三大特性之一,保证对象的可扩展性。
- 通过继承可以获取到其他类中的属性和方法。
- 在定义类时,可以在类名后括号里指定当前类的父类(超类、基类、super)
- 子类(衍生类)可以直接继承父类中的所有属性和方法。
- 通过继承可以让子类避免重复编写跟父类相同的代码。
- 若省略父类,则默认继承父类object。object是所有类的父类。
- issubclass() 检查一个类是否是另一个类的子类。
class Animal():
def run(self):
print("动物跑")
def sleep(self):
print("动物睡觉")
class Dog(Animal):
def bark(self):
print("汪汪汪")
class Husky(Dog):
def komatik(self):
print("哈士奇拉雪橇")
h1 = Husky()
h1.run()
h1.sleep()
h1.bark()
h1.komatik()
3.2 方法重写(override)
- 子类中存在与父类同名的方法,通过子类实例调方法时,调用的是子类的方法。
- 当调用对象方法时:
- 去对象中寻找该方法:
- 存在,直接调用。
- 不存在,去父类中寻找:
- 存在,调用父类的方法。
- 不存在,去父类的父类中寻找。直到找到object,还没有则报错。
- 去对象中寻找该方法:
class A():
def test(self):
print("AAA")
class B(A):
def test(self):
print("BBB")
class C(B):
def test(self):
print("CCC")
c = C()
c.test()
# 输出结果
# CCC
3.3 super
- 有时候希望可以在子类中直接调用父类的方法。
- super() 可以用来获取当前类的父类,并且通过super()返回对象调用父类方法时,不需要传输self。
class Animal():
def __init__(self, name):
self._name = name
def run(self):
print("动物跑")
def sleep(self):
print("动物睡觉")
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
class Dog(Animal):
def __init__(self, name, age):
super().__init__(name)
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def bark(self):
print("汪汪汪")
def run(self):
print("动物跑")
d = Dog("旺财", 5)
print(d.name, d.age)
3.4 多重继承
- Python是支持多重继承的,即一个类同时指定多个父类
- 可以在类名()里添加多个类,实现多重继承。
- 多重继承的子类会获取所有父类中的方法。
- 实际开发中没有特殊情况,应该尽量避免多重继承。
- 类名.__bases__ 此属性可以用来获取当前类的所有父类。
- 如果多个父类中有同名的方法,则会按父类的顺序查找,前面的父类方法覆盖后面的。
class A(object):
def test(self):
print("AAA")
class B(object):
def test(self):
print("BBB")
class C(B, A):
def test2(self):
print("CCC")
print(C.__bases__)
c = C()
c.test()
# 输出结果
# (<class '__main__.B'>, <class '__main__.A'>)
# BBB
四、多态
- 多态是面向对象的三大特性之一,保证了程序的灵活性。
- 一个对象可以从不同的形态去呈现。
- 例子:len()
- 之所以一个对象能通过len()获取长度,是因为对象中具有特殊方法__len__
- 只要对象中具有__len__特殊方法,就可以通过len()获取长度。
class B():
def __init__(self, name):
self._name = name
def __len__(self):
return 10
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
b = B("Jerry")
print(len(b))
4.1 属性和方法
属性
- 类属性
- 定义:直接在类中定义。(类似于Java的static属性)
- 访问:可以通过类、实例访问。
- 修改:只可以通过类修改,实例对象无法修改。
- 实例属性
- 定义:在实例初始化时定义。
- 访问修改:只能通过实例对象访问修改,类无法访问修改。
方法
- 类方法
- 定义:在类内部,使用@classmethod 修饰,第一个参数是cls(类似于Java的static方法)
- 调用:类和实例调用时,均自动传递cls。
- 实例方法
- 定义:在类中定义,第一个参数为self的方法
- 调用:
- 类调用时,不会自动传递self,必须手动传递。
- 实例调用时,自动将实例对象作为self传入。
- 静态方法
- 定义:使用@staticmethod 修饰,不指定任何默认参数
- 调用:可以被类和实例调用
- 基本上是一个和当前类无关的方法,只是保存在类中的函数。
# 定义类
class A(object):
count = 0
# 类属性:直接在类中定义
# 可以通过类或者类的实例访问到
# 只能通过类对象来修改,无法通过实例对象修改
def __init__(self):
self.name = '孙悟空'
# 实例属性:通过实例对象添加的属性
# 只能通过实例对象来访问和修改,类对象无法访问修改
def test(self):
# 实例方法:在类中定义,第一个参数是self的方法都是实例方法
# 当通过实例调用时,会将调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时必须手动传递self
print("这是test=,实例方法")
# 类方法:类内部使用@classmethod修饰方法
@classmethod
def test_2(cls):
print("这是test2,类方法")
# 静态方法:使用@staticmethod修饰的方法
# 不需要指定参数,类和实例都可以去调用
# 基本上是一个和当前类无关的方法,只是一个保存到当前类中的函数。
@staticmethod
def test_3():
print("这是test_3,静态方法")
a = A()
#属性
print("A,", A.count)
print("a,", a.count)
# print("A,",A.name) # 报错,无法访问
print("a,", a.name)
#实例方法
a.test()
# A.test() # 报错,不会自动传self
A.test(a) # 等价于 a.test()
#类方法
A.test_2()
a.test_2()
#静态方法
A.test_3()
a.test_3()
输出结果:
A, 0
a, 0
a, 孙悟空
这是test=,实例方法
这是test=,实例方法
这是test2,类方法
这是test2,类方法
这是test_3,静态方法
这是test_3,静态方法
五、垃圾回收
- 在Python中有自动的垃圾回收机制,会自动将没有被引用的对象删除。
- __del__(self) 在对象被回收之前自动调用。
class A():
def __init__(self):
self.name = 'A类'
# 在对象被回收之前自动调用
def __del__(self):
print("A() 对象被删除了~", self)
a = A()
print(a.name)
a = None
# 输出结果
# A类
# A() 对象被删除了~ <__main__.A object at 0x0000029462A15A30>
六、特殊方法
- 特殊方法,也被称为魔术方法,都是使用双下划线开头和结尾的。
- 一般不需要手动调用,在特殊情况下自动执行。
__str__()方法
- 调用:在对象使用print()函数打印时自动调用。(类似于Java中的toString()方法)
- 作用:将对象内容转化成字符串。
- 返回:字符串。
class Person():
def __init__(self, name, age):
self._name = name
self._age = age
def __str__(self):
return "Person[name=%s ,age=%d]" % (self._name, self._age)
p1 = Person("Tom", 25)
p2 = Person("Jerry", 23)
print(p1)
print(p2)
输出结果
Person[name=Tom ,age=25]
Person[name=Jerry ,age=23]
__repr__()方法
- 调用:在对象使用repr()函数时自动调用。
- 作用:指定对象在 ‘交互模式’ 中直接输出的结果。
- 返回:字符串。
比较大小的特殊方法
- object.__lt__(self,other) 小于
- object.__le__(self,other) 小于等于
- object.__eq__(self,other) 等于
- object.__ne__(self,other) 不等于
- object.__gt__(self,other) 大于
- object.__ge__(self,other) 大于等于
以小于为例
- 调用:在对象做小于比较时调用。
- 作用:指定比较大小的数据。
- 返回:布尔值
class Person():
def __init__(self, name, age):
self._name = name
self._age = age
def __lt__(self, other):
return self._age < other._age
p1 = Person("Tom", 25)
p2 = Person("Jerry", 23)
print(p1 < p2) # False
print(p2 < p1) # True
__bool__(self)
- 调用:当对象转换成bool类型时被调用。
- 作用:指定对象转换成bool类型时的布尔值。
- 返回:布尔值
七、模块、包
7.1 简介
- 将程序分解成一个个小的模块,写到多个文件中。
- 特点:
- 方便开发
- 方便维护
- 模块可以复用
7.2 模块的创建
模块的创建
- 在python中一个py文件就是一个模块。
- 注意:模块名要符合标识符规范。
模块的引用
- 方式:
- import 模块名 (py文件名)
- import 模块名 as 模块别名
- 在每个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
- __name__属性为 __main__的模块就是主模块,程序的入口。
7.3 模块的使用
- 在模块中可以定义变量、函数、类
- 访问模块中的内容:模块名.变量、模块名.函数、模块名.类
- 引入模块的部分内容:from 模块名 import 变量、函数
- 此方式引入的,调用时不需要带上模块名。
模块代码:
# 在模块中定义变量
a = 10
b = 20
# 在模块中定义函数
def test():
print("test")
def test2():
print("test2")
# 在模块中定义类
class Person():
def __init__(self, name, age):
self._name = name
self._age = age
def __str__(self):
return "Person[name=%s ,age=%d]" % (self._name, self._age)
def __lt__(self, other):
return self._age < other._age
调用代码:
from m import a, b, test, test2, Person
print(a)
print(b)
test()
test2()
p1 = Person("Tom", 25)
print(p1)
- 当有部分代码只在当前文件作为主模块的时候才需要执行的情况时,而当模块被其他模块引入时,不需要执行的,此时我们就必须检查当前模块是否主模块。
if __name__ == '__main__':
p = Person("Jerry", 18)
print(p)
7.4 包
- 包是一个文件夹,包含了多个模块。
- 包中必须要有一个__init__.py 这个文件,这个文件可以包含有包中的主要内容。
- __pycache__ 是模块的缓存文件:
- py代码在执行前,需要被解析器转换成机器码,然后再执行,
- 为例提高运行性能,python在编译一次过后,将代码保存到一个缓存文件中,
- 这样下次再加载这个模块(包)时,就不用再重复编译,而是直接加载缓存中编译好的代码即可。
7.5 Python标准库
- 开箱即用。
- 为了实现开箱即用的思想,Python提供了一个模块的标准库,
- 在标准库中,有很多强大的模块可以直接使用,并且标准库会随Python安装一起安装。
sys模块
- sys.argv :属性,当前命令所有参数的列表。
- sys.modules:属性,当前程序引入的所有模块,形式是字典,key是模块名,value是模块对象。
- sys.path:属性,模块的搜索路径的列表。
- sys.platform :属性,当前python运行的平台:linux、win32、cygwin、darwin。
- sys.exit():函数,退出程序。
pprint模块 √
- pprint.pprint():可以用来对打印的数据简单的格式化。
os模块 对操作系统进行访问
- os.environ:属性,获取到系统的环境变量
- os.system():方法,可以用来执行操作系统的名字,相当于cmd。
os.system("notepad") # 打开记事本