1. 编程范式
1)面向过程
核心是过程,过程指的是解决问题的步骤。设计一套流水线,根据业务逻辑从上到下写代码,是一种机械式的思维方式。将某个功能代码封装到函数中,日后便无需重复填写,仅调用函数即可
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差
2)面向对象
核心就是对象,对象就是特征与技能的结合体。对函数进行分类和封装,让开发“更快更好更强···”
优点:可扩展性强
缺点:编程复杂度高
用户场景:用户需求经常变化,互联网应用、游戏
2. 反射
通过字符串的形式倒入模块
通过字符串的形式去模块中寻找指定函数,并执行
如果是类:只能找类里的成员
如果是反射:既可以找对象,也可以找类的成员
简单案例1:
# 根据用户输入的内容,导入模块
inp = input("请输入模块名: ")
# __import__ 用于以字符串的形式导入模块
mod = __import__(inp) # 相当于用import引入函数
# 模块中寻找函数并执行函数
inp_func = input("请输入要执行的函数: ")
# getattr用于以字符串的形式去某个模块中寻找函数
target_func = getattr(mod, inp_func, None) # 第三个参数为默认值,防止在模块中没有找到方法而报错
# 将获取到的函数名后加()表示,执行函数
result = target_func()
print(result)
案例2,根据类创建对象:
# 导入模块
m = __import__("test", fromlist=True)
# 去模块中找类
class_name = getattr(m, "Foo")
# 根据类创建对象
obj = class_name("Steve")
# 去对象中找name对应的值
val = getattr(obj, "name")
print(name)
1) getattr(input_module, input_function, None) # 获取模块中的方法
2) hasattr(input_module, input_function) # 根据字符串的形式去某各个模块中判断东西是否存在
3) setattr(input_module, "global_var", 1) # 设置模块的全局变量或函数
setattr(inout_module, "func1", lambda x : x**2)
4) delattr(input_module, "func1") # 去某个模块中删除变量或方法
5) 导入模块
mod = __import__(module_name)
mod = __import__("lib.test.com", fromlist = True)
模拟web框架的案例:
# 输入模块与方法名
target_module, target_func = input("请输入url: ").split("/")
m = __import__(target_module, fromlist=True)
if hasattr(m, target_func):
target_func = getattr(m, target_func)
r = target_func()
print(r)
else:
print("404")
2. 面向对象
类:一系列对象相似的特征与技能的结合体
类中数据属性,是所有对象共有的
类中函数属性,是绑定给对象,绑定到不同的对象是不同的绑定方法
1) 面向对象编程
a. 定义类
class student:
school = 'OT'
def learn(self):
print('Learn')
def eat(self):
print('Eat')
def sleep(self):
print('Sleep')
class 类名:
def 方法1(self, args):
pass
b. 根据类创建对象
stu1 = student()
使用对象去执行类中方法
2) self,形式参数,python内部传递。执行方法,执行过程中可以根据self去obj1中去取已经封装在里面的数据
3) 类+括号 =》自动执行类中的__init__方法
在__init__方法中执行具体封装的操作
__init__有一个特殊名字:构造方法
==》 初始化
4)
(1) __del__,解释器销毁对象时自动调用,特殊的名:析构方法
(2)__dict__,查看类的名称空间,
查: print(student.__dict__['school']); student.school
增:student.age = 19
删:del student.age
改:student.school = "TT"
5) 封装
使用场景:当同一类型的方法具有相同参数时,直接封装到对象即可
使用场景:把类当作模板,创建多个对象(对象内封装的数据可以不一样)
6) 继承与派生
派生类可以继承基类中所有的功能
派生类和基类同时存在,优先找派生类
继承的子类会先于父类被检查
多个父类会根据他们在列表中的顺序被检查
如果对下一个类存在两个合法的选择,选择第一个父类
Python类可以同时继承多个类,优先级:自己、左边、右边
新式类:广度优先
经典类:深度优先
继承父类的构造方法案例:
class Animal:
def __init__(self):
print("Animal")
class Cat(Animal):
def __init__(self):
print("Cat")
super(Cat, self).__init__()
c = Cat()
7) 多态,多种形态,Python本身支持多态
多态性:指的是可以在不考虑对象的类型的情况下,而直接使用对象
优点:增加了程序的灵活性;增加了程序的可扩展性
8) 重载,函数名相同,参数个数不同
重写,派生类中重新实现基类中的方法
9) 静态方法与静态字段,静态方法无需使用对象封装的内容
通过类访问有:静态字段、静态方法
通过对象访问:普通字段,类的方法
class Province:
# 静态字段
country = "China"
def __init__(self):
pass
def show(self):
pass
# 静态方法
@ staticmethod
def play():
print("Static method")
# 自己去访问自己的成员
print(Province.country)
# 通过类直接访问静态访问
Province.play()
10) 类方法,相当于特殊的静态方法
class Province:
def __init__(self):
pass
# 类方法,至少要有个class参数
@ classmethod
def show(cls):
print("Class method")
Province.show()
11) 特性property,将方法伪造成一种字段,无需加括号来访问方法,但也无法添加参数
class Person:
def __init__(self,name):
self.name = name
# 特性,用来获取
@property
def hello(self):
return "Hello %s!" % self.name
# 设置
@hello.setter
def hello(self, name):
self.name = name
return "Hello %s!" % self.name
p = Person("Dante")
print(p.hello)
p.hello = "Nero"
print(p.hello)
12) 成员修饰符
成员:普通字段、静态字段、普通方法、静态方法、类方法、普通特性class Account:
# 普通字段,可以从外部访问
balance = 100
# 私有字段,无法从外部直接访问
__credit = 200
def __init__(self,balance):
self.balance = balance
def withdaraw(self, amount):
self.balance -= amount
return self.balance
def save(self, amount):
self.balance += amount
return self.balance
# 私有方法
def __set_credit(self, credit):
self.__credit = credit
# 可以通过以下方式访问私有字段:对象+一个下划线+私有方法名
a1 = Account(1000)
print(a1._Account__credit)
13) 类的特殊成员call
class Test:
def __init__(self):
print("init")
def __call__(self, *args, **kwargs):
print("call")
return 1
t = Test()()
print(t)
14) 类的特殊成员setitem,getitem,delitem
class Test:
def __init__(self):
print("init")
def __call__(self, *args, **kwargs):
print("call")
return 1
# getitem方法
def __getitem__(self, item):
print(item)
# setitem方法
def __setitem__(self, key, value):
print(key, value)
# delitem方法
def __delitem__(self, key):
print(key)
t = Test()
# 对象加中括号会自动执行__getitem__()方法
t["k1"]
# 对象加中括号赋值,会自动执行__setitem__()方法
t["k2"] = "Steve"
# 在对象上用del方法加中括号,会自动执行__delitem__()方法
# del t["k1"]
# 类似切片操作时,会执行以下方法:__getslice__ / __getitem__
t[1:3]
# 类似切片赋值的操作会执行以下方法:__setslice__ / __setitem__
t[1:3] = [1,2,3]
# 类似切片删除的操作时会执行以下方法:__delslice__ / __delitem__
del t[1:3]
15) 类的特殊成员dict
class Test:
def __init__(self):
self.name = "Steve"
def __call__(self, *args, **kwargs):
print("call")
return 1
t = Test()
# 获取对象的信息
print(t.__dict__)
# 获取类的信息
print(Test.__dict__)
16) 类的特殊成员iter
class Test:
def __iter__(self):
for i in range(10):
yield i
t = Test()
# for循环会自动执行类中的__iter__(self)方法
for i in t:
print(i)
17) 抽象类
import abc
class Animal(metaclass=abc.ABCMeta): # 只能被继承,不能被实例化
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
class People(Animal):
def run(self):
print("People is running")
def eat(self):
print("People is eating")
18)封装之隐藏
class A:
__x = 1
def __init__(self,name):
self.__name = name # self._A__name = name
def __foo(self):
print('foo')
def bar(self):
self.__foo()
print('from bar')
这种变形的特点:
(1)在类内部无法直接访问
(2)在内部是可以直接使用
(3)子类无法覆盖父类__开头的属性
这种变性需要注意的问题:
(1)这种机制并没有真正意义上限制我们从外部直接访问属性,a._A__N便可访问
(2)变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
(3)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
封装的意义:
封装数据属性:明确地区分内外,控制外部对隐藏属性的操作
封装方法:隔离复杂度
19)单例模式
class MySQL:
__instance = None
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
@classmethod
def singleton(cls):
if not ls.__instance:
obj = cls()
cls.__instance = obj
return ls.__instance
def conn(self):
pass
def execute(self):
pass
obj1 = MySQL.singleton()
4. 接口,interface,在接口中写方法,但不实现具体的方法
interface IFather:
def fun1(self):pass
def fun2(self):pass
5. 异常处理
简单的异常处理案例:
inp = input("Please input an integer: ")
try:
num = int(inp)
print(num)
except Exception as e:
# 如果出错,将错误信息打印出来
print(e)
1) python中的常用异常种类
AttributeError: 试图访问一个对象没有的属性
IOError: 输入/输出异常,基本上是无法打开文件
ImportError:无法引入模块或包,基本上是路径问题或名称错误
IndentationError:语法错误(的子类),代码没有正确对齐
IndexError:下标索引超出序列边界
KeyError:试图访问字典里不存在的键
KeyboardInterrupt: Ctrl + C 被按下
NameError:使用一个还未被赋予对象的变量
SyntaxError:python代码非法,代码不能编译
TypeError: 出入对象类型与要求的不符合
UnboundLocalError: 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致以为在访问它
ValueError:传入一个调用者不期望的值,即使值的类型是正确的
Exception:所有错误类的基类
2)完整的异常代码块
try:
# 主代码块
pass
except Exception as e:
# 异常时,执行该块
pass
else:
# 主代码块执行完,执行该块
pass
finally:
# 无论异常与否,最终执行该块
pass
3)主动触发异常
try:
raise Exception("Error raised")
except Exception as e:
print(e)
4)断言
a = 1
# 条件不成立则报错,一般用来测试条件是否成立
assert a > 2
5)多分支
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
6)自定义异常类型
class MyException(BaseException):
def __init__(self, msg):
super(MyException, self).__init__()
self.msg = msg
5. 单例模式,只有一个实例,通过静态方法+静态字段实现
所有的实例中封装的内容相同时,用单例模式
简单案例:
class ConnectionPool:
__instance = None
def __init__(self):
self.ip = "127.0.0.0"
self.port = 3306
self.username = "root"
self.pwd = "root"
# 去连接,假设建立了10个连接
self.conn_list = [1,2,3,4,5,6,7,8,9,10]
@staticmethod
def getInstance(self):
if ConnectionPool.__instance:
return ConnectionPool.__instance
else:
ConnectionPool.__instance = ConnectionPool()
return ConnectionPool.__instance
def get_conection(self):
# 获取连接
import random
num = random.randint(1,11)
return num
for i in range(10):
pool = ConnectionPool.getInstance()
print("去连接池", pool, "中获取一个连接")
conn = pool.get_conection()
print("获取到的是连接: ", conn)