码迷,mamicode.com
首页 > 编程语言 > 详细

Python_面向对象

时间:2019-07-20 09:52:15      阅读:71      评论:0      收藏:0      [点我收藏+]

标签:打开   魔法   代码   ide   save   das   搜索   关系   问题   

面向对象:类 class 和 对象 object:

01. 什么是对象:
对象是指现实中的物体或实例

02. 什么是面向对象:
把一切看成对象(实例),对象和对象之间用方法(行为)建立关联关系
面向过程是一件事怎么去一步一步实现, 面向对象是一件事有谁(实例)去实现

03. 什么是类:
拥有相同属性和行为的对象分为一组, 即为一个类
类是用来描述对象的工具

04. 面向对象示意:
车(类) ----->> BYD E6(京A.88888) 对象(实例)
狗(类) ----->> 小京巴(户籍号: 00001) 对象(实例)
int(类) ----->> 100(对象,实例)

05. 类的创建语法:
class 类名(继承列表):
"""类文档字符串"""
实例方法(类内的函数methd) 的定义
类变量(class variable) 定义
类方法(@classmethod)定义
静态方法(@staticmethod)定义

06. 类的作用:
可以用类创建一个或多个此类的对象(实例)
类内的变量和方法能被此类所创建的所有实例所共同拥有
说明:
类名必须是标识符(与变量名命名规则相同, 建议首字母大写)
类名实质上就是变量, 它绑定一个类实例
类的定义最后面要加两个空格以告诉解释执行器, 类的定义已经结束
示例:
class Dog:
pass
术语:
类 对象  实例
class object instance

07. 构造函数:
构造函数的调用表达式: 
  类名([创建传参列表])
[] 里的内容代表可省略
作用:
  创建这个类的实例对象, 并返回此实例对象的引用关系
示例:
class Dog: # 定义一个狗类
pass


dog1 = Dog() # 用类来创建一个对象用dog1绑定
print(id(dog1)) # 打印dog1所在的内存地址
dog2 = Dog() # 创建第二个对象 用dog2绑定
print(id(dog2))
print(dog1 is dog2) # 判断两只狗是不是同一条狗, False
实例说明:
实例有自己的作用域或名字空间, 可以为该实例添加实例变量(也叫属性)
实例可以调用类的方法
实例可以访问类中的类变量

08. 实例变量(属性 attribute):
每个实例可以有自己的变量, 称为实例变量(属性)
属性的使用语法:
实例.属性名
01. 属性的赋值规则:
(同变量规则相同)
01. 首次为属性赋值则创建此属性
02. 再次为属性赋值则改变属性的绑定关系
示例:
class Dog:
pass


dog1 = Dog()
dog1.kinds = "京巴" #为dog1绑定的实例添加kinds属性
dog1.color = "白色" # 添加属性
print(dog1.kinds, dog1.color) # 访问属性
dog1.color = ‘黄色‘ # 修改dog1.color 的绑定关系
print(dog1.color)

02. 删除属性:
del 语句
语法:
del 对象.属性名
示例:
class Student:
pass
stu = Student()
stu.name = ‘xiaozhang‘ # 创建属性
print(stu.name)
del stu.name # 删除此属性
print(stu.name) # 属性错误,因为属性已经不存在了
03. 查找顺序:
对象.属性 : 先从对象空间找,如果找不到,再从类空间找,再找不到,再从父类找....
类名.属性 : 先从本类空间找,如果找不到,再从父类找....

09. 实例方法 method:
语法:
class 类名(继承列表):
def 实例方法名(self, 参数1, 参数2, ....):
语句块
作用:
用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为
说明:
实例方法的实质是函数, 是定义在类内的函数
实例方法的第一个参数代表调用这个方法的实例, 一般命名为‘self‘
实例方法的调用语法:
实例.实例方法名(调用参数)

类名.实例方法名(实例, 调用参数)

初始化方法:
作用:
对新创建的对象添加属性等必须的资源
语法形式:
class 类名:
# [] 代表其中内容可省略
def __init__(self[, 参数列表]):
语句块

说明:
初始化方法名必须为 __init__ 不可改变
初始化方法会在构造函数创建实例后自动调用, 且将实例自身通过第一个参数 self 传入 __init__ 方法
构造函数的实参将通过 __init__ 方法的参数列表传到 __init__ 方法中
初始化方法内如果需要 return 语句返回, 则必须返回 None
示例:
# 此示例示意初始化方法的定义方法和调用过程
class Car:
"""小汽车类"""
def __init__(self, c, b, m):
self.color = c # 颜色
self.brand = b # 品牌
self.model = m # 型号
self.wheel = 4
print("__init__方法被调用")

def run(self, speed):
print(self.color, ‘的‘, self.brand,
self.model, ‘正在以‘, speed,
‘公里/小时的速度行驶‘)

def change_color(self, c):
self.color = c


a4 = Car(‘红色‘, ‘奥迪‘, ‘A4‘)
a4.run(199)
a4.change_color("白色")
a4.run(280)
x5 = Car(‘蓝色‘, ‘宝马‘, ‘x5‘)
x5.run(188)

10. 析构方法:
作用:
在对象被销毁之前被调用,主要负责清理对象所占用的资源
语法形式:
class 类名:
def __del__(self):
语句块
说明:
Python建议尽可能少的在析构方法内做事情, 因为销毁时间难以确定
示例:
class FileManage:
"""定义一个文件管理员类"""
def __init__(self, filename=‘a.txt‘):
self.file = open(filename, ‘w‘)

def writeline(self, string):
self.file.write(string)
self.file.write(‘\n‘)

def __del__(self):
"""析构方法会在对象销毁前自动调用"""
self.file.close()
print("文件已关闭")


fm = FileManage()
fm.writeline("hello world")
fm.writeline("这是中文写的第二行")
del fm
while True: # 死循环永远不退出, del不调用一直不关闭文件
pass
print("程序结束")

11. 预置的实例属性:
__dict__ 属性:
用于绑定一个存储此实例自身变量的字典

__class__ 属性:
用于绑定创建此实例的类
示例:
class Dog:
pass


dog1 = Dog()
print(dog1.__dict__) # {}
dog1.color = "白色"
print(dog1.__dict__) # {‘color‘: ‘白色‘}
print(dog1.__class__) # <class ‘__main__.Dog‘>

12. 用于类的函数:
isintance(obj, class_or_tuple)
返回这个对象obj是否是某个类的对象, 或者某些类中的一个类的对象, 如果是则返回True, 否则返回False
type(obj) 返回对象的类
对象:
属性(对象拥有的名词) 用实例变量存储
行为(对象拥有的动作) 用方法表示

13. 类变量:
类变量是类的属性, 此属性属于类, 不属于此类创建的实例
说明:
类变量,可以通过该类直接访问
类变量可以通过该类的实例直接访问
类变量可以通过此类的对象的 ‘__class__‘属性间接访问
示例1:
class Human:
total_count = 0 # 类变量, 用于记录对象的个数


print(Human.total_count)
h1 = Human()
print(h1.total_count) # 0 # 不会出错
Human.total_count = 1 # 修改类变量
h1.total_count = 2 #添加了自己的实例属性total_count
h1.__class__.total_count = 3 # 间接修改类变量

示例2:
class Human:
total_count = 0 # 类变量,用于记录对象的个数
def __init__(self, name):
self.name = name
self.__class__.total_count += 1 # 人数加1
print(name, "对象创建")

def __del__(self):
self.__class__.total_count -= 1 # 总人数减1


print("当前对象的个数是:", Human.total_count) # 0
h1 = Human("张飞")
h2 = Human("赵云")
print("当前对象的个数是:", Human.total_count) # 2
del h2 # 或 h2 = None
print("当前对象的个数是:", Human.total_count) # 1

14. 类的 __slots__ 属性:
作用:
限定一个类创建的实例只能有固定的属性(实例变量)
说明:
__slots__ 属性是一个列表, 列表的值是字符串
含有 __slots__ 属性的类所创建的对象没有__dict__字典
示例:
class Student:
# 限定此的类创建的对象只能有name和age两个属性
__slots__ = [‘name‘, ‘age‘]

def __init__(self, n, a):
self.name = n
self.age = a
s1 = Student("小张", 20)
s1.Age = 21 # 此时是错写了age为Age, 会报错
print(s1.__dict__) # 出错,因为没有__dict__字典

15. 类方法 @classmethod:
类方法是操作类的方法, 类方法属于类, 不属于该类创建的对象
说明:
类方法需要使用@classmethod装饰器定义
类方法的第一个参数用来绑定类, 约定写为cls
类和对象实例都可以调用类方法
类方法不能访问此类创建的对象的属性
示例:
class A:
v = 0 # 类变量
@classmethod
def get_v(cls): #此方法不是实例方法, 是类方法
return cls.v


