类是OOP和核心概念,所以我今天又看了一遍,比较之前理解又深刻了一些。
常规OOP语言的三大核心概念,“继承、封装、多态”在Python也依然适用,Python支持多继承,也就是说他能有多个超类(父类)。这个特性就意味着我们可以根据自己的需求对已有的类进行重组。从而开发出更适合项目的类。
举个简单的例子
class Calculator:
def calculate(self, expression):
self.value = eval(expression)
class Talker:
def talk(self):
print("Hi, my value is {}".format(self.value))
class TalkingCalculator(Calculator, Talker):
calculatorName = [""]
pass
TalkingCalculator类继承了Calculator和Talker类,TalkingCalculator的实例可以这两个类中的方法和属性
在使用多继承时,好处是显而易见的。当然它也会有缺点,当一个类继承了多个超类,而超类中的函数名有重复时,那么先引用的那个超类会覆盖后面超类的方法。比如说Calculator中也有talk()函数,而继承的顺序是TalkingCalculator(Calculator, Talker)。
那么,Calcularot中的talk方法会overwrite TalkingCalcularot的talk函数。也就是说Talker中的talk()函数不会被子类调用。
接口和内省
什么是接口(或者称为“协议”)?就是公开的方法和特性。
检查一个对象是否有某一个方法,hasattr(对象, '方法名或者属性名')
print(hasattr(tc, 'talk'))
print(hasattr(tc, 'asdf'))
甚至可以检查某一方法是否可以调用
print(hasattr(getattr(tc, 'talk', None), 'call'))
给对象设置属性值
设置已存在的值
setattr(tc, 'calculatorName', ["nzhCalculator"])
print("tc has {} attr".format("tc.calculatorName"))
print(tc.calculatorName)
添加一个新属性并赋值
setattr(tc, 'calculatorTimes', 0)
tc.calculatorTimes += 10
print(tc.calculatorTimes)
查看对象内存储的所有值(这里只有属性和属性的值,没有方法)
print(tc.dict) #output: {'value': 7, 'calculatorName': ['nzhCalculator'], 'calculatorTimes': 10}
可以看到父类中的value也被打印出来了,本类自己的属性,还有后来用setattr()函数添加的属性
下面是一些关于面向对象设计的思考
- 将属性一类的对象放在一起
- 方法应该只关心自己实例的特性,让其他实例管理自己的状态
- 要小心继承,尤其是多重继承,不应该出现太多层继承# 4. 简单就好,让你的方法小巧,一般来说,多数方法应该在30秒以内被读完,尽量将代码行数控制在一页或者一屏之内。
当考虑需要什么类,以及类要有哪些方法时,应该尝试下面的方法:
- 写下问题的描述,必须程序需要做什么?把所有名词、动词和形容词加下滑线。
- 对于类名,尽量使用名词
- 对于方法,尽量使用动词
- 对于特性(或者说是属性),尽量使用形容词
- 把所有特性和方法分配到类
继承
# 创建一个过滤类(可以过list中的元素), 目前的filter函数不能过滤任何list,因为bolcked列表中是空的
class Filter:
def init(self):
self.blocked = []
def filter(self, sequece):
return [x for x in sequece if x not in self.blocked]
# 下面写一个继承Filter的子类,要求是可以过滤“SPAN”字符串元素
class SPANFilter(Filter):
def init(self):
self.blocked = ['SPAN']
f = Filter()
f.init()
result = f.filter(['1,2,3'])
print(result)
s = SPANFilter()
s.init()
result = s.filter(['SPAN', 'SPAN', 'abc', '123'])
print(result)
一些关于对象和类的操作
# 查看某个类是否是另一个类的子类,issubclass(a,b),如果a是b的父类,那么返回True
r = issubclass(SPANFilter, Filter)
print(r)
y = issubclass(Filter, SPANFilter)
print(y)
# 查看某一个已知类的基类, 类名.__bases__,返回类名<class '__main__.Filter'>
superclass = SPANFilter.__bases__
print(superclass)
# 查看一个对象,是否是某一个类的实例呢?
s = SPANFilter()
print(isinstance(s, SPANFilter)) #实例和类,True
print(isinstance(s, Filter)) #实例和父类,True
# 书中提到了使用isinstance不是个好习惯,应该尽量使用多态
# 如果想知道某一个对象,到底是哪一个类生产的,可以用 对象.__class__
print(s.__class__)
#也可以使用type()函数来查看
print(type(s))
网友评论