关于python中的一些法则
程序员都是懒惰的 都是急躁的 因此为了能达到该目标应该知道一些官方的法则
开闭原则 ——软件实现应该对扩展开放,对修改关闭
依赖倒转原则
里氏替换原则 —— 子类可以替换父类
接口隔离原则
合成聚合复用原则 —— 可以强关联的地方就不要继承
迪米特法则(最少知识原则):
高内聚 低偶合
一个函数只干一件事,一个类只做类该做的事 不要特定绑定到一起
比如下面的例子 如果计算两个数的阶乘和求和
如果定义多个函数就违背了迪米特法则
因此我们有两种解决方法:
# decorator -装饰器 f(f(x)) 高阶函数
# calc函数中的第二个参数就是另一个函数 他代表的是一个二元运算
# 这样calc函数就不需要跟某一特定的二院运算偶合在一起
# 所哟calc函数就变得更加通用 可以由传入的第二个参数来决定到底做什么
def calc(m, a): #函数传函数
total = m[0]
for index in range(1, len(m)):
total = a(total,m[index])
return total
def add(x ,y):
return x + y
def mul(x, y):
return x * y
list = [1,2,3,4]
print(calc(list,add))
calc(calc,mul)
lamubda
当然我们为了写更少的函数还可以命名 匿名函数:lamubda
print(calc(lambda x , y : x + y)
命名关键字参数
” * “后面的参数必须给参数名,前面的随便你给不给
def foo(a,b,c,*,name,age):
print(a+b)
print(name,':',age)
foo(1,2,3,'h',15)# 如果没有*这样写是对的
foo(1,2,c=3,name='h',age=18)#这样写才能判断正确
# 根据参数名来决定如何执行
def hello(**kwargs):#关键字参数 不知道参数多少个并且要用到你的参数名字——传进来的是字典
print(kwargs)
if 'name'in kwargs:
print('你好%s' % kwargs['name'])
elif 'age' in kwargs:
age = kwargs['age']
if age < 18:
print('未成年')
else:
print('提供个人信息')
def main():
hello(name='A',age=20)#多个参数组装成字典
param = {'name':'wang', 'age':13}
hello(**param)
#如果传入的是一个字典那么就需要在参数前加**
# 同理在传入元组时候是*
if __name__ == '__main__':
main()
装饰器
通过命名装饰器我们可以先执行装饰器内的内容, 然后执行装饰器外的内容
先定义一个装饰器 然后再@该装饰器
def record(fn):
def wrapper(*args, **kwargs):
print('A')
# 此行代码在执行被装饰的函数
# 在这行代码的前后我们可以附加其他代码
# 这些代码可以让我们去做一些额外的工作
val = fn(*args, **kwargs) # 为了把元组或字典拆散
return val
return wrapper
# 通过装饰器修饰函数f 让函数f在执行过程可以做更多额外操作
@record
def f(n):
if n == 0 or n == 1:
return 1
return n * f(n - 1)
@record
def e(x, y):
return x + y
if __name__ == '__main__':
print(f(5))
print(e(x=5, y=6))
#这里就会先打印A再执行e函数
在类中固定参数
如果类中你写的参数不想被添加新元素那么可以用”slots
class Ultraman(object):
# 表示类里只能有这些值
__slots__ = ('_name', '_hp', '_mp')
继承
在创建类中 class XXX(object) 括号中的位置表示继承,其意义在于创建该类能够拥有括号中类的属性 一般没有可继承的类都用object表示
就好比儿子继承父亲的属性特征,因此也叫父类,子类 在运用继承关系的时候要用到函数
““superr”
用法:super().init(要继承的属性)
同时在python中没有从语言层面支持抽象概念
我们可以通过abc模块来制造抽象效果
在定义类的时候通过指定metaclass=ABCMeta 可以将类声明为抽象类
抽象类是不能创建对象的 抽象类存在的意义是专门拿给其他类继承
abc模块中还有个包装器 abstractmethod
通过包装器可以将方法包装为抽象方法 必须要求子类进行重写
isinstance 判断对象里有什么
isinstance(列表,里面你想要的参数)
在定义类的时候通过指定metaclass=ABCMeta 可以将类声明为抽象类
下面来进行讲述:
from abc import ABCMeta, abstractclassmethod
class Employee(object, metaclass=ABCMeta):
# 在self后加入._表示受保护的程序 虽然是可以修改因为python设计的就是都可以修改 但这作为提醒不能修改
# self表示类取值本身
def __init__(self, name):
"""
初始化方法
:param name:姓名
"""
self._name = name
@property # 属性访问器 只能读 不能改写
def name(self):
return self._name
@abstractclassmethod # 表示子类必须加上这个方法
def get_salary(self):
pass
class Manager(Employee):
def get_salary(self):
return 15000
class Programmer(Employee):
def __init__(self, name):
super().__init__(name)
self._working_hour = 0
@property
def working_hour(self):
return self._working_hour
# 非必要属性给setter 表示随时可以修改的值
@working_hour.setter
def working_hour(self, working_hour):
self._working_hour = working_hour if working_hour > 0 else 0
def get_salary(self):
return 150 * self._working_hour
class Salersman(Employee):
def __init__(self, name):
super().__init__(name)
self._sales = 0
@property
def sales(self):
return self._sales
@sales.setter
def sales(self, sales):
self._sales = sales if sales > 0 else 0
def get_salary(self):
return 1200 + self._sales * 0.05
def main():
emps = [
Manager('A'), Programmer('123'), Salersman('大大')
]
for emp in emps:
# 判断是不是什么对象
if isinstance(emp, Programmer):
emp.working_hour = int(input('输入%s工作时间:' % emp.name))
elif isinstance(emp, Salersman):
emp.sales = int(input('%s销售额是:' % emp.name))
# 同样是接受get_salary这个消息 但是不同员工都是不同方法
# 因为三个字类都重写了get_salary方法 所以这个方法会表现多态行为
print('%s本月工资:¥%.2f元' %
(emp.name, emp.get_salary()))