a = A()
a.get_v() # 0
A.get_v() # 0
a.__dict__ # {}

16. 静态方法 @staticmethod:
静态方法是定义在类的内部的函数, 此函数作用域是类的内部
说明:
静态方法需要使用@staticmethod装饰器定义 
静态方法与普通函数的定义相同, 不需要传入self和cls
静态方法只能凭借该类和实例来调用
静态方法不能访问类变量和实例变量
示例:
  class A:
@staticmethod
def myadd(a, b):
return a + b


print(A.myadd(100, 200)) # 300
a = A()
print(a.myadd(300, 400)) # 300

17. 继承 inheritance 和 派生 derived:
什么是继承 / 派生
继承是从已有类中派生出新类, 新类具有原类的数据属性和行为,并能扩展新的能力
派生就是从一个已有的类衍生出新类, 在新的类上添加新的属性和行为
作用:
01. 用继承派生机制, 可以将一些共有功能加在基类中, 实现代码的共享
02. 在不改变超类的代码的基础上, 改变原有的功能
名词:
基类(base class) / 超类(super class) / 父类(father class)
派生类(derived class) / 子类(child class)
单继承:
语法:
class 类名(超类名):
语句块
示例:
class Human: # 人
def say(self, what): # 说话的行为
print("说: ", what)
def walk(self, distance): # 走路的行为
print("走了", distance, "公里")


h1 = Human()
h1.say("今天天气不错!")
h1.walk(5)

class Student(Human):
# def say(self, what): # 说话的行为
# print("说: ", what)

# def walk(self, distance): # 走路的行为
# print("走了", distance, "公里")

def study(self, subject):
print("正在学习", subject)


s1 = Student()
s1.say("今天晚饭吃什么?")
s1.walk(3)
s1.study("python")
继承说明:
任何类都直接或间接的继承自object类
object类是一切类的超类

18. 类内的 __base__属性:
此属性用来记录此类的基类
示例:
In [9]: class A:
...: pass
...:

In [10]: class B(A):
...: pass
...:

In [11]: B.__base__
Out[11]: __main__.A

In [12]: A.__base__
Out[12]: object

19. 覆盖: override:
什么是覆盖
覆盖是指在有继承派生关系的类中, 子类中实现了与基类(超类)同名的方法
在子类实例调用方法时, 实际调用的是子类中的覆盖版本, 这种现象叫做覆盖
示例:
class A:
def work(self):
print("A类的work方法被调用")

class B(A):
def work(self):
print("B类的work方法被调用")

b = B()
b.work() # 子类已经覆盖了父类的方法

20. super函数:
super(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例)
super() 返回绑定超类的实例, 等同于super(__class__, 实例的第一个参数), 且必须在方法内调用
作用:
  返回超类的实例, 用超类实例来调用其自身的方法
说明:
  当子类实现了__init__方法后, 父类的__init__方法将被覆盖
即不再会主动调用父类的__init__方法, 会引起父类的属性得不到初始化
此时需要显式调用父类的初始化方法
示例1:
# 此示例示意用super函数访问父类的覆盖方法
class A:
def work(self):
print("A类的work方法被调用")

class B(A):
def work(self):
print("B类的work方法被调用")

def doworks(self):
# self.work() # 调用B类的
super(B, self).work() # 调用超类的方法
super().work() # 一样会调用超类的方法
# super(__class__, self).work()

b = B()
b.work() # B类的work方法被调用
print("-----以下用b调用覆盖版本的方法----")
# A.work(b) # A类的work方法被调用
super(B, b).work()
b.doworks()

示例2:
# 此示例示意显式调用基类的初始化方法
class Human:
def __init__(self, n, a):
self.name = n
self.age = a
print("Human类的 __init__被调用")

def show_info(self):
print("姓名:", self.name)
print("年龄:", self.age)


class Student(Human):
""""""
def __init__(self, n, a, s=0):
super().__init__(n, a) # 显式调用基类的初始化方法
self.score = s
print("Student类的 __init__被调用")

def show_info(self):
super().show_info()
print("成绩:", self.score)


s1 = Student(‘coco‘, 20)
s1.show_info()

21. issubclass 函数:
issubclass(cls, class_or_tuple)
判断一个类是否是继承自其它的类, 如果此类cls是class或tuple中的一个派生子类则返回True,否则返回False
示例:
class A:
pass


class B(A):
pass


class C(B):
pass

class D(B):
pass


issubclass(B, A) # True
issubclass(C, B) # True
issubclass(D, C) # False
issubclass(C, (int, str)) False

22. 封装 enclosure:
封装是指隐藏类的实现细节.让使用者不关心这些细节;
封装的目的是让使用者通过尽可能少的使用实例变量名(属性)操作对象
私有属性和方法
python类中以双下划线(‘__‘)开头, 不以双下划线结尾的标识符为私有成员
私有成员只能被方法调用, 不能在子类或其它地方使用
私有成员有两种:
私有属性
私有方法
示例:
class A:
def __init__(self):
self.__p1 = 100 # 创建私有属性

def __m1(self):
print("A类的私有方法被调用!")

def test(self):
print(self.__p1) # 可以访问
self.__m1() # 可以访问!


a = A()
# print(a.__p1) #  出错, 不可以访问
# a.__m1() # 出错, 在类外部不能调用类的私有方法
a.test() # 用方法来操作私有属性和私有方法
a.__dict__ # {‘_A__p1‘: 100}
a._A__p1 # 100

示例2:
class Parent:
def __func(self):
print(‘in Parent func‘)

def __init__(self):
self.__func()


class Son(Parent):
def __func(self):
print(‘in Son func‘)


son1 = Son() # in Parent func

23. 多态  polymorphic:
字面意思:多种状态
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
多态说明:
多态调用方法与对象相关, 不与类相关
python的全部对象只有"运行时状态(动态)", 没有"C++/Java"里的"编译时状态(静态)"
面向对象编程语言的特征:
封装
继承
多态
面向对象的语言: C++/Java/Python/Swift/C#
示例1:
class Shape:
def draw(self):
pass

class Point(Shape):
def draw(self):
print("正在画一个点")

class Circle(Point):
def draw(self):
print("正在画一个圆")


def my_draw(s):
s.draw() # 在运行时动态决定调用的方法


s1 = Circle()
s2 = Point()
my_draw(s1) # 正在画一个圆
my_draw(s2) # 正在画一个点

示例2:
class MiniOS(object):
"""MiniOS 操作系统类 """
def __init__(self, name):
self.name = name
self.apps = [] # 安装的应用程序名称列表

def __str__(self):
return "%s 安装的软件列表为 %s" % (self.name, str(self.apps))

def install_app(self, app):
# 判断是否已经安装了软件
if app.name in self.apps:
print("已经安装了 %s,无需再次安装" % app.name)
else:
app.install()
self.apps.append(app.name)


class App(object):
def __init__(self, name, version, desc):
self.name = name
self.version = version
self.desc = desc

def __str__(self):
return "%s 的当前版本是 %s - %s" % (self.name, self.version, self.desc)

def install(self):
print("将 %s [%s] 的执行程序复制到程序目录..." % (self.name, self.version))


class PyCharm(App):
pass


class Chrome(App):
def install(self):
print("正在解压缩安装程序...")
super().install()


linux = MiniOS("Linux")
print(linux)

pycharm = PyCharm("PyCharm", "1.0", "python 开发的 IDE 环境")
chrome = Chrome("Chrome", "2.0", "谷歌浏览器")

linux.install_app(pycharm)
linux.install_app(chrome)
linux.install_app(chrome)

print(linux)

24. 多继承 multiple inheritance:
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(超类名1, 超类名2, ...):
pass
示例:
class Car:
def run(self, speed):
print("汽车以", speed, "km/h的速度行驶")


class Plane:
def fly(self, height):
print("飞机以海拔", height, "米的高度飞行")


class PlaneCar(Car, Plane):
"""飞行汽车类, 时继承 自Car和 Plane"""
pass


p1 = PlaneCar()
p1.fly(10000) # 飞机以海拔 10000 米的高度飞行
p1.run(299) # 汽车以 299 km/h的速度行驶

多继承的问题(缺陷)
标识符(名字空间)冲突的问题
要谨慎使用多继承
示例:
# 小张写了一个类A
class A:
def m(self):
print("A.m()被调用")


# 小李写了一个类B:
class B:
def m(self):
print("B.m() 被调用")


# 小王感觉小张和小李写的两个类自己可以用
class AB(A, B):
pass


ab = AB()
ab.m() # 调用A类中的m方法

