4.1 鸭子类型和多态

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

只要利用Python的魔法函数,就能实现某些Python数据类型的类似的方法。

class Cat(object):
def say(self):
print("i am a cat") class Dog(object):
def say(self):
print("i am a fish")
class Duck(object):
def say(self):
print("i am a duck") animal_list=[Cat,Dog,Duck]
for animal in animal_list:
animal().say() # 不同的对象实现了相同的方法,多态 i am a cat
i am a fish
i am a duck
--- a = ["lewen1", "lewen2"]
b = ["lewen2", "lewen"]
name_tuple = ["lewen3", "lewen4"]
name_set = set()
name_set.add("lewen5")
name_set.add("lewen6")
a.extend(name_set) # extend() 括号里面为可迭代对象
print(a) ['lewen1', 'lewen2', 'lewen6', 'lewen5']
--- class Company(object):
def __init__(self, employee_list):
self.employee = employee_list def __getitem__(self, item):
return self.employee[item] def __len__(self):
return len(self.employee) company = Company(["tom", "bob", "jane"])
b.extend(company) # 可以接受
print(b) ['lewen2', 'lewen', 'tom', 'bob', 'jane']

4.2 抽象基类(abc模块)

Python的变量不需指定类型,可以动态修改类型(多态)
不同的魔法函数赋予了不同的特性
不需要继承某个类,只需要实现相应的魔法函数就可以实现特定的方法
抽象基类无法被实例化
#我们去检查某个类是否有某种方法
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list

def __len__(self):
return len(self.employee)


com = Company(["bobby1","bobby2"])
print(hasattr(com, "__len__"))
True
#我们在某些情况之下希望判定某个对象是否是某个类型
from collections.abc import Sized
isinstance(com, Sized)
class A:
pass

class B(A):
pass

b = B()
print(isinstance(b, A))
True
#我们需要强制某个子类必须实现某些方法
#实现了一个web框架,集成cache(redis, cache, memorychache)
#需要设计一个抽象基类, 指定子类必须实现某些方法

#如何去模拟一个抽象基类

class CacheBase(object):
def get(self, key):
raise NotImplementedError
def set(self, key, value):
raise NotImplementedError

# class RedisCache(CacheBase):
# pass #没有实现父类对应的方法,调用时会报错
class RedisCache(CacheBase):
def set(self, key, value): #调用不会再报错
pass

redis_cache = RedisCache()
redis_cache.set("key", "value")
#上面更规范的写法
import abc
#from collections.abc import *


class CacheBase(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get(self, key):
pass

@abc.abstractmethod
def set(self, key, value):
pass
class RedisCache(CacheBase):
# def set(self, key, value):
pass
redis_cache = RedisCache() #初始化的时候就需要重载基类被装饰器修饰的方法
# redis_cache.set("key", "value")
---------------------------------------------------------------------------

TypeError Traceback (most recent call last)

<ipython-input-16-a30c00982960> in <module>
15 # def set(self, key, value):
16 pass
---> 17 redis_cache = RedisCache() #初始化的时候就需要重载基类方法
18 # redis_cache.set("key", "value")
TypeError: Can't instantiate abstract class RedisCache with abstract methods get, set
抽象基类用的比较少

mixin

e

4.3 使用isintance而不是type

class A:
pass

class B(A):
pass

b = B()

print(isinstance(b, B))
print(isinstance(b, A))

print(type(b))
print(type(b) is B) # is 去判断两个对象是不是一个对象,
print(type(b) == B) # == 是对值是否相等的判断
print(type(b) is A)
print(isinstance(b, A))
True
True
<class '__main__.B'>
True
True
False
True
尽量使用isinstance 而不是type去判断一个类型 isinstance 返回一个对象是否是类或其子类的一个实例。(Return whether an object is an instance of a class or of a subclass thereof) type 对象的类型

4.4 类变量和对象变量

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 # 将值赋给实例变量
print(a.x, a.y, a.aa) print(A.aa) b = A(3,5)
print(b.aa)
---
2 3 100
11
11

4.5 类属性和实例属性以及查找顺序

深度优先

这种深度优先就不再合理,如果C重载了D的方法,而找了B直接找D,C就没有用了

再Python3以后修改了这种搜索,为广度优先

C和D有重名的话,理应找完B再找D,而广度优先就会使C覆盖掉D

Python3 都是采用的深度优先

#C3算法

小结:py3 有共同父类(菱形)的广度优先,没有共同父类的深度优先

4.6 静态方法、类方法以及对象方法

class Date:
#构造函数
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day def tomorrow(self):
self.day += 1
#静态方法
@staticmethod
def parse_from_string(date_str):
year, month, day = tuple(date_str.split("-"))
return Date(int(year), int(month), int(day))
#硬编码的方式,只要类名修改,这反回的类名就得修改 #类方法
@classmethod
def from_string(cls, date_str):
year, month, day = tuple(date_str.split("-"))
return cls(int(year), int(month), int(day)) # 判断是否是合法的字符串,不需要反回函数
@staticmethod
def valid_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 def __str__(self):
return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)

