作者: 转身丶即天涯 | 来源:发表于2017-11-27 15:12 被阅读6次

类是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()函数添加的属性

下面是一些关于面向对象设计的思考

  1. 将属性一类的对象放在一起
  2. 方法应该只关心自己实例的特性,让其他实例管理自己的状态
  3. 要小心继承,尤其是多重继承,不应该出现太多层继承# 4. 简单就好,让你的方法小巧,一般来说,多数方法应该在30秒以内被读完,尽量将代码行数控制在一页或者一屏之内。

当考虑需要什么类,以及类要有哪些方法时,应该尝试下面的方法:

  1. 写下问题的描述,必须程序需要做什么?把所有名词、动词和形容词加下滑线。
  2. 对于类名,尽量使用名词
  3. 对于方法,尽量使用动词
  4. 对于特性(或者说是属性),尽量使用形容词
  5. 把所有特性和方法分配到类

继承

# 创建一个过滤类(可以过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))

相关文章

网友评论

      本文标题:

      本文链接:https://www.haomeiwen.com/subject/hehdbxtx.html