25. 多继承的 MRO (Method Resolution Order)问题:
MRO 方法搜索顺序问题
python 3 广度优先: 一条路走到倒数第二级,判断,如果其他路能走到终点,则返回走另一条路.如果不能,则走到终点.
python 2 深度优先: 一条路走到底.
单独调用父类的方法示例:
print("******多继承使用类名.__init__ 发生的状态******")
class Parent(object):
def __init__(self, name):
print(‘parent的init开始被调用‘)
self.name = name
print(‘parent的init结束被调用‘)

class Son1(Parent):
def __init__(self, name, age):
print(‘Son1的init开始被调用‘)
self.age = age
Parent.__init__(self, name)
print(‘Son1的init结束被调用‘)

class Son2(Parent):
def __init__(self, name, gender):
print(‘Son2的init开始被调用‘)
self.gender = gender
Parent.__init__(self, name)
print(‘Son2的init结束被调用‘)

class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print(‘Grandson的init开始被调用‘)
Son1.__init__(self, name, age) # 单独调用父类的初始化方法
Son2.__init__(self, name, gender)
print(‘Grandson的init结束被调用‘)

gs = Grandson(‘grandson‘, 12, ‘男‘)
print(‘姓名:‘, gs.name)
print(‘年龄:‘, gs.age)
print(‘性别:‘, gs.gender)

print("******多继承使用类名.__init__ 发生的状态******\n\n")

多继承中super调用有所父类的被重写的方法示例:
print("******多继承使用super().__init__ 发生的状态******")
class Parent(object):
def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print(‘parent的init开始被调用‘)
self.name = name
print(‘parent的init结束被调用‘)

class Son1(Parent):
def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print(‘Son1的init开始被调用‘)
self.age = age
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
print(‘Son1的init结束被调用‘)

class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print(‘Son2的init开始被调用‘)
self.gender = gender
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
print(‘Son2的init结束被调用‘)

class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print(‘Grandson的init开始被调用‘)
# 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
# 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
# super(Grandson, self).__init__(name, age, gender)
super().__init__(name, age, gender)
print(‘Grandson的init结束被调用‘)

print(Grandson.__mro__)

gs = Grandson(‘grandson‘, 12, ‘男‘)
print(‘姓名:‘, gs.name)
print(‘年龄:‘, gs.age)
print(‘性别:‘, gs.gender)
print("******多继承使用super().__init__ 发生的状态******\n\n")

单继承中super示例:
print("******单继承使用super().__init__ 发生的状态******")
class Parent(object):
def __init__(self, name):
print(‘parent的init开始被调用‘)
self.name = name
print(‘parent的init结束被调用‘)

class Son1(Parent):
def __init__(self, name, age):
print(‘Son1的init开始被调用‘)
self.age = age
super().__init__(name) # 单继承不能提供全部参数
print(‘Son1的init结束被调用‘)

class Grandson(Son1):
def __init__(self, name, age, gender):
print(‘Grandson的init开始被调用‘)
super().__init__(name, age) # 单继承不能提供全部参数
print(‘Grandson的init结束被调用‘)

gs = Grandson(‘grandson‘, 12, ‘男‘)
print(‘姓名:‘, gs.name)
print(‘年龄:‘, gs.age)
#print(‘性别:‘, gs.gender)
print("******单继承使用super().__init__ 发生的状态******\n\n")

26. 函数重写 overwrite:
什么是函数重写
在自定义的类中,通过添加特定的方法,让自定义的类生成的对象(实例) 能象内建对象一样进行内建函数操作
对象转字符串函数重写
repr(obj) 返回一个能代表此对象的字符串,通常:eval(repr(obj)) == obj
str(obj) 通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)
换句话说:
repr(obj) 返回的字符串是给python用的
str(obj) 返回字符串是给人看的
示例:
class B:
def __str__(self):
return ‘str : class B‘

def __repr__(self):
return ‘repr : class B‘


b=B()
print(‘%s‘%b) # str : class B
print(‘%r‘%b) # repr : class B

27. 重写方法:
repr(obj) 函数的重写方法 def __repr__(self)
str(obj) 函数的重写方法 def __str__(self)
当对象没有 __str__方法时, 则返回__repr__(self)的值

01. 内建函数重写:
obj.__abs__() 方法对应 abs(obj)
obj.__len__() 方法对应 len(obj)
obj.__reversed__() 方法对应 reversed(obj)
obj.__round__() 方法对应 round(obj)
示例:
# 此示例示意abs(obj) 函数的重写方法 obj.__abs__() 方法的使用
class MyInteger:
def __init__(self, value):
self.data = value

def __repr__(self):
return ‘MyInteger(%d)‘ % self.data

def __abs__(self):
if self.data < 0:
return MyInteger(-self.data) # 创建一个新的以对象并返回
return MyInteger(self.data)

def __len__(self):
‘‘‘len(x)函数规定只能返回整数值,
因此此方法不能返回字符串等其它类型的值‘‘‘
return 100

I1 = MyInteger(-10)
print(I1) # <-- 此处等同于print(str(I1))
I2 = abs(I1) # I2 = MyInteger(10)
print(I2) # MyInteger(10)
print(len(I1)) # I1.__len__()

02. 数值转换函数重写:
obj.__complex__() 对应 complex(obj)
obj.__int__() 对应 int(obj)
obj.__float__() 对应 float(obj)
obj.__bool__() 对应 bool(obj)

03. 布尔测试函数的重写:
格式:
def __bool__(self):
pass
作用:
1. 用于bool(obj)函数取值
2. 用于if语句真值表达式中
3. 用于while语句真值表达式中
说明:
布测试式方法的查找顺序是 __bool__方法, 其次是__len__方法
如果没有以上方法则返回True
示例:
# 此示例示意 bool 真值测试函数的重写
class MyList:
‘‘‘定义一个容器类,用于存储任意类型的数据
其内部的存储方式用list实现
‘‘‘
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%s)‘ % self.data

def __len__(self):
print("__len__ 方法被调用!")
return len(self.data) # 返回列表的长度

def __bool__(self):
print(‘__bool__方法被调用‘)
‘‘‘此方法用于bool(obj) 函数取值,优先取此函
数的返回值,此方法用于定义bool(obj)的取值规则‘‘‘
# 规则,所有元素的和为0,则返回False否则返回True
return sum(self.data) != 0

myl = MyList([1, -2, 5, -4])
print(myl) # MyList([1, -2, 5, -4])
print(‘bool(myl) =‘, bool(myl))
if myl:
print(‘myl 的布尔值为True‘)
else:
print(‘myl 的布尔值为False‘)

04. 自定制格式化字符串__format__ :
format_dict={
‘nat‘:‘{obj.name}-{obj.addr}-{obj.type}‘,#学校名-学校地址-学校类型
‘tna‘:‘{obj.type}:{obj.name}:{obj.addr}‘,#学校类型:学校名:学校地址
‘tan‘:‘{obj.type}/{obj.addr}/{obj.name}‘,#学校类型/学校地址/学校名
}
class School:
def __init__(self,name,addr,type):
self.name=name
self.addr=addr
self.type=type

def __repr__(self):
return ‘School(%s,%s)‘ %(self.name,self.addr)
def __str__(self):
return ‘(%s,%s)‘ %(self.name,self.addr)

def __format__(self, format_spec):
# if format_spec
if not format_spec or format_spec not in format_dict:
format_spec=‘nat‘
fmt=format_dict[format_spec]
return fmt.format(obj=self)

s1=School(‘oldboy1‘,‘北京‘,‘私立‘)
print(‘from repr: ‘,repr(s1))
print(‘from str: ‘,str(s1))
print(s1)

‘‘‘
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
‘‘‘
print(format(s1,‘nat‘))
print(format(s1,‘tna‘))
print(format(s1,‘tan‘))
print(format(s1,‘asfdasdffd‘))

28. 迭代器(高级):
什么是迭代器
可以通过 next(obj) 函数取值的对象, 就是迭代器
迭代器协议:
迭代器议是指对象能够使用next函数获取下一项数据, 在没有下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器协议的实现方法:
在类内需要定义 __next__(self)方法来实现迭代器协议
语法形式:
class MyIterator:
def __next__(self):
迭代器协议
return 数据
什么是可迭代对象
是指能用iter(obj)函数返回迭代器的对象(实例)
可迭代对象的内部要定义 __iter__(self)方法来返回迭代器对象

29. 属性管理函数(反射):
getattr(obj, name[, default]) 从一个对象得到对象的属性;getattr(x, ‘y‘) 等同于x.y; 当属性不存在时,如果给出default参数,则返回default,如果没有给出default 则产生一个AttributeError错误
hasattr(obj, name) 用给定的name返回对象obj是否有此属性,此种做法可以避免在getattr(obj, name)时引发错误
setattr(obj, name, value) 给对象obj的名为name的属性设置相应的值value, set(x, ‘y‘, v) 等同于 x.y = v
delattr(obj, name) 删除对象obj中的name属性, delattr(x, ‘y‘) 等同于 del x.y
示例1:
# 类反射
class Student:
ROLE = ‘STUDENT‘
@classmethod
def check_course(cls):
print(‘查看课程了‘)

@staticmethod
def login():
print(‘登录‘)


# 反射查看属性
print(Student.ROLE) # STUDENT
print(getattr(Student,‘ROLE‘)) # STUDENT

# 反射调用方法
getattr(Student,‘check_course‘)() # 查看课程了
getattr(Student,‘login‘)() # 登录

num = input(‘>>>‘) # login
if hasattr(Student,num):
getattr(Student,num)() # 登录
示例2:
# 对象放射
class Foo:
f = ‘类的静态变量‘
def __init__(self,name,age):
self.name=name
self.age=age

def say_hi(self):
print(‘hi,%s‘%self.name)

obj=Foo(‘egon‘,73)

#检测是否含有某属性
print(hasattr(obj,‘name‘))
print(hasattr(obj,‘say_hi‘))

#获取属性
n=getattr(obj,‘name‘)
print(n)
func=getattr(obj,‘say_hi‘)
func()

print(getattr(obj,‘aaaaaaaa‘,‘不存在啊‘)) #报错

#设置属性
setattr(obj,‘sb‘,True)
setattr(obj,‘show_name‘,lambda self:self.name+‘sb‘)
print(obj.__dict__)
print(obj.show_name(obj))

#删除属性
delattr(obj,‘age‘)
delattr(obj,‘show_name‘)
delattr(obj,‘show_name111‘)#不存在,则报错

print(obj.__dict__)
示例3:
# 类反射
class Foo(object):

staticField = "old boy"

def __init__(self):
self.name = ‘wupeiqi‘

def func(self):
return ‘func‘

@staticmethod
def bar():
return ‘bar‘

print getattr(Foo, ‘staticField‘)
print getattr(Foo, ‘func‘)
print getattr(Foo, ‘bar‘)
示例4:
# 反射当前模块成员
import sys


def s1():
print ‘s1‘


def s2():
print ‘s2‘


this_module = sys.modules[__name__]

hasattr(this_module, ‘s1‘)
getattr(this_module, ‘s2‘)
示例5:
# 导入其他模块,利用反射查找该模块是否存在某个方法
def test():
print(‘from the test‘)

"""
程序目录:
module_test.py
index.py

当前文件:
index.py
"""

import module_test as obj

#obj.test()

print(hasattr(obj,‘test‘))

getattr(obj,‘test‘)()

30. 异常(高级):
with语句
语法:
with 表达式1 [as 变量名1], 表达式2 [as 变量名2], ...
作用:
用于对资源访问的场合, 确保使用过程中不管是否发生异常, 都会执行必要有"清理"操作, 并释放资源.
如:
文件打开后自动关闭, 线程中锁的自动获取和释放
说明:
with语句与try-finally相似, 并不会必变异常状态
as 子句用于绑定表达式创建的对象
示例:
# 打开文件读取文件数据(with来实现关闭文件)
def read_file():
try:
# f = open("abcd.txt")
with open(‘abcd.txt‘) as f:
while True:
s = f.readline()
if not s:
break # return
int(input("请输入任意数字打印下一行:"))
print(s)
print("文件已经关闭")

except IOError:
print("出现异常已经捕获!")
except ValueError:
print("程序已转为正常状态")


read_file()
print("程序结束")

31. 环境管理器(上下文管理器):
1. 类内有__enter__ 和 __exit__方法的类被称为环境管理器
2. 能够用with进行管理的对象必须是环境管理器
3. __enter__ 将在进入with语句时被调用, 并返回由as变量管理的对象
4. __exit__ 将在离开with语句时被调用, 且可以用参数来判断离开with语句时是否出现异常并做出相应的处理
示例:
# 本程序示意自定义的类作为环境管理器使用
class FileWriter:
def __init__(self, filename):
self.filename = filename # 此属性用于记住文件名

def writeline(self, s):
‘‘‘此方法用于向文件内写入字符串,同时自动添加换行‘‘‘
self.file.write(s)
self.file.write(‘\n‘)

def __enter__(self):
‘‘‘此方法用于实现环境管理器‘‘‘
self.file = open(self.filename, ‘w‘)
print("已进入__enter__方法,文件打开成功")
return self # 返回值向用于 with中的as 绑定

def __exit__(self, exec_type, exec_value, exec_tb):
‘‘‘
exec_type 为异常类异,没有异常发生时为None
exec_value 为错误的对象,没有异常时为None
exec_tb 为错误的traceback对象
‘‘‘
self.file.close()
print("文件", self.filename, "已经关闭")
if exec_type is None:
print("退出with时没有发生异常")
else:
print("退出with时,有异常,类型是", exec_type,
"错误是", exec_value)
print("__exit__法被调用,已离开with语句")


try:
with FileWriter(‘log.txt‘) as fw:
while True:
s = input("请输入一行: ")
if s == ‘exit‘:
break
if s == ‘error‘:
raise ValueError("故意制造的值错误")
fw.writeline(s)
except:
print("有错误发生,已转为正常")

print("这是with语句之外,也是程序的最后一条语句")

32. 运算符重载:
什么是运算符重载
让自定义的类生成的对象(实例)能够使用运算符进行操作
作用:
让实例象数学表达式一样进行运算操作
让程序简洁易读
说明:
运算符重载方法的参数已经有固定的含义, 不建议改变原有的含义

01. 算术运算符:
方法名 运算符
__add__ 加法 +
__sub__ 减法 -
__mul__ 乘法 *
__truediv__ 除法 /
__floordiv__ 地板除 //
__mod__ 取模(求余) %
__pow__ 幂 **
二元运算符重载方法格式:
def __xxx__(self, other):
....
示例:
# 此程序示意运算符重载
class MyNumber:
def __init__(self, v):
self.data = v

def __repr__(self):
return "MyNumber(%d)" % self.data

def __add__(self, other):
print("__add__方法被调用")
obj = MyNumber(self.data + other.data)
return obj

def __sub__(self, other):
return MyNumber(self.data - other.data)


n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.__add__(n2)
n3 = n1 + n2 # 等同于 n1.__add__(n2)
print(n3)
n4 = n2 - n1
print(‘n4 =‘, n4) # MyNumber(100)

02. 反向算术运算符:
方法名 运算符
__radd__ 加法 +
__rsub__ 减法 -
__rmul__ 乘法 *
__rtruediv__ 除法 /
__rfloordiv__ 地板除 //
__rmod__ 取模(求余) %
__rpow__ 幂 **
示例:
# 此示例示意返向算术运算符的重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%r)‘ % self.data

def __mul__(self, rhs):
return MyList(self.data * rhs)

def __rmul__(self, lhs):
print("__rmul__被调用, lhs=", lhs)
return MyList(self.data * lhs) # lhs (left hand side)


L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
L4 = L1 * 2 # 实现乘法运算
print(‘L4 =‘, L4) # MyList([1,2,3,1,2,3])
L5 = 2 * L1
print(L5)

03. 复合赋值运算符重载:
方法名 运算符
__iadd__ 加法 +=
__isub__ 减法 -=
__imul__ 乘法 *=
__itruediv__ 除法 /=
__ifloordiv__ 地板除 //=
__imod__ 取模(求余) %=
__ipow__ 幂 **=
示例:
# 此示例示意复合赋值算术运算符的重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%r)‘ % self.data

def __add__(self, rhs):
print("__add__方法被调用")
return MyList(self.data + rhs.data)

def __iadd__(self, rhs):
print("__iadd__方法被调用")
self.data.extend(rhs.data)
return self

L1 = MyList([1, 2, 3])
L2 = MyList(range(4, 7))
print("id(L1) =", id(L1))
L1 += L2 # 相当于 L1 = L1 + L2
print(‘L1 =‘, L1)
print("id(L1) =", id(L1))
问题:
# 解法1
a = [100]
def test(x):
x = x + x
print(x)

test(a) # [100, 100]
print(a) # [100]

# 解法2
a = [100]
def test(x):
x += x # 此处与上题不同。结果也会不同
print(x)

test(a) # [100, 100]
print(a) # [100, 100]

04. 比较的运算符的重载:
__lt__ < 小于
__le__ <= 小于等于
__gt__ > 大于
__ge__ >= 大于等于
__eq__ == 等于
__ne__ != 不等于
注:
比较运算符通常返回True或False

