写给编程高手的Python教程(11) 深入类和对象

学习使我快乐

鸭子类型和多态

当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

例如下面三个类(Cat、Dog、Duck)的定义中都定义了say方法

class Cat:
def say(self):
print("I am a cat!")

class Dog:
def say(self):
print("I am a dog! ")

class Duck:
def say(self):
print("I am a duck! ")

我们就可以如下面的方法,使用这三个类的定义。

animals = [Cat, Dog, Duck]
for Animal in animals:
Animal().say();
复制代码
要在Java、C++那些静态语言中,要实现上述效果,通常要使用如下的多态机制。

class Animal:
def say(self):
print("I am a animal!")

class Cat(Animal):
def say(self):
print("I am a cat!")

a_animal = Cat()
a_animal.say() # 多态

扩展:列表的extend方法传递可迭代的对象即可,它会调用getitem方法

抽象基类 (abc模块)

首先看看如下定义:

class Company:
def init(self, employee_list):
self.employee = employee_list
def len(self):
return len(self.employee)

com = Company(["bobby1", "bobby2"])

抽象基类通常有以下几个优点:

判断类型
我们要判定某个类型是否是“某个鸭子”,通常有如下两种方法。

print(hasattr(com, "len"))
print(isinstance(com, Company)) # 这种方式更好

扩展:abc模块collections.abc,和全局abc

强制某个子类必须实现某些方法
例如要实现了一个web框架, 集成Cache(redis、cache、、),需要设计一个抽象基类, 指定子类必须实现某些方法

from abc import abstractmethod
class Cache:
@abstractmethod
def get(self, key):
pass
@abstractmethod
def set(self, key, value):
pass

class RedisCache(Cache):
def get(self, key):
pass
def set(self, key, value):
pass

redis = RedisCache()
redis.set("key", "value")

扩展:isinstance和type的区别 首先看看如下定义:

class A:
pass
class B(A): #A、B可以看成是模板对象,全局只有一个
pass
b = B()

print(isinstance(b, A)) #True

python中的is是判断两个对象的地址是否一样,==是判断两个对象的内容是否一样。

print(type(b) is B) #判断地址是否相同 True
print(type(b) == B) #判断值是否相同 True
print(type(b) is A) #False

类变量和实例变量

class A:
aa = 1
def init(self, x, y):
self.x = x
self.y = y

a = A(2, 3)
A.aa = 11
a.aa = 100 # 添加新的属性到a对象上
print(a.x, a.y, a.aa) # 100
print(A.aa) # 11

print(A.x) #抛异常

b = A(4, 6)
print(b.aa)

类和实例属性的查找顺序—mro查找

多继承子类属性的查找问题,如下所述,采用广度和深度搜索都是有问题的。 父类 子类 D---->B---->A E---->C---->A

DFS: A->B->D->C->E BFS: A->B->C->D->E, 如果D和C有重名方法,C会覆盖D

菱形继承 D---->B---->A D---->C---->A

DFS: A->B->D->C, C的方法无法覆盖D的方法 BFS: A-->B->C->D

python采用一种C3的算法查找属性和函数。

class D:
  pass
class C(D):
  pass
class B(D):
  pass
class A(B, C):
  pass

print(A.mro) # 获取查询顺序

类方法、静态方法和实例方法

class Date:
#构造函数
def init(self, year, month, day):
self.year = year
self.month = month
self.day = day

def tomorrow(self):  #实例方法
    self.day += 1

@staticmethod  # 不需要cls类型的信息
def vaild_str(date_str):
    year, month, day = tuple(date_str.split("-"))
    if int(year) > 0 and int(month) > 0 and int(month) <= 12 and int(day) > 0 and int(day) <= 31:
        return True
    else:
        return False

@staticmethod
def parse_from_string(date_str): #静态方法
    year, month, day = tuple(date_str.split("-"))
    return Date(year, month, day)

@classmethod
def parse_from(cls, date_str):  #类方法
    year, month, day = tuple(date_str.split("-"))
    return cls(year, month, day)  #cls不用硬编码了

def __str__(self):
    return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)

扩展:元组是可以拆包的

date_str = "2018-12-31"
year, month, day = tuple(date_str.split("-"))

数据封装和私有属性

class User: def init(self, birthday): self.__birthday = birthday

def age(self):
return 2020 - self.__birthday.year

user = User(Date(1990, 2, 1))

print(user.__birthday) #报错,到达私有目的, 子类也没办法获取
print(user._User__birthday) #变形规则 print(user.age())

class Student(User): def init(self, birthday): self.__birthday = birthday

stu = Student(Date(1995, 4, 1))

print(stu._Student__birthday)

python对象的自省机制

自省是通过一定的机制查询到对象的内部结构
class Person: """ 人 """ name = "person"

class Student(Person): def init(self, school): self.school = school

stu = Student("慕课网") print(stu.dict) print(stu.name) # name属于Person类 print(Person.dict)

stu.dict["addr"] = "北京市" print(stu.addr) print(dir(stu)) # 列出对象所有属性

4-10 super真的是调用父类吗?
class A: def init(self): print("A")

class B(A): def init(self): print("B") super().init()

class C(A): def init(self): print("C") super().init()

class D(B, C): def init(self): print("D") super().init() b = B() print("-------------------") d = D() #按MRO算法 super调用顺序 from threading import Thread

class MyThread(Thread): def init(self, name, user): self.user = user super().init(name=name) # MRO算法

mixin继承案例
python中的with语句
try except finally
try: print("code started") raise KeyError # raise IndexError except KeyError as e: print("key error") else: print("other error") finally: print("finally...")

上下文管理器(协议)

class Sample: def enter(self): print("enter") return self

def exit(self, exc_type, exc_val, exc_tb):
print("exit")

def do_something(self):
print("doing something.....")

with Sample() as sample: sample.do_something()

from contextlib import contextmanager

@contextmanager def openFile(file): print("file open....") yield {} print("file close....")

print("-------------") with openFile("hao.txt"): print("file processing...")

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345