Python 类


# coding = utf-8

#######################################################################

# 1. 对象
# 创建对象
o1 = object()
# 1.1 多态
# 无须知道对象属于哪种对象,也能对其执行操作,且操作的行为将随对象所属的类型而异
# Python内置的+ count函数都是多态的
# 对于字符串 数 序列 不需要知道它属于哪个对象,都可以执行+方法 这就是多态
print('string1' + 'string2')
print(1+2)
print([1, 2, 3]+[4, 5])
print()

print('abc'.count('a'))
print(['a', 'b', 1, 2, 'a', 3, 'a', 'a'].count('a'))
print()

# 自定义函数 使其支持多态
def addfunc(x, y):
    return x + y
print(addfunc('ABC','Tana'))
print(addfunc(1, 3))
print(addfunc([1, 3], [5, 4, 5]))
print()



#######################################################################

# 1.2 封装
# 封装是指向外部隐藏不必要的细节

#######################################################################
# 1.3 继承
# 继承是指某个对象继承于另个一个对象,是其不用实现另一个对象的方法,就可以使用另一个对象的方法
# 子类扩展超类的定义



#######################################################################

# 2 类
# 2.1 类
# 每个对象都属于特定的类,并成为该类的实例
# 一个类的对象是另一个类的对象的子集时,前者就是后者的子类,后者是前者的超类(基类)


#######################################################################

# 2.2 自定义类
# class语句创建独立的命名空间,用于在自重定义函数
class person:
    def set_name(self, name):
        self.name = name
    def get_name(self, name):
        return self.name
    def greet(self):
        print('Hello,{}'.format(self.name))

aperson = person()
bperson = person()
aperson.set_name('Tana')
bperson.set_name('Joe')
aperson.greet()
bperson.greet()
print()


#######################################################################

#2.3 属性 函数 方法
# 方法 与对象属性相关联的函数称为方法
# 方法与函数的区别在于参数self上,方法将其第一个参数关联到它所属的实例上,因此无需提供这个参数


class AClass:
    def method(self):
        print('I have a self')

def function():
    print("I don't ...")

instance = AClass() #创建对象一定要有()
instance.method()
instance.method = function
instance.method()
print()

class Bird:
    song = 'Squaak'
    def sing(self):
        print(self.song)

bird = Bird()
bird.sing()
print()

birdsong = bird.sing
birdsong()
print()
# 变量birdsong 指向的是关联的方法bird.sing


#######################################################################

# 2.4 再谈隐藏
# 可以通过在方法或属性名称前以两个下划线打头,来使方法或属性称为私有的

class Secretive:
    def __inaccessible(self):
        print("Bet you can't see me ...")
    def accessible(self):
        print('The secret message is :')

s = Secretive()
s.accessible()

# 在类的定义中,对所有的以两个下划线打头的名称都进行转换,即在开头加上一个下划线和类名
s._Secretive__inaccessible()

# 在Python中无法禁止别人访问对象的私有方法和属性,
# 但可以通过在名称前加一个下划线加以标识,表示私有,这在Python中是约定俗成的
# 例如:from module import * 不会导入一个以下划线打头的名称



#######################################################################
# 2.5 类的命名空间
# 在class语句中定义的代码都在一个特殊的命名空间内执行的,而类的所有成员都可以访问这个命名空间
# 类定义其实就是要执行的代码段

# 定义一个计算类的实例数量
class MemberConter:
    member = 0
    def init(self):
        MemberConter.member+=1

m1 = MemberConter()
m1.init()
m2 = MemberConter()
m2.init()
print(m1.member,m2.member)
print()

m1.member = 'Tom'
print(m1.member,m2.member)
print()

# 理解:新值被写入m1的一个属性number中,这个属性遮住了类级属性,有点类似于函数中的局部变量和全局变量的关系


#######################################################################

# 2.6 指定超类(基类)
# 指定超类,可以在class语句中的类名后加上超类名,并用括号括起来

class Filter:
    def init(self):
        self.blocked = []
    def filter(self, seq):
        return [x for x in seq if x not in self.blocked]

class SPAMFilter(Filter): # SPAMFilter 是Filter的一个子类
    def init(self): # 重写超类的init方法
        self.blocked = ['SPAM']

f = Filter()
f.init()
print(f.filter([1, 2, 3, 'SPAM']))
print()

s = SPAMFilter()
s.init()
print(s.filter(['SPAM','SPAM','!','2','SPAM']))
print()