05. 位运算符重载:
__inert__ ~ 取反(一元运算符)
__and__ & 位与(交集)
__or__ | 位或(并集)
__xor__ ^ 位异或(对称补集)
__lshift__ << 左移
__rshift__ >> 右移

06. 反向位运算符重载:
同算术运算符相同
__rand__ & 位与(交集)
__ror__ | 位或(并集)
__rxor__ ^ 位异或(对称补集)
__rlshift__ << 左移
__rrshift__ >> 右移

07. 复合赋值运算符重载:
__iand__ &= 位与(交集)
__ior__ |= 位或(并集)
__ixor__ ^= 位异或(对称补集)
__ilshift__ <<= 左移
__irshift__ >>= 右移

08. 一元运算符的重载:
__neg__ - 负号
__pos__ + 正号
__invert__ ~ 按位取反
格式:
def __xxx__(self):
....
示例:
# 此示例示意一元运算符的重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%r)‘ % self.data

def __neg__(self):
print("__neg__方法被调用!")
L = (-x for x in self.data)
return MyList(L)


L1 = MyList([1, -2, 3, -4, 5])
print("L1 =", L1)
L2 = -L1
print("L2 =", L2)

09. in / not in 运算符的重载:
格式:
def __contains__(self, e): # e代表元素
...
说明:
not in 相当于 in取反, 所有只需要重载in 即可
# 此示例示意in / not in 运算符的重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%r)‘ % self.data

def __contains__(self, e): # e 代表测试元素
print("__contains__被调用")
for x in self.data:
if e == x: # 如果相同,则说明e在列表中
return True
return False


L1 = MyList([1, -2, 3, -4, 5])
if 2 in L1: # 需要重载 __contains__方法
print("2在L1中")
else:
print("2 不在L1中")

10.索引和切片运算符的重载:
重载方法:
__getitem__(self, i) 用于索引/切片取值
__setitem__(self, i) 用于索引/切片赋值
__delitem__(self, i) 用于del语句删除索引操作
作用:
让自定义的类型的对象能够支持索引和切片操作
示例:
# 此示例示意索引 index 和切片 slice 运算符的重载
class MyList:
def __init__(self, iterable):
self.data = [x for x in iterable]

def __repr__(self):
return ‘MyList(%r)‘ % self.data

def __getitem__(self, i):
print("__getitem__被调用", i)
return self.data[i]

def __setitem__(self, i, v):
self.data[i] = v

L1 = MyList([1, -2, 3, -4, 5])
print(L[0:2]) # [1, -2]
print(L1[2]) # 3
L1[1] = 2
print(L1) # MyList([1, 2, 3, -4, 5])

33. 组合:
给一个类的对象封装一个属性,这个属性是另一个类的对象
示例1:
class GameRole:
"""英雄人物类"""
def __init__(self, name, ad, hp):
self.name = name
self.ad = ad
self.hp = hp

def attack(self,p):
p.hp = p.hp - self.ad
print(‘%s 攻击 %s,%s 掉了%s血,还剩%s血‘ %(self.name,p.name,p.name,self.ad,p.hp))

def armament_weapon(self,wea):
self.wea = wea


class Weapon:
"""武器属性类"""
def __init__(self,name,ad):
self.name = name
self.ad = ad
def fight(self,p1,p2):
p2.hp = p2.hp - self.ad
print(‘%s 用%s打了%s,%s 掉了%s血,还剩%s血‘\
% (p1.name,self.name,p2.name,p2.name,self.ad,p2.hp))

p1 = GameRole(‘coco‘,20,500)
p2 = GameRole(‘cat‘,50,200)
axe = Weapon(‘三板斧‘,60)
broadsword = Weapon(‘屠龙宝刀‘,100)
p1.armament_weapon(axe) # 给coco装备了三板斧这个对象.
p1.wea.fight(p1,p2)

示例2:
# 组合实现与类的关联
class School:
def __init__(self, name, addr):
self.name = name
self.addr = addr


class Course:
def __init__(self, name, price, school):
self.name = name
self.price = price
self.school = school


s1 = School("coco", "成都")
s2 = School("coco", "广州")

msg = """
1 coco 成都
2 coco 广州
"""

while True:
print(msg)
menu = {
"1": s1,
"2": s2
}
choice = input("请选择学校>>>:")
school_obj = menu[choice]

name = input("课程名:")
price = input("课程费用:")

new_course = Course(name, price, school_obj)
print("课程 %s 属于 %s 学校" % (new_course.name, new_course.school.name))

34. 接口类, 抽象类:
定制一个规范, 让其子类必须按照此规范实现
示例:
from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta): # 抽象类(接口类):
@abstractmethod
def pay(self): # 制定了一个规范
pass


class Alipay(Payment):
def __init__(self,money):
self.money = money

def pay(self):
print(‘使用支付宝支付了%s‘ %self.money)


class Jdpay(Payment):
def __init__(self, money):
self.money = money

def pay(self):
print(‘使用京东支付了%s‘ % self.money)

class Wechatpay(Payment):

def __init__(self,money):
self.money = money

def pay(self):
print(‘使用微信支付了%s‘ % self.money)


def pay(obj):
obj.pay()


w1 = Wechatpay(200)
a1 = Alipay(200)
j1 = Jdpay(100)
pay(a1) # 归一化设计
pay(j1)

35. 静态属性:
将方法伪装成一个属性,代码上没有什么提升,只是更合理
语法:
@property
@属性名.setter
@属性名.deleter
示例1:
class Person:
def __init__(self,name,age):
self.name = name
if type(age) is int:
self.__age = age
else:
print( ‘你输入的年龄的类型有误,请输入数字‘)

@property
def age(self):
return self.__age

@age.setter
def age(self,a1):
‘‘‘判断,你修改的年龄必须是数字‘‘‘
if type(a1) is int:
self.__age = a1
else:
print(‘你输入的年龄的类型有误,请输入数字‘)

@age.deleter
def age(self):
del self.__age


p1 = Person(‘帅哥‘,20)
print(p1.age) # 20
print(p1.__dict__) # {‘name‘: ‘帅哥‘, ‘_Person__age‘: 20}
p1.age = 23
print(p1.age) # 23
del p1.age

示例2:
# 使用property取代getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0

# 使用装饰器对money进行装饰,那么会自动添加一个叫money的属性,当调用获取money的值时,调用装饰的方法
@property
def money(self):
return self.__money

# 使用装饰器对money进行装饰,当对money设置值时,调用装饰的方法
@money.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型数字")

a = Money()
a.money = 100
print(a.money)

36. 单例:
如果一个类 从头到尾只能有一个实例,说明从头到尾之开辟了一块儿属于对象的空间,那么这个类就是一个单例类
示例1:
class Single:
__ISINCTANCE = None
def __new__(cls, *args, **kwargs):
if not cls.__ISINCTANCE:
cls.__ISINCTANCE = object.__new__(cls)
return cls.__ISINCTANCE

def __init__(self,name,age):
# self.name = name
# self.age = age
print(self)


s1 = Single(‘coco‘,23)
s2 = Single(‘gogo‘,40)

示例2:
class MusicPlayer(object):

# 记录第一个被创建对象的引用
instance = None

# 记录是否执行过初始化动作
init_flag = False

def __new__(cls, *args, **kwargs):

# 1.判断类属性是否是空对象
if cls.instance is None:
# 2.调用父类方法,为第一个对象分配空间
cls.instance = super().__new__(cls)

# 3.返回类属性保存的对象引用
return cls.instance

def __init__(self):

# 1.判断是否执行过初始化动作
if MusicPlayer.init_flag:
return
# 2.没有执行过,再执行初始化动作
print("初始化播放器")
# 3.修改类属性标记
MusicPlayer.init_flag = True


player1 = MusicPlayer() # 初始化播放器
print(player1) # <__main__.MusicPlayer object at 0x0000000006AA28D0>
player2 = MusicPlayer()
print(player2) # <__main__.MusicPlayer object at 0x0000000006AA28D0>

37. __new__ 构造方法:
class Single:
def __new__(cls, *args, **kwargs):
# print(‘在new方法里‘)
obj = object.__new__(cls)
print(‘在new方法里‘,obj)
return obj

def __init__(self):
print(‘在init方法里‘,self)

01.开辟一个空间,属于对象的
02.把对象的空间传给self,执行init
03.将这个对象的空间返回给调用者
obj = Single()
single的new,single没有,只能调用object的new方法
new方法在实例化之后,__init__ 之前先执行new来创建一块空间

38. __call__ 方法:
__call__ 相当于 对象()
class A:
def __call__(self, *args, **kwargs):
print(‘执行call方法了‘)
def call(self):
print(‘执行call方法了‘)
class B:
def __init__(self,cls):
print(‘在实例化A之前做一些事情‘)
self.a = cls()
self.a()
print(‘在实例化A之后做一些事情‘)
a = A()
a() # 对象() == 相当于调用__call__方法
a.call()

A()() # 类名()() ,相当于先实例化得到一个对象,再对对象(),==>和上面的结果一样,相当于调用__call__方法
B(A)

39. item 系列方法:
item系列 和对象使用[]访问值有联系
示例1:
obj = {‘k‘:‘v‘}
print(obj) # 字典的对象
print(obj[‘k‘])

class B:
def __getitem__(self, item):
return getattr(self,item)

def __setitem__(self, key, value):
setattr(self,key,value*2)

def __delitem__(self, key):
delattr(self,key)


b = B()
# b.k2 = ‘v2‘
# print(b.k2)
b[‘k1‘] = ‘v1‘ # __setitem__
print(b[‘k1‘]) # __getitem__
del b[‘k1‘] # __delitem__
print(b[‘k1‘])

示例2:
class Foo:
def __init__(self,name):
self.name=name

def __getitem__(self, item):
print(self.__dict__[item])

def __setitem__(self, key, value):
self.__dict__[key]=value
def __delitem__(self, key):
print(‘del obj[key]时,我执行‘)
self.__dict__.pop(key)
def __delattr__(self, item):
print(‘del obj.key时,我执行‘)
self.__dict__.pop(item)

f1=Foo(‘sb‘)
f1[‘age‘]=18
f1[‘age1‘]=19
del f1.age1 # del obj.key时,我执行
del f1[‘age‘] # del obj[key]时,我执行
f1[‘name‘]=‘coco‘
print(f1.__dict__) # {‘name‘: ‘coco‘}

40. __eq__ 方法:
class A:
def __init__(self,name,age):
self.name = name
self.age = age
def __eq__(self, other):
if self.name == other.name and self.age == other.age:
return True


a = A(‘gogo‘,83)
aa = A(‘gogo‘,83)
aa2 = A(‘gogo‘,83)
aa3 = A(‘gogo‘,83)
aa4 = A(‘gogo‘,83)
print(a,aa)
print(aa3 == aa == aa4) # ==这个语法 是完全和__eq__

41. 面向对象设计:
def dogs(name, gender, type):
# 狗的属性
def init(name, gender, type):
dog = {
"name": name,
"gender": gender,
"type": type,
"run": run
}
return dog

# 狗的方法
def run(dog):
print("一条狗%s正在跑" % dog["name"])

return init(name, gender, type)


d1 = dogs("wangcai", "公", "中华田园犬")
d2 = dogs("xiaoqiang", "公", "哈士奇")
print("面向对象设计", d1)
d1["run"](d1)
print(d2["name"])

# 面向对象编程-->用面向对象独有的class语法实现面向对象设计
class Dog:
"""定义一个狗类"""
def __init__(self,name, gender, type):
self.name = name
self.gender = gender
self.type = type

def run(self):
print("一条狗%s正在跑" % self.name)


dog1 = Dog("wangcai", "公", "中华田园犬")
dog2 = Dog("xiaoqiang", "公", "哈士奇")

print("面向对象编程", dog1.__dict__) # __dict__ 查看属性字典
print(dog1.__dict__["type"]) # 中华田园犬

# 创建出的实例只有数据属性,函数属性实际是调的类的函数属性
dog1.run()
print(dog2.name)

# 查看类的名字
print(Dog.__name__) # Dog
# 查看文档说明
print(Dog.__doc__) # 定义一个狗类
# 查看第一个父类
print(Dog.__base__) # <class ‘object‘>
# 查看所有父类,构成元组
print(Dog.__bases__) # (<class ‘object‘>,)
# 查看类的属性,返回一个字典
print(Dog.__dict__)
# 查看类定义所在的模块
print(Dog.__module__) # __main__
# 查看实例对应的类
print(Dog.__class__) # <class ‘type‘>

42. 静态属性, 类方法, 静态方法:
@property @classmethod @staticmethod
综合示例:
class Room(object):
tag = 1

def __init__(self, wight, length):
self.wight = wight
self.length = length

@property
def car_area(self):
return self.length * self.wight + self.tag

@classmethod
def tell_info(cls):
print(cls)
print("-->", cls.tag)

@staticmethod
def run(a, b):
print("%s %s 正在跑步" % (a, b))


# 静态属性:将类的函数属性@property装饰后,是对象以数据属性的方式调用
# 只和实例对象绑定-->即可以访问实例属性也可以访问类的属性
p1 = Room(10, 20)
print("类属性", p1.tag)
print("实例对象调用静态属性", p1.car_area)

# 类方法:将类的函数属性@classmethod装饰后,不用创建实例对象,调用类的函数属性
# 只和类绑定-->可以访问类属性,不能访问实例属性
Room.tell_info()

# 静态方法:将类的函数属性@staticmethod装饰后,不创建和创建实例对象,都可以调用类的函数属性
# 即不和类绑定也不和实例对象绑定-->不能访问类属性,也不能访问实例属性,是类的工具包
Room.run("co1", "co2")
p2 = Room(20, 20)
p2.run("co3", "co4")

43. 包装标准类型:
基于标准数据类型来定制我们自己的数据类型,新增/改写方法
# 包装=继承+派生
class List(list):
# 定义一个方法取列表中间值
def show_midlle(self):
min_index = int(len(self)/2)
return self[min_index]

# 重写列表的append方法,限制只允许添加字符串
def append(self, p_object):
if type(p_object) is str:
super().append(p_object)
else:
print("类型错误,只允许添加字符串")

l1 = List("helloworld")
print(l1, type(l1))
print("列表%s的中间值是%s" %(l1, l1.show_midlle()))
l1.append("coco")
l1.append(123)
print(l1)

44. 重写反射方法:
class Foo():
x = 1
def __init__(self):
self.y = 1

def __getattr__(self, item):
print("你要找的%s属性不存在" % item)

# 重写内置删除方法,限制删除条件
def __delattr__(self, item):
print("执行了删除%s属性的操作" % item)
self.__dict__.pop(item)

# 重写内置设置方法,限制设置条件
def __setattr__(self, key, value):
print("你执行了设置%s属性值为%s的操作" %(key, value))
self.__dict__[key] = value

f1 = Foo()
f1.x = 10
f1.name = "coco" # 设置属性时会触发__setattr__

print(f1.z) # 属性不存在时,会自动触发__getattr__
del f1.y # 删除属性时,会触发__delattr__

print(f1.__dict__)

45. 授权:
授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其它的则保持原样。
授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性
实现授权的关键点就是覆盖__getattr__方法
示例1:
# 授权-->是组合的运用
class Open:
def __init__(self,filename, mode="r", encoding="utf-8"):
self.filename = filename
self.file = open(filename, mode, encoding=encoding)
self.mode = mode
self.encoding = encoding

def write(self, line):
t = time.strftime("%Y-%m-%d %X")
self.file.write("%s %s" % (t, line))

def __getattr__(self, item):
return getattr(self.file, item, "没有找到%s" % item)


f1 = Open("a.txt", "r+")
print(f1.file)
print(f1.reads)
print(f1.read)
f1.write("hello world\n")
f1.seek(0) # 移动文件指针到文件开头
print("读文件%s内容是%s" % (f1.filename, f1.read()))

示例2:
#加上b模式支持
import time
class FileHandle:
def __init__(self,filename,mode=‘r‘,encoding=‘utf-8‘):
if ‘b‘ in mode:
self.file=open(filename,mode)
else:
self.file=open(filename,mode,encoding=encoding)
self.filename=filename
self.mode=mode
self.encoding=encoding

def write(self,line):
if ‘b‘ in self.mode:
if not isinstance(line,bytes):
raise TypeError(‘must be bytes‘)
self.file.write(line)

def __getattr__(self, item):
return getattr(self.file,item)

def __str__(self):
if ‘b‘ in self.mode:
res="<_io.BufferedReader name=‘%s‘>" %self.filename
else:
res="<_io.TextIOWrapper name=‘%s‘ mode=‘%s‘ encoding=‘%s‘>" %(self.filename,self.mode,self.encoding)
return res
f1=FileHandle(‘b.txt‘,‘wb‘)
# f1.write(‘你好啊啊啊啊啊‘) #自定制的write,不用在进行encode转成二进制去写了
f1.write(‘你好啊‘.encode(‘utf-8‘))
print(f1)
f1.close()

示例3:
class List:
def __init__(self,seq):
self.seq=seq

def append(self, p_object):
‘ 派生自己的append加上类型检查,覆盖原有的append‘
if not isinstance(p_object,int):
raise TypeError(‘must be int‘)
self.seq.append(p_object)

@property
def mid(self):
‘新增自己的方法‘
index=len(self.seq)//2
return self.seq[index]

