1 类的基本使用
class Person:
def __init__(self, name):
self.name = name
def info(self):
print(f'姓名为{ self.name }')
person = Person('小明')
person.info() # 姓名为小明
python3中写成
class 类名
会自动解析为新式类class 类名(object)
2 类中的self(代表调用对象自身)
class Person:
def info(self):
print(self)
person = Person('小明')
print(person) # <__main__.Person object at 0x000001ADE83CAE48>
person.info() # <__main__.Person object at 0x000001ADE83CAE48>
3 魔法方法
class Washer:
def __init__(self, w, h):
self.width = w
self.height = h
def __str__(self):
return '洗衣机对象'
def __del__(self):
print(f'【{self}】已被删除')
washer = Washer(100, 200)
print(washer)
# 控制台输出如下:
# 洗衣机对象
# 【洗衣机对象】已被删除
4 私有属性和方法
class Person:
def __init__(self):
self.__age = 17
def __priv(self):
print('Person私有方法')
class Son(Person):
pass
person = Person()
print(person.__age) # 报错
print(person._Person__age ) # 17
person.__priv() # 报错
person._Person__priv() # Person私有方法
son = Son()
print(son.__age ) # 报错
print(son._Son__age ) # 报错
print(son._Person__age ) # 100
son.__priv() # 报错
son._Son__priv() # 报错
son._Person__priv() # Person私有方法
5 继承
5.1 多继承
class A:
def info(self):
print(f'A中的info方法')
class B:
def info(self):
print(f'B中的info方法')
class Test(B, A):
pass
test = Test()
print(Test.__mro__)
test.info()
# 控制台输出如下:
# (<class '__main__.Test'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
# B中的info方法
5.2 子类调用父类方法
class Animal:
def __init__(self):
self.name = 'animal'
def info(self):
print(f'Animal中{self.name}')
class Dog(Animal):
def __init__(self):
self.name = 'dog'
def info(self):
# 调用子类初始化方法,对象name属性值赋为dog
self.__init__()
print(f'Dog中{self.name}')
def super_info(self):
# 调用父类初始化方法,对象name属性值赋为animal
super().__init__() # super(Dog, self).__init__()的缩写,也可写为Animal.__init__(self)
super().info() # super(Dog, self).info()的缩写,也可写为Animal.info(self)
dog = Dog()
dog.info()
dog.super_info()
dog.info()
# 控制台输出如下:
# Dog中dog
# Animal中animal
# Dog中dog
若子类Dog调用完父类方法后不做
self.__init__()
初始化,即为如下代码:class Dog(Animal): def __init__(self): self.name = 'dog' def info(self): # self.__init__() print(f'Dog中{self.name}') def super_info(self): super().__init__() super().info()
此时按照如上调用顺序则控制台输出为(对象name属性被
super().__init__()
初始化为animal):# Dog中dog # Animal中animal # Dog中animal
6 多态
class Animal:
def bark(self):
pass
class Dog(Animal):
def bark(self):
print('汪汪汪~')
class Cat(Animal):
def bark(self):
print('喵喵喵~')
class Test:
def bark(self, obj):
obj.bark()
dog = Dog()
cat = Cat()
test = Test()
test.bark(dog) # 汪汪汪~
test.bark(cat) # 喵喵喵~
多态:继承自同一父类的不不同子类,实例化出不同对象,传入不同对象调用相同方法表现出不同状态
7 类属性、类方法和静态
7.1 类属性
class Test:
a = 100
test = Test()
print(Test.a) # 100
print(test.a) # 100
test.a = 200 # 此处并非是将类属性a值改为200,而是实例test新增一个属性a,值为200
print(Test.a) # 100
print(test.a) # 200
7.2 类方法
class Test:
__age = 100
def __init__(self):
self.__age = 20
@classmethod
def get_age(cls):
print(cls.__age)
def instance_fun(self):
print('实例方法')
test = Test()
print(test.__age) # 报错
print(test._Test__age) # 20 此处访问的是实例私有属性
print(Test.__age) # 报错
print(Test._Test__age) # 100 此处访问的是类私有属性
test.get_age() # 100 此处访问类属性而非实例属性
Test.get_age() # 100
test.instance_fun() # 实例方法
Test.instance_fun() # 报错,类不能访问实例方法
\ | 实例方法 | 类方法 | 静态方法 |
---|---|---|---|
a = A() | a.foo(x) | a.class_foo(x) | a.static_foo(x) |
A | 不可用 | A.class_foo(x) | A.static_foo(x) |
7.3 静态方法
class Test:
@staticmethod
def static_fun():
print('静态方法')
test = Test()
test.static_fun() # 静态方法
Test.static_fun() # 静态方法
8 异常
8.1 基本使用
try:
可能发生异常的代码
except:
出现异常执行的代码
8.2 详细语法
try:
可能发生异常的代码
except 异常类型 as result:
print(result) # 捕获单个异常并输出异常信息
except (异常类型1, 异常类型2) as result:
print(result) # 捕获多中可能出现的异常并输出具体发生的某一异常信息
except:
捕获所有异常
except Exception as result:
print(result) # 捕获所有可能出现的异常并输出具体发生的某一异常信息
else:
没有发生异常时执行的代码
finally:
无论是否发生异常都执行的代码
8.3 自定义异常
class Error(Exception):
def __init__(self, len, min_len):
self.len = len
self.min_len = min_len
def __str__(self):
return f'输入的长度为{self.len},不能少于{self.min_len}个字符'
try:
con = input('请输入密码:')
if len(con) < 3:
ex = Error(len(con), 3) # 也可直接不定义专门异常类,ex = Exception(输入密码长度小于3位)
raise ex
except Exception as result:
print(result)
else:
print('密码输入完成')
由于异常具有传递性,所以一般在主程序中进行异常捕获即可,无需在每个子函数中进行处理
9 模块
9.1 模块导入
"""
方法一:
导入:import 模块名(import 模块名1, 模块名2...)
使用:模块名.功能
"""
import math
print(math.sqrt(9))
"""
方法二:
导入:from 模块名 import 功能(from 模块名 import 功能1, 功能2...)
使用:功能调用(不需要书写模块名.功能)
"""
from math import sqrt
print(sqrt(9))
"""
方法三:
导入:from 模块名 import *
使用:功能调用(不需要书写模块名.功能)
"""
# 方法三:from 模块名 import *; 功能调用(不需要书写模块名.功能)
from math import *
print(sqrt(9))
"""
方法四:
导入:import 模块名 as 模块别名
使用:模块别名.功能
"""
import time as tt
tt.sleep(2)
time.sleep(2) # 报错,使用了模块别名就不能再用原模块名了
print('hello')
"""
方法五:
导入:from 模块名 import 功能 as 功能别名
使用:功能别名调用(不需要书写模块名.功能别名)
"""
from time import sleep as sl
sl(2)
sleep(2) # 报错,使用了功能别名就不能再用原功能名了
print('hello')
导入模块时会自动执行模块中全局作用域下的代码,因此模块中的测试代码需写在如下区域,才能保证在导入该模块时其中的测试代码不被执行:
if __name__ == '__main__': 测试代码
9.2 模块定位
python解析器对模块位置的搜索顺序为:
- 1 当前目录
- 2 系统目录
# python中每一个模块都有一个内置属性__file__,可以查看到导入模块的完整路径
import random
print(random.__file__) # D:\Software\Python\lib\random.py
若同一文件导入的多个模块中存在同名的功能,后导入的模块功能会覆盖其之前导入的模块功能
9.3 __all__
列表(指定要暴露给外界的模块功能列表)
9.3.1 不指定__all__
列表
- 模块文件test.py
def test1():
print('test1')
def test2():
print('test2')
- 导入模块
# 方法一
import test
test.test1() # test1
test.test2() # test2
# 方法二
from test import test1, test2
test1() # test1
test2() # test2
# 方法三
from test import *
test1() # test1
test2() # test2
9.3.2 指定__all__
列表
- 模块文件test.py
__all__ = ['test1']
def test1():
print('test1')
def test2():
print('test2')
- 导入模块
# 方法一
import test
test.test1() # test1
test.test2() # test2
# 方法二
from test import test1, test2
test1() # test1
test2() # test2
# 方法三
from test import *
test1() # test1
test2() # 报错,因为通过all列表指定了允许导入的模块功能只有test1
9.4 模块中的单下划线全局变量
若某一py模块文件内容中存在单下划线全局变量,使用from 模块名 import *
导入模块后访问该变量会报错(类中只有双下划线开头的属性才算私有属性,定义单下划线的属性不算私有属性)
- module.py模块内容
aa = 10
_bb = 20
- 导入module.py模块
from module import *
print(aa) # 10
print(_bb) # 报错
from module import _bb
print(_bb) # 20
import module
print(module._bb) # 20
9.5 模块导入注意点
若一个模块文件中有一个全局变量,则其他文件中使用import 模块名
和from 模块名 import 全局变量
导入模块意义不同
- module.py模块内容
G_NUM = 0
G_LIST = [1, 2]
9.5.1 import 模块名
import 模块名
导入时,模块名指向公共模块,使用模块名.全局变量
指向的是公共模块中的全局变量名,对其赋值相当于在公共模块中给全局变量修改值
- deal1.py内容
import module
def deal1():
module.G_NUM = 1
module.G_LIST.append(3)
def print1():
print(module.G_NUM)
print(module.G_LIST)
- deal2.py内容
import module
def print2():
print(module.G_NUM)
print(module.G_LIST)
- main.py内容
import deal1
import deal2
deal1.deal1()
deal1.print1() # 1 [1, 2, 3]
deal2.print2() # 1 [1, 2, 3]
9.5.2 from 模块名 import 全局变量
from 模块名 import 全局变量
导入时,全局变量指向公共模块中全局变量指向的内存地址,对其赋值相当于让该模块中全局变量重新指向一块新的内存地址,不影响公共模块中的值,但全局变量为可变数据类型时,使用方法修改值,因为内存地址不变,公共模块中的可变数据类型变量也指向该地址,所以公共模块中的可变数据类型变量值也会变
- deal1.py内容
from module import G_NUM, G_LIST
def deal1():
global G_NUM
G_NUM = 1
G_LIST.append(3)
def print1():
print(G_NUM)
print(G_LIST)
- deal2.py内容
from module import G_NUM, G_LIST
def print2():
print(G_NUM)
print(G_LIST)
- main.py内容
import deal1
import deal2
deal1.deal1()
deal1.print1() # 1 [1, 2, 3]
deal2.print2() # 0 [1, 2, 3]
10 包
python新建包会在包目录下自动生成一个__init__.py
文件,若my_package包下有两个py模块文件my_package1.py和my_package2.py,即可在__init__.py
文件中通过all列表写入指定要暴露给外界使用的模块
-
__init__.py
文件内容
__all__ = ['my_package1']
- 导入包
# 方法一
import my_package
my_package.my_package1.方法名() # 报错
my_package.my_package2.方法名() # 报错
# 方法二
import my_package.my_package1, my_package.my_package2
my_package.my_package1.方法名() # 正确调用
my_package.my_package2.方法名() # 正确调用
# 方法三
from my_package import my_package1, my_package2
my_package1.方法名() # 正确调用
my_package2.方法名() # 正确调用
# 方法三
from my_package import *
my_package1.方法名() # 正确调用
my_package2.方法名() # 报错,因为__init__.py文件中all列表指定了允许导入的模块只有my_package1
11 __dict__
方法
class Test:
def __init__(self):
self.name = 'zhangsan'
self.tel = 123456
test = Test()
print(test.__dict__) # {'name': 'zhangsan', 'tel': 123456}