# Filter类的用途在于可用于其他类(例如将'SPAM'从序列中过滤掉的SPAMFilter类)的基类
# SPAMFilter类定义要点
# 1.以提供新定义的方式重写了Filter类中init的定义
# 2.直接从Filter类继承了方法filter的定义,因此无需重新编写其定义
# 第二点说明继承很有用,可以创建大量不同的过滤类,它们都是从Filter类派生而来的,并且都使用已编好的方法filter



#######################################################################

# 2.7 深入探讨继承
# issubclass 判断一个列是否为另一个类的子类
print(issubclass(SPAMFilter,Filter))
print()

# 如果想知道一个类的基类 可通过__base__来访问
print(SPAMFilter.__bases__)
print()

# isinstance 判断对象是否是特定类的实例 type()
s = SPAMFilter()
print(isinstance(s, SPAMFilter))
print(isinstance(s, Filter))
print()
# s 是SPAMFilter类的对象,也是Filter的对象

# 如果想知道哪个对象属于哪个类,可使用属性__class__
print(s.__class__)
print(type(s))
print()



#######################################################################

# 2.8 多个超类
# 一个类可以继承于多个超类 这被称为多重继承
class Calculator:
    def calculate(self, expression):
        self.value = eval(expression)
class Talker:
    def talk(self):
        print('Hi, The value is', self.value)

class TalkingCalculator(Calculator, Talker):
    pass

tc = TalkingCalculator()
tc.calculate('1+4+5')
tc.talk()
print()

# 如果多个超类以不同的方式实现了同一个方法(即有多个同名方法),必须在class语句中小心排列超类的顺序
# 因为位于前面的超类的方法会覆盖位于后面的超类的同名方法

# 多个超类的超类相同时,查找特定方法或属性时访问超类的顺序称为方法解析顺序



#######################################################################

# 2.9 接口和内省
# 在处理多态对象,你只关心其接口(协议)--对外暴露的方法和属性。
# 在python中,不显示的指定对象必须包含哪些方法才能用作参数。都是假定对象可以完成任务,如果不能完成,程序失败

# hasattr 判断对象是否有特定的属性或方法
print(hasattr(tc, 'talk'))
print(hasattr(tc, 'foot'))
print()

# 检查对象某个属性是否可调用callable getattr可以在获取指定属性不存在时使用默认值
print(callable(getattr(tc, 'talk', None)))
print(callable(getattr(tc, 'fnord', None)))
print()

# 设置对象的属性
setattr(tc, 'name', 'Tana')
print(tc.name)
print()

# 查看对象存储的所有值,可通过其__dict__属性
print(tc.__dict__)
print()



#######################################################################

# 2.10 抽象基类 abc模块
# 抽象基类是不能(至少不应该)实例化的类,其职责是定义子类应该实现的一组抽象方法
# 抽象类最重要的特征是不能实例化,实例化报错

from abc import ABC, abstractmethod

class Talker(ABC):
    @abstractmethod
    def talk(self):
        pass

# 形如@this的东西被称为装饰器
# @abstractmethod 来将方法标记为抽象的,在子类必须实现的方法
# 如果子类也没有实现超类的抽象方法,子类也是抽象类,不能实例化

class Knigget(Talker):
    pass

# a = Knigget() # 报错 抽象类不能实例化

class Knigget1(Talker):
    def talk(self):
        print('Knigget')

k = Knigget1()
k.talk()
print()


# 可以将某一个类注册为另一个类 register
class Herring:
    def talk(self):
        print('Herring')

h = Herring()
print(isinstance(h,Talker))

Talker.register(Herring)
print(isinstance(h, Talker))

def talk(a):
    if isinstance(a, Talker):
        a.talk()

talk(h)
print()

# 但这样做存在一个缺点 就是直接从抽象基类派生的保障没有啦
class Clam:
    pass

Talker.register(Clam)

c = Clam()
print(isinstance(c, Talker))
# c.talk() 报错

# 3. 关于面向对象设计的一些思考
# ① 将相关的东西放在一起,如果一个函数操作一个全局变量,最好将他们放到一个类的属性和方法
# ② 不要让对象之间过于亲密,方法只应该关心所属实例的属性。对于其他实例的状态,让他们自己去管理
# ③ 慎用继承,尤其多重继承
# ④ 保持简单,让方法短小紧凑

你可能感兴趣的:(Python 类)