def __getattr__(self, item):
return getattr(self.seq,item)

def __str__(self):
return str(self.seq)

l=List([1,2,3])
print(l)
l.append(4)
print(l)
# l.append(‘3333333‘) #报错,必须为int类型

print(l.mid)

#基于授权,获得insert方法
l.insert(0,-123)
print(l)

46. 双下方法其它补充, 示例说明:
示例1:
# isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo():
def __getattr__(self, item):
print("执行了getattr查找%s" % item)

# 无论是否找到属性都会执行getattribute
def __getattribute__(self, item):
print("执行了getattribute查找%s" % item)
raise AttributeError("抛出异常")


f1 = Foo()
print(isinstance(f1, Foo)) # 判断对象是否是类实例化出来的 True

# issubclass(sub, super)检查sub类是否是 super 类的派生类
class Bar():
# 只针对字典方式操作触发
def __getitem__(self, item):
print("%s getitem" % item)
return self.__dict__[item]

# 只针对字典方式操作触发
def __setitem__(self, key, value):
print("%s:%s setitem" % (key, value))
self.__dict__[key] = value

# 只针对字典方式操作触发
def __delitem__(self, key):
print("%s delitem" % key)
self.__dict__.pop(key)


print(issubclass(Bar, Foo)) # 判断子类是否是由父类继承来的 True
f1.x # 执行了 __getattribute__ 查找x -->执行了 __getattr__ 查找x
f2 = Bar()
f2["name"] = "coco"
print(f2["name"])
f2["age"] = "18"
print(f2.__dict__)
del f2["age"]
print(f2.__dict__)

示例2:
# __str__ 与 __repr__ 示例
class Foo1():
# 运用在print打印时触发
def __str__(self):
return "自定义打印信息"

# 运用在解释器时触发
def __repr__(self):
return "自定义打印信息2"


l2 = Foo1()
print(l2) # 自定义打印信息
print(l2) # 自定义打印信息,__str__和 __repr__共存,print先找str没有再找repr

示例3:
# __format__ 格式化方法示例
format_dic = {
"ymd": "{0.year}{0.mon}{0.day}",
"m-d-y": "{0.mon}-{0.day}-{0.year}",
}

class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day

def __format__(self, format_spec):
print("-->", format_spec)
if not format_spec or format_spec not in format_dic:
format_spec = "ymd"
fm=format_dic[format_spec]
return fm.format(self)


d1 = Date(2019, 4, 13)
print("{0.year}{0.mon}{0.day}".format(d1)) # 2019413

print(format(d1, "ymd")) # 2019413
print(format(d1, "m-d-y")) # 4-13-2019

示例4:
class Foo2:
"文档描述"
# __slost__取代了类的__dict__使实例化除的属性没有__dict__方法
__slots__ = ["name", "age"]


class Foo3(Foo2):
def __del__(self):
print("回收实例时触发")

def __call__(self, *args, **kwargs):
print("__call__方法让实例对象可以加()执行")

f3 = Foo2
print("f3", f3.__slots__)

# __doc__记录类的文档描述信息
print(Foo2.__doc__) # 文档描述

# __doc__无法被子类继承,应为子类一旦定义就有属于自己的__doc__
print(Foo3.__doc__) # None
print(Foo3.__dict__)

# __module__查看f3来自于哪个模块
print(f3.__module__) # __main__
# __class__查看f3来自于哪个类
print(f3.__class__) # <class ‘type‘>

# __del__析构函数,回收实例时触发
f3 = Foo3()

f3() # __call__方法让实例对象可以加()执行

示例5:
# 描述符__get__ __set__ __delete__
class Foo4():
def __get__(self, instance, owner):
print("get")

def __set__(self, instance, value):
print("set")

def __delete__(self, instance):
print("delete")

class Foo5(Foo4):
name = Foo4()


f5 = Foo5()
f5.name # get
f5.name = 1 # set
del f5.name # delete

示例6:
# 上下文管理器 实现 __enter__ __exit__
class Open():
def __init__(self, name):
self.name = name

def __enter__(self):
print("执行了enter")
return self

def __exit__(self, exc_type, exc_val, exc_tb):
print("执行了exit")
print(exc_type) # 异常类型
print(exc_val) # 异常值
print(exc_tb) # 异常追踪信息


with Open("a.txt") as f:
print(f) # <__main__.Foo6 object at 0x000000000358E0F0>
print(f.name) # a.txt
print("结束") # 结束

示例7:
# __hash__
class A:
def __init__(self):
self.a = 1
self.b = 2

def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))

示例8:
# __len__
class B:
def __len__(self):
print(666)

b = B()
len(b) # len 一个对象就会触发 __len__方法。

class A:
def __init__(self):
self.a = 1
self.b = 2

def __len__(self):
return len(self.__dict__)
a = A()
print(len(a))

示例9:
# __iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
class Foo(object):
def __init__(self, sq):
self.sq = sq

def __iter__(self):
return iter(self.sq)

obj = Foo([11,22,33,44])

for i in obj:
print i

示例10:
分片操作 __getslice__ __setslice__ __delslice__
class Foo(object):
def __getslice__(self, i, j):
print(‘__getslice__‘, i, j)

def __setslice__(self, i, j, sequence):
print(‘__setslice__‘, i, j)

def __delslice__(self, i, j):
print(‘__delslice__‘, i, j)

obj = Foo()

obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__

47. 描述符的应用与优先级:
描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
数据描述符:至少实现了__get__()和__set__()
非数据描述符:没有实现:__set__()
描述符应用示例:
class Typed:
def __init__(self,key,expected_type):
self.key=key
self.expected_type=expected_type

def __get__(self, instance, owner):
print(‘get方法‘)
# print(‘instance参数【%s】‘ %instance)
# print(‘owner参数【%s】‘ %owner)
return instance.__dict__[self.key]

def __set__(self, instance, value):
print(‘set方法‘)
# print(‘instance参数【%s】‘ % instance)
# print(‘value参数【%s】‘ % value)
# print(‘====>‘,self)
if not isinstance(value,self.expected_type):
# print(‘你传入的类型不是字符串,错误‘)
# return
raise TypeError(‘%s 传入的类型不是%s‘ %(self.key,self.expected_type))
instance.__dict__[self.key]=value

def __delete__(self, instance):
print(‘delete方法‘)
# print(‘instance参数【%s】‘ % instance)
instance.__dict__.pop(self.key)


class People:
name=Typed(‘name‘,str) #t1.__set__() self.__set__()
age=Typed(‘age‘,int) #t1.__set__() self.__set__()
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary


p1=People("coco", 13, 13.3)
print(p1.__dict__)

描述符的优先级:
类属性 > 数据描述符 > 实例属性 > 非数据描述符 > 找不到的属性触发__getattr__()

01. 类属性 > 数据描述符:
#描述符Str
class Str:
def __get__(self, instance, owner):
print(‘Str调用‘)
def __set__(self, instance, value):
print(‘Str设置...‘)
def __delete__(self, instance):
print(‘Str删除...‘)

class People:
name=Str()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age


# 在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典
# 描述符被定义成了一个类属性,直接通过类名也可以调用
People.name #调用类属性name,本质就是在调用描述符Str,触发了__get__()

People.name=‘coco‘ # 赋值并没有触发__set__()
del People.name # del也没有触发__delete__()
‘‘‘
原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级
People.name # 调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__()
People.name=‘coco‘ # 直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,不会触发描述符的__set__()
del People.name #同上
‘‘‘

02. 数据描述符 > 实例属性:
#描述符Str
class Str:
def __get__(self, instance, owner):
print(‘Str调用‘)
def __set__(self, instance, value):
print(‘Str设置...‘)
def __delete__(self, instance):
print(‘Str删除...‘)

class People:
name=Str()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age


p1=People(‘angels‘,18)

# 如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性
p1.name=‘coco‘
p1.name
print(p1.__dict__) # 实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了
del p1.name

03. 实例属性 > 非数据描述符:
class Foo:
def __set__(self, instance, value):
print(‘set‘)
def __get__(self, instance, owner):
print(‘get‘)
class Room:
name=Foo()
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length


#name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级
#对实例的属性操作,触发的都是描述符的
r1=Room(‘厕所‘,1,1)
r1.name
r1.name=‘厨房‘

 

class Foo:
def __get__(self, instance, owner):
print(‘get‘)
class Room:
name=Foo()
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length


#name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级
#对实例的属性操作,触发的都是实例自己的
r1=Room(‘厕所‘,1,1)
r1.name
r1.name=‘厨房‘

04. 非数据描述符 > 找不到:
class Foo:
def func(self):
print(‘func被调用‘)