if __name__ == "__main__":
new_day = Date(2018, 12, 31)
new_day.tomorrow()
print(new_day)
2018/12/32
#2018-12-31
date_str = "2018-12-31"
year, month, day = tuple(date_str.split("-"))
new_day = Date(int(year), int(month), int(day))
print (new_day) #用staticmethod(静态方法)完成初始化
new_day = Date.parse_from_string(date_str)
print (new_day) #用classmethod完成初始化
new_day = Date.from_string(date_str)
print(new_day)

print(Date.valid_str("2018-12-32"))
2018/12/31
2018/12/31
2018/12/31
False

4.7 数据封装和私有属性

class User:
def __init__(self, birthyear):
self.__birthyear = birthyear # 双下划线 def get_age(self):
# 返回年龄
return 2018 - self.__birthyear if __name__ == "__main__":
user = User(1990)
print(user.get_age())
# print(user.__birthyear) # 私有属性是无法通过,实例访问的
print(user._User__birthyear) # 双下划线并不是绝对安全的
"""
28
1990
"""

4.8 python对象的自省机制

#自省是通过一定的机制查询到对象的内部结构

class Person:
name = "user"

class Student(Person):
def __init__(self, scool_name):
self.scool_name = scool_name


user = Student("慕课网")
#通过__dict__查询属性
print(user.__dict__)
#---
{'scool_name': '慕课网'}
#---
user.__dict__["school_addr"] = "北京市"
print(user.school_addr)
#---
北京市
#---
print(Person.__dict__)
print(user.name)
#---
{'__module__': '__main__', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
user
#---
a = [1,2]
print(dir(a))
#---
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

4.9 super函数

class A:
def __init__(self):
print ("A")

class B(A):
def __init__(self):
print ("B")
#super(B,self).__init__() # py2中的写法
super().__init__()

b = B()
#---
B
A
既然我们重写B的构造函数, 为什么还要去调用super?
super到底执行顺序是什么样的? from threading import Thread
class MyThread(Thread):
def __init__(self, name, user):
self.user = user
super().__init__(name=name) # 重用父类的代码 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(D, self).__init__()

if __name__ == "__main__":
print(D.__mro__)
d = D()

# 有共同父类,广度优先
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D
B
C
A super() 调用的顺序是mro的顺序

4.10 django rest framework中对多继承使用的经验

mixin(混合继承)模式特点
1. Mixin类功能单一(一个mixin实现一个功能)
2. 不和基类关联,可以和任意基类组合。 基类可以不和mixin关联就能初始化成功
3. 在mixin中不要使用super这种用法

django中一个类继承多个mixin类实现多个功能

4.11 python中的with语句

try:
print ("code started")
raise KeyError
except KeyError as e:
print ("key error")
else: #没有抛异常才会运行 else
print ("other error")
finally: # 不管有没有异常,最后会执行
print ("finally") # 资源的释放 # ---
code started
key error
finally
# ---
def exe_try():
try:
print ("code started")
raise KeyError
return 1
except KeyError as e:
print ("key error")
return 2
else:
print ("other error")
return 3
finally:
print ("finally")
return 4 # 有返回值会反回,没有反回上一层的返回值
exe_try()
# ---
code started
key error
finally
4
# ---
# 上下文管理器协议, 由 __enter__,__exit__ 实现
# with 支持上下文管理器协议
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() # ---
enter
doing something
exit

4.12 contextlib实现上下文管理器

import contextlib          #上下文管理器
@contextlib.contextmanager # 用装饰器,将一个函数变成上下文管理器
def file_open(file_name):
print ("file open")
yield {} # 必须是生成器
print ("file end") with file_open("lewen.txt") as f_opened:
print ("file processing") ---
file open
file processing
file end
---

Python 本身没有接口,利用魔法函数的组合,和协议实现某些数据类型的属性

gj4 深入类和对象的更多相关文章

  1. Java编程里的类和对象

    像我们搞计算机这块的,都知道这么一件事,当前的计算机编程语言主要分为两大块,一为面向过程,二为面向对象.Java就是一门纯面向对象的语言.学习了一个月左右的Java,在下对于Java当中的类和对象有了 ...

  2. Python - 类与对象的方法

    类与对象的方法

  3. C++基础知识(5)---类和对象

    终于把C++中的基础在前面的几篇博客中总结完了,可能还有一些语法还没有总结到,没关系,以后用到了再查资料就好.类是C++中的一个非常重要的概念,这是区别你使用的C++到底是面向过程还是面向对象的一个重 ...

  4. 简述JavaScript对象、数组对象与类数组对象

    问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...

  5. 前端学PHP之面向对象系列第一篇——类和对象

    × 目录 [1]类 [2]成员属性[3]成员方法[4]对象[5]成员访问[6]this 前面的话 面向对象程序设计(OOP)是一种计算机编程架构.计算机程序由单个能够起到子程序作用的单元或对象组成,为 ...

  6. Objective-C Runtime 运行时之一:类与对象

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...

  7. [Java入门笔记] 面向对象编程基础(一):类和对象

    什么是面向对象编程? 我们先来看看几个概念: 面向过程程序设计 面向过程,是根据事情发展的步骤,按进行的顺序过程划分,面向过程其实是最为实际的一种思考方式,可以说面向过程是一种基础的方法,它考虑的是实 ...

  8. 解析Java类和对象的初始化过程

    类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...

  9. 02OC的类和对象

    这章重点介绍OC的类以及对象,由于C语言是面向过程语言,而OC只是对于C语言多了一些面向对象的特性,所以OC相对于其他面向对象语言,例如C#.Java等没有那么多的语法特性,所以差别还是比较大的. 一 ...

随机推荐

  1. FD 设置字体大小

    英文版: 依次选择菜单 Tools ->Syntax Coloring 中文版本: 如依次选择菜单 工具 ->语法配色器

  2. 求数组中的逆序对的数量----剑指offer36题

    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数: 如数组{7,5,6,4},逆序对总共有5对,{7,5},{7,6},{7, ...

  3. AKKA集群中的分布式发布订阅

    集群中的分布式发布订阅 如何向一个不知道在哪个节点上运行的actor发送消息呢? 如何向集群中的所有actor发送感兴趣的主题的消息? 这种模式提供了一个中介actor,akka.cluster.pu ...

  4. blast及其格式输出简介

    1)blast产生背景 双序列比对可以采用是基于动态规划算法的Needleman-Wunsch(NW)和Smith-Waterman algorithm(SW)算法,虽然精度高,但计算消耗大.当与数据 ...

  5. jquery 不选择第一个

    参考 https://zhidao.baidu.com/question/174343639.html th:not(':first')

  6. SQLserver和oracle中对应的数据类型

  7. ThreadPoolExecutor的execute源码分析

    上一篇文章指出,ThreadPoolExecutor执行的步骤如下: 向线程池中添加任务,当任务数量少于corePoolSize时,会自动创建thead来处理这些任务: 当添加任务数大于corePoo ...

  8. Python3 range() 函数用法

    Python3 range() 函数用法  Python3 内置函数 Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表. Pyth ...

  9. leetcode 183. Customers Who Never Order

    select Name as Customers from Customers where Id not in (select CustomerId from Orders);

  10. 不同的路径12障碍物 · Unique Paths12

    [抄题]: 有一个机器人的位于一个 m × n 个网格左上角. 机器人每一时刻只能向下或者向右移动一步.机器人试图达到网格的右下角. 问有多少条不同的路径? [思维问题]: 以为要用count来计数: ...