def __getattr__(self, item):
print(‘找不到就调用getattr‘,item)
f1=Foo()

f1.xxx # 找不到就调用getattr xxx

48. 类装饰器应用:
01. 类的装饰器无参数示例:
def decorate(cls):
print(‘类的装饰器开始运行啦------>‘)
return cls

@decorate #无参:People=decorate(People)
class People:
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary

p1=People(‘egon‘,18,3333.3)

02. 类的装饰器有参数示例:
示例1:
def typeassert(**kwargs):
def decorate(cls):
print(‘类的装饰器开始运行啦------>‘,kwargs)
return cls
return decorate
@typeassert(name=str,age=int,salary=float) #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
class People:
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary

p1=People(‘egon‘,18,3333.3)

示例2:
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("---装饰器中的功能---")
self.__func()
#说明:
#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
# 并且会把test这个函数名当做参数传递到__init__方法中
# 即在__init__方法中的属性__func指向了test指向的函数
#2. test指向了用Test创建出来的实例对象
#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
@Test
def test():
print("----test---")
test()
showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"

03. 描述符装饰器综合运用示例:
class Typed:
def __init__(self,key,expected_type):
self.key=key
self.expected_type=expected_type

def __get__(self, instance, owner):
print(‘get方法‘)
# print(‘instance参数【%s】‘ %instance)
# print(‘owner参数【%s】‘ %owner)
return instance.__dict__[self.key]

def __set__(self, instance, value):
print(‘set方法‘)
# print(‘instance参数【%s】‘ % instance)
# print(‘value参数【%s】‘ % value)
# print(‘====>‘,self)
if not isinstance(value,self.expected_type):
# print(‘你传入的类型不是字符串,错误‘)
# return
raise TypeError(‘%s 传入的类型不是%s‘ %(self.key,self.expected_type))
instance.__dict__[self.key]=value

def __delete__(self, instance):
print(‘delete方法‘)
# print(‘instance参数【%s】‘ % instance)
instance.__dict__.pop(self.key)


def deco(**kwargs):
def wrapper(obj):
for key,val in kwargs.items():
print("-->", key, val)
setattr(obj, key, Typed(key, val))
return obj
return wrapper


@deco(name=str, age=int)
class People:
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary


p1=People(‘coco‘,13, 13.3)
print(p1.__dict__)

49. 用描述符定制 @property, @classmethod, @staticmethod:
01. 定制@property:
class Lazyproperty:
def __init__(self,func):
print(‘==========>‘,func)
self.func=func

def __get__(self, instance, owner):
print(‘get‘)
# print(instance)
# print(owner)
if instance is None:
return self
res=self.func(instance)
setattr(instance,self.func.__name__,res)
return res


class Room:
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length

# @property #area=property(area)
@Lazyproperty #area=Lazypropery(area)
def area(self):
return self.width * self.length

@property #test=property(test)
def area1(self):
return self.width * self.length


r1 = Room("coco", 10, 10) # ==========> <function Room.area at 0x0000000006AC4C80>

print(r1.area1) # 100
#先从自己的属性字典找,没有再去类的中找,然后触发了area的__get__方法
print(r1.area) # 先打印get, 再打印100
#先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
print(r1.area) # 先打印100, 再打印get
print(Room.area) # <__main__.Lazyproperty object at 0x0000000005AE52B0>
print(Room.area1) # <property object at 0x00000000052F1458>

02. 定制@classmethod:
class ClassMethod:
def __init__(self,func):
self.func=func

def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback():
print(‘在这里可以加功能啊...‘)
return self.func(owner)
return feedback

class People:
name=‘coco‘
@ClassMethod # say_hi=ClassMethod(say_hi)
def say_hi(cls):
print(‘你好啊,world %s‘ %cls.name)

People.say_hi()

p1=People()
p1.say_hi()

class ClassMethod:
def __init__(self,func):
self.func=func

def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback(*args,**kwargs):
print(‘在这里可以加功能啊...‘)
return self.func(owner,*args,**kwargs)
return feedback

class People:
name=‘linhaifeng‘
@ClassMethod # say_hi=ClassMethod(say_hi)
def say_hi(cls,msg):
print(‘你好啊,world %s %s‘ %(cls.name,msg))

People.say_hi(‘每天都是充满希望的一天‘)

p1=People()
p1.say_hi(‘每天都是充满希望的一天‘)

03. 定制@staticmethod:
class StaticMethod:
def __init__(self,func):
self.func=func

def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback(*args,**kwargs):
print(‘在这里可以加功能啊...‘)
return self.func(*args,**kwargs)
return feedback

class People:
@StaticMethod# say_hi=StaticMethod(say_hi)
def say_hi(x,y,z):
print(‘------>‘,x,y,z)

People.say_hi(1,2,3)

p1=People()
p1.say_hi(4,5,6)

50. 自定义元类:
元类就是用来创建这些类(对象)的,元类就是类的类, type就是Python在背后用来创建所有类的元类
作用: 拦截类的创建, 修改类, 返回修改之后的类
类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程
示例1:
class MyType(type):
def __init__(self, a, b, c):
print(a) # Foo
print(b) # ()
print(c) # {‘__module__‘: ‘__main__‘, ‘__qualname__‘: ‘Foo‘, ‘__init__‘: <function Foo.__init__ at 0x00000000056307B8>}
print("元类构造执行完成") # 元类构造执行完成

def __call__(self, *args, **kwargs):
print(args, kwargs) # (‘coco‘, 18) {}
obj = object.__new__(self) # object.__new__(Foo)-->f1
self.__init__(obj, *args, **kwargs) # Foo.__init__(f1, *args, **kwargs)
return obj


class Foo(metaclass=MyType): # Foo=MyType(Foo, "Foo", (), {})-->__init__
def __init__(self, name, age):
self.name = name
self.age = age


f1 = Foo("coco", 18)
print(f1) # <__main__.Foo object at 0x00000000055BF6A0>
print(f1.__dict__) # {‘name‘: ‘coco‘, ‘age‘: 18}

示例2:
class MyType(type):
def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)

def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)

self.__init__(obj)

class Foo(object):
__metaclass__ = MyType

def __init__(self, name):
self.name = name

def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)

# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo()

示例3:
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value

# 方法1:通过‘type‘来做类对象的创建
return type(class_name, class_parents, new_attr)

# 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr)

# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = ‘bip‘

# python2的用法
# class Foo(object):
# __metaclass__ = UpperAttrMetaClass
# bar = ‘bip‘


print(hasattr(Foo, ‘bar‘))
# 输出: False
print(hasattr(Foo, ‘BAR‘))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:‘bip‘

51. 元类实现ORM:
ORM释义:
ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM
创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句
作用:
ORM就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单
示例1:
# 通过元类简单实现ORM中的insert功能
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print(‘Found mapping: %s ==> %s‘ % (k, v))
mappings[k] = v

# 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k)

# 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs[‘__mappings__‘] = mappings # 保存属性和列的映射关系
attrs[‘__table__‘] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)


class User(metaclass=ModelMetaclass):
uid = (‘uid‘, "int unsigned")
name = (‘username‘, "varchar(30)")
email = (‘email‘, "varchar(30)")
password = (‘password‘, "varchar(30)")
# 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储
# 以上User类中有
# __mappings__ = {
# "uid": (‘uid‘, "int unsigned")
# "name": (‘username‘, "varchar(30)")
# "email": (‘email‘, "varchar(30)")
# "password": (‘password‘, "varchar(30)")
# }
# __table__ = "User"
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)

def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None))

args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""‘%s‘""" % temp)
sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(args_temp))
print(‘SQL: %s‘ % sql)


u = User(uid=12345, name=‘Michael‘, email=‘test@orm.org‘, password=‘my-pwd‘)
# print(u.__dict__)
u.save()

示例2:
# 抽取到基类中
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print(‘Found mapping: %s ==> %s‘ % (k, v))
mappings[k] = v

# 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k)

# 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs[‘__mappings__‘] = mappings # 保存属性和列的映射关系
attrs[‘__table__‘] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)


class Model(object, metaclass=ModelMetaclass):
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)

def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None))

args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""‘%s‘""" % temp)
sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(args_temp))
print(‘SQL: %s‘ % sql)


class User(Model):
uid = (‘uid‘, "int unsigned")
name = (‘username‘, "varchar(30)")
email = (‘email‘, "varchar(30)")
password = (‘password‘, "varchar(30)")


u = User(uid=12345, name=‘Michael‘, email=‘test@orm.org‘, password=‘my-pwd‘)
# print(u.__dict__)
u.save()

Python_面向对象

标签:打开   魔法   代码   ide   save   das   搜索   关系   问题   

原文地址:https://www.cnblogs.com/tangxuecheng/p/11216313.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!