python-面向对象编程

第八章 面向对象

用代码实现对列和栈

Queue队列:先进先出 FIFO(First In First Out)

Stack栈 : 后进先出 LIFO(Last In First Out)

  • 方式一

class Foo:
   def __init__(self):
       self.l = []
   
   def put(self,item):
       self.l.apend(item)
       
class Queue(Foo):
   def get(self):
       return self.l.pop(0)
   
class Stack(Foo):
   def get(self):
       return self.l.pop()
   
obj = Queue()
obj.put(1)
obj.put(2)
print(obj.get())
print(obj.get()) # 先进先出

s1 = Stack()
s1.put(1)
s1.put(2)
print(s1.get()) # 先进后出
print(s1.get())
  • 方式二

class Foo:
   def __init__(self):
       self.l = []
   def put(self,item):
       self.l.append(item)
       
   def get(self):
       return self.l.pop() if self.index else self.l.pop(0)
   
   
class Queue(Foo):
   def __init(self):
       self.index = 0
       Foo.__init__(self)
       
       
class Stack(Foo):
   def __init(self):
       self.index = 1
       Foo.__init__(self)    

自定义Pickle,借助pickle模块来完成简化的dump和load

import pickle  # 导入pickle模块
class My_pickle:   # 定义pickle类
   def __init__(self, path):
       self.file = path

   def dump(self, obj):
       with open(self.file, 'ab') as f:  # 以ab模式写入
           pickle.dump(obj, f)

   def load(self):
       l = []
       with open(self.file,'rb') as f:  # rb模式读出
           while True:
               try:
                   l.append(pickle.load(f))
               except EOFError:
                   break
       return l

pic = My_pickle('pickle_file')
pic.dump(obj)
for i in pic.load():
   print(i)
   
   
方式二
import pickle
class My_pickle:
   def __init__(self,path):
       self.file = path
       
   def dump(self,obj):
       with open(self.file,'ab') as f:
           pickle.dump(obj,f)

   def load(self):
       with open(self.file,'rb') as f:
           while 1:
               try:
                   yield pickle load(f)
               except EOFError:
                   break
pic = My_pickle('pickle_file')
pic.dump(obj)

for i in pic.load():
   print(i)

自定义json

import json


class My_json:   # 定义json类
   def __init__(self, path):  # 初始化方法
       self.file = path

   def dump(self, obj):  # 方法
       with open(self.file, 'a', encoding='utf-8') as f:
           ret = json.dumps(obj)
           f.write(ret + '\n')

   def load(self):
       with open(self.file, 'r', encoding='utf-8') as f:
           while 1:
               try:
                   for i in f:
                       yield json.loads(i.strip())
               except EOFError:
                   break


obj = My_json('json_file')  # 传入文件路径
obj.dump([1, 2, 3])
for i in obj.load():
   print(i)

 

 

 

 

 

 

1. 面向对象基本格式

# ###### 定义类 ###### 
类的作用:1.实例化对象  2.操作静态变量

什么时候是对类中的变量赋值或使用:
类名.名字 = '值'
print(类名.名字) # print(对象名.名字) # 对象本身没有这个名字

什么时候是对对象中的变量赋值
对象名.名字 的时候和 self.名字




先来定义模子,用来描述一类事物
具有相同的属性和相似功能的一类
class 类名:
   def 方法名(self,name):
       print(name)
       return 123
   def 方法名(self,name):
       print(name)
       return 123
   def 方法名(self,name):
       print(name)
       return 123
# ###### 调用类中的方法 ######
# 1.创建该类的对象
obj = 类名()
# 2.通过对象调用方法
result = obj.方法名('alex')
print(result)

# 类和对象之间的关系?
   # 类 是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值
   # 对象 是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性赋上具体的值
   
# 写代码的时候,是先有的父类还是先有的子类?
# 在加载代码的过程中 需要先加载父类 所以父类写在前面
# 从思考的角度出发 总是先把子类都写完 发现重复的代码 再把重复的代码放到父类中

应用场景:复杂的 ,拥有开放式结局的程序, 比较适合使用面向对象开发,比如开发游戏(遇到很多函数,需要给函数进行归类和划分。 【封装】)

面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化。

什么时候用面向对象

  • 函数(业务功能)比较多,可以使用面向对象来进行归类。

  • 想要做数据封装(创建字典存储数据时,面向对象)。

  • 游戏示例:创建一些角色并且根据角色需要再创建人物。

 

2. 面向对象的初识

class Person:       # 类名
   def __init__(self,name,sex,job,hp,weapon,ad):
       # 必须叫__init__这个名字,不能改变的,所有的在一个具体的人物出现之后拥有的属性
       self.name = name
       self.sex = sex
       self.job = job
       self.level = 0
       self.hp = hp
       self.weapon = weapon
       self.ad = ad
#
alex = Person('alex','不详','搓澡工',260,'搓澡巾',1)     # alex 就是对象 alex = Person()的过程 是通过类获取一个对象的过程 - 实例化
print(alex,alex.__dict__)
wusir = Person('wusir','male','法师',500,'打狗棍',1000)
# print(wusir,wusir.__dict__)
print(alex.name)   # print(alex.__dict__['name']) 属性的查看
alex.name = 'alexsb'    # 属性的修改
print(alex.name)
alex.money = 1000000     # 属性的增加
print(alex.money)
print(alex.__dict__)
del alex.money           # 属性的删除
print(alex.__dict__)
类名() # 会自动调用类中的__init__方法


   
# Person是一个类 :alex wusir都是这个类的对象
# 类有一个空间,存储的是定义在class中的所有名字
# 每一个对象又拥有自己的空间,通过对象名.__dict__就可以查看这个对象的属性和值


# 实例化所经历的步骤
   # 1.类名() 之后的第一个事儿 :开辟一块儿内存空间
   # 2.调用 __init__ 把空间的内存地址作为self参数传递到函数内部
   # 3.所有的这一个对象需要使用的属性都需要和self关联起来
   # 4.执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方)

2.1内存

d = {'k':'v'}
print(d,id(d))
d['k'] = 'vvvv'
print(d,id(d))

# 修改列表\字典中的某个值,或者是对象的某一个属性 都不会影响这个对象\字典\列表所在的内存空间

3. 对象的作用

存储一些值,以后方便自己使用

class File:
   def read(self):
       with open(self.xxxxx, mode='r', encoding='utf-8') as f:
           data = f.read()
       return data

   def write(self, content):
       with open(self.xxxxx, mode='a', encoding='utf-8') as f:
           f.write(content)

# # 实例化了一个File类的对象
obj1 = File()
# # 在对象中写了一个xxxxx = 'test.log'
obj1.xxxxx = "test.log"
# # 通过对象调用类中的read方法,read方法中的self就是obj。
# # obj1.read()
obj1.write('alex')


# 实例化了一个File类的对象
obj2 = File()
# 在对象中写了一个xxxxx = 'test.log'
obj2.xxxxx = "info.txt"
# 通过对象调用类中的read方法,read方法中的self就是obj。
# obj2.read()
obj2.write('alex')

总结

"""
如果写代码时,函数比较多比较乱。
1. 可以将函数归类并放到同一个类中。
2. 函数如果有一个反复使用的公共值,则可以放到对象中。
"""

class File:
   def __init__(self,path):
       self.file_path = path
       
   def read(self):
       print(self.file_path)
   
   def write(self,content):
       print(self.file_path)
   
   def delete(self):
       print(self.file_path)
   
   def update(self):
       print(self.file_path)
   
p1 = File('log.txt')
p1.read()

p2 = File('xxxxxx.txt')
p2.read()
# 1. 循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。
# ########## 以前的写法
USER_LIST = []
while True:
   user = input('请输入用户名:')
   pwd = input('请输入密码:')
   email = input('请输入邮箱:')
   temp = {'username':user,'password':pwd,'email':email}
   USER_LIST.append(temp)
   for item in USER_LIST:
       temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],)
       print(temp)
   
# ########## 面向对象写法

class Person:
   def __init__(self,user,pwd,email):
       self.username = user
       self.password = pwd
       self.email = email

USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
   user = input('请输入用户名:')
   pwd = input('请输入密码:')
   email = input('请输入邮箱:')
   p = Person(user,pwd,email)
   USER_LIST.append(p)

for item in USER_LIST:
   temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
   print(temp)

4 命名空间

  • python中一切皆对象,对象的类型就是类。

  • 所有的对象都有一个都有一个类型,class A实例化出来的对象的类型就是A类。

  • 类型:int、float、str、list、tuple、set、--类(类置的数据类型,内置的类)

  • 在类的命名空间:静态变量 绑定方法

  • 能定义到类中的

    • 静态变量 是个所有对象共享的变量 由对象\类调用,但是不能重新赋值

    • 绑定方法 是个自带self参数的函数 由对象调用

    • 类方法 是个自带cls参数的函数 由对象\类调用

    • 静态方法 是个啥也不带的函数 由对象\类调用

    • property属性 是个伪装成属性的方法 由对象调用 但是不加括号,类名调用就是一个property对象地址

      (<property object at 0x0000021011049318>)

 # 类的成员和命名空间
class A:
   Country = '中国'  # 静态变量/静态属性 存储在类的命名空间里的
   def __init__(self,name,age): # 绑定方法 存储在类的命名空间里
       self.name = name  # 把变量存储在对象的地址中
       self.age = age
   def func1(self):
       print(self)
   def func2(self):pass
   def func3(self):pass
   def func4(self):pass
   def func5(self):pass
   
   
a = A('alex',83)
print(a.name)
print(a.Country)

print(A.Country)
a.func1() # == A.func1(a)

# 绑定方法
# 对象.绑定方法() # ==> 类名.绑定方法(对象)



class A:
   Country = '中国'     # 静态变量/静态属性 存储在类的命名空间里的
   def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的
       self.name = name
       self.age = age
   def func1(self):
       print(self)
   def func2(self):pass
   def func3(self):pass
   def func4(self):pass
   def func5(self):pass

a = A('alex',83,'印度')
b = A('wusir',74,'泰国人')
A.Country = '日本人'
print(a.Country)
print(b.Country)
print(A.Country)

# 类中的变量是静态变量
# 对象中的变量只属于对象本身,每个对象有属于自己的空间来存储对象的变量
# 当使用对象名去调用某一个属性的时候会优先在自己的空间中寻找,找不到再去对应的类中寻找
# 如果自己没有就引用类的,如果类也没有就报错
# 对于类来说,类中的变量所有的对象都是可以读取的,并且读取的是同一份变量

# 实现一个类,能够自动统计这个类实例化了多少个对象
# class A:pass
# A.Country = 123   # 属性的增加
# print(A.Country) # 查看或者引用



class A:
   count = 0
   def __init__(self):
       A.count += 1
       
a1 = A()
print(a1.count)
a2 = A()
print(a1.count)

# 类中的静态变量的用处
# 如果一个变量 是所有的对象共享的值,那么这个变量应该被定义成静态变量
# 所有和静态变量相关的增删改查都应该使用类名来处理
# 而不应该使用对象名直接修改静态变量

# 调用的习惯
       # 类名.静态变量
       # 对象.静态变量 (对象调用静态变量的时候,不能对变量进行赋值操作 对象.静态变量 = 1UI27)

5 组合

# 一个类的对象是另外一个类的对象的属性

# 学生类
   # 姓名 性别 年龄 学号 班级 手机号
# 班级信息
   # 班级名字
   # 开班时间
   # 当前讲师
   
class Student:
   def __init__(self,name,sex,age,number,clas,phone):
       self.name = name
       self.sex = sex
       self.age = age
       self.number = number
       self.clas = clas
       self.phone = phone
class Clas:
   def __init__(self,cname,begint,teacher):
       self.cname = cname
       self.begint = begint # 开班日期
       self.teacher = teacher

# 查看的是大壮的班级的开班日期是多少
# 查看的是雪飞的班级的开班日期是多少
py22 = Clas('python全栈22期','2019-4-26','小白')
py23 = Clas('python全栈23期','2019-5-28','宝元')

大壮 = Student('大壮','male',18,27,py23,13812012012)
雪飞 = Student('雪飞','male',18,17,py22,13812012013)

print(大壮.clas,py23) # 类对象的内存地址相同
print(py23.begint)
print(大壮.clas.begint)
print(雪飞.clas.begint)
# 练习 :
# 对象变成了一个属性
# 班级类
   # 包含一个属性 - 课程
# 课程
   # 课程名称
   # 周期
   # 价格

# 创建两个班级 linux57
# 创建两个班级 python22
# 查看linux57期的班级所学课程的价格
# 查看python22期的班级所学课程的周期


class Clas:
   def __init__(self,cname,begint,teacher):
       self.cname = cname
       self.begint = begint
       self.teacher = teacher
class Course:
   def __init__(self,name,period,price):
       self.name = name
       self.period = period
       self.price = price
py22 = Clas('python全栈22期','2019-4-26','小白')
linux57 = Clas('linux运维57期','2019-3-27','李导')
linux58 = Clas('linux运维58期','2019-6-27','李导')
python = Course('python','6 months',21800)
linux = Course('linux','5 months',19800)

py22.course = python
linux57.course = linux
linux58.course = linux

print(py22.course.period)
print(linux57.course.price)

linux.price = 21800
print(linux57.course.price)
print(linux58.course.price)

class Clas:
   def __init__(self,cname,begint,teacher,cprice,cperiod):
       self.cname = cname
       self.begint = begint
       self.teacher = teacher
       self.cprice = cprice    # 课程价格
       self.cperiod = cperiod  # 课程周期
linux57 = Clas('linux运维57期','2019-3-27','李导',19800,'5 months')
linux58 = Clas('linux运维58期','2019-3-27','李导',19800,'5 months')
linux59 = Clas('linux运维59期','2019-3-27','李导',19800,'5 months')
linux60 = Clas('linux运维60期','2019-3-27','李导',19800,'5 months')
linux61 = Clas('linux运维51期','2019-3-27','李导',19800,'5 months')
linux57.cprice = 21800 # 每个对象的地址不同,所以改变的是自己对应的值
linux58.cprice = 21800

6 继承【有一些属性和内置函数在此处】

# 继承 -- 需要解决代码的重复
# 继承语法
# class A:
#     pass
# class B(A):
#     pass
# B继承A,A是父类,B是子类
# A是父类 基类 超类
# B是子类 派生类
# 父类(基类)
class Base:
   def f1(self):
       print('f1')
# 子类(派生类)
class Foo(Base):
   def f2(self):
       print('f2')

# 创建了一个字类的对象
obj = Foo()
# 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。
obj.f2()
obj.f1()

# 创建了一个父类的对象
obj = Base()
obj.f1()
# 子类可以使用父类中的 : 方法 静态变量
class Animal:
   def __init__(self, name):
       self.name = name

   def eat(self):
       print('%s is eating' % self.name)

   def drink(self):
       print('%s is drinking' % self.name)

   def sleep(self):
       print('%s is sleeping' % self.name)


class Cat(Animal):
   def climb_tree(self):
       print('%s is climbing' % self.name)


class Dog(Animal):
   def house_keep(self):
       print('%s house keeping' % self.name)


小白 = Cat('小白')
#     先开辟空间,空间里有一个类指针-->指向Cat
#     调用init,对象在自己的空间中找init没找到,到Cat类中找init也没找到,
#     找父类Animal中的init
小白.eat()
小白.climb_tree()
小黑 = Dog('小黑')
小黑.eat()
小黑.house_keep()
# 当子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了
class Animal:
   def __init__(self, name):
       self.name = name

   def eat(self):**
       print('%s is eating' % self.name)

   def drink(self):
       print('%s is drinking' % self.name)

   def sleep(self):
       print('%s is sleeping' % self.name)


class Cat(Animal):
   def eat(self):**
       print('%s吃猫粮' % self.name)

   def climb_tree(self):
       print('%s is climbing' % self.name)


小白 = Cat('小白')
小白.eat()
# 子类想要调用父类的方法的同时还想执行自己的同名方法
# 猫和狗在调用eat的时候既调用自己的也调用父类的,
# 在子类的方法中调用父类的方法 :父类名.方法名(self)
class Animal:
   def __init__(self, name, food):
       self.name = name
       self.food = food
       self.blood = 100
       self.waise = 100

   def eat(self):
       print('%s is eating %s' % (self.name, self.food))

   def drink(self):
       print('%s is drinking' % self.name)

   def sleep(self):
       print('%s is sleeping' % self.name)


class Cat(Animal):
   def eat(self):
       self.blood += 100
       Animal.eat(self)

   def climb_tree(self):
       print('%s is climbing' % self.name)
       self.drink()


class Dog(Animal):
   def eat(self):
       self.waise += 100
       Animal.eat(self)

   def house_keep(self):
       print('%s is keeping the house' % self.name)


小白 = Cat('小白', '猫粮')
小黑 = Dog('小黑', '狗粮')
小白.eat()
小黑.eat()
print(小白.__dict__)
print(小黑.__dict__)


# 继承语法 class 子类名(父类名):pass
# 父类和子类方法的选择:
# 子类的对象,如果去调用方法
# 永远优先调用自己的
# 如果自己有 用自己的
# 自己没有 用父类的
# 如果自己有 还想用父类的 : 直接在子类方法中调父类的方法 父类名.方法名(self)
# 思考一:下面代码的输出?
class Foo:
   def __init__(self):
       self.func()   # 在每一个self调用func的时候,我们不看这句话是在哪里执行,只看self是谁

   def func(self):
       print('in foo')

class Son(Foo):
   def func(self):
       print('in son')

Son()

注意事项:

- self 到底是谁?
- self 是哪个类创建的,就从此类开始找,自己没有就找父类。
# 思考二: 如果想给狗和猫定制个性的属性
class Animal:
   def __init__(self, name, food):
       self.name = name
       self.food = food
       self.blood = 100
       self.waise = 100

   def eat(self):
       print('%s is eating %s' % (self.name, self.food))

   def drink(self):
       print('%s is drinking' % self.name)

   def sleep(self):
       print('%s is sleeping' % self.name)


class Cat(Animal):
   def __init__(self, name, food, eye_color):
       Animal.__init__(self, name, food)  # 调用了父类的初始化,去完成一些通用属性的初始化
       self.eye_color = eye_color  # 派生属性


class Dog(Animal):
   def __init__(self, name, food, size):
       Animal.__init__(self, name, food)
       self.size = size


# 猫 : eye_color眼睛的颜色
# 狗 : size型号
小白 = Cat('小白', '猫粮', '蓝色')
print(小白.__dict__)
小黑 = Dog('小黑', '狗粮', '藏獒')
print(小黑.__dict__)
# 单继承
class D:
   def func(self):
       print('in D')


class C(D): pass


class A(C):
   def func(self):
       print('in A')


class B(A): pass
B().func()




# 多继承 有好几个爹
# 有一些语言不支持多继承 java
# python语言的特点 : 可以在面向对象中支持多继承
class B:
   def func(self): print('in B')


class A:
   def func(self): print('in A')


class C(B, A): pass


C().func()

# 单继承
# 调子类的 : 子类自己有的时候
# 调父类的 : 子类自己没有的时候
# 调子类和父类的 :子类父类都有,在子类中调用父类的

# 多继承
# 一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
# object类 类祖宗
# 所有在python3当中的类都是继承object类的
# object中有init
# 所有的类都默认的继承object
# 开辟空间 调用__init__方法

class Foo:
   pass


class Foo(object):
   pass


# 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。


# 如果在python2中这样定义,则称其为:经典类
class Foo:
   pass
# 如果在python2中这样定义,则称其为:新式类


class Foo(object):
   pass


class Base(object):
   pass


class Bar(Base):
   pass

总结

# 只要继承object类就是新式类
# 不继承object类的都是经典类

# 经典类 :在py3中不存在,在py2中不主动继承object的类
# python3 所有的类都继承object类,都是新式类
# 在py2中 不继承object的类都是经典类
#         继承object类的就是新式类了

# 在py2中
class A:pass         # 经典类
class B(object):pass # 新式类
# 在py3中
class A:pass         # 新式类
class B(object):pass # 新式类


# 在单继承方面(无论是新式类还是经典类都是一样的)
# class A:
#     def func(self):pass
# class B(A):
#     def func(self):pass
# class C(B):
#     def func(self):pass
# class D(C):
#     def func(self):pass
# d = D()
# 寻找某一个方法的顺序:D->C->B->A
# 越往父类走,是深度


# 多继承
class A:
   def func(self):
       print('A')

class B(A):
   def func(self):
       print('B')
class C(A):
   
   def func(self):
       print('C')  
class D(B,C):  
   
   def func(self):
       print('D')
print(D.mro())   # # 经典类没有mro,但新式类有
d = D()
d.func()
# 在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
# 在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了


# C3算法
# A(O) = [AO]
# B(A) = [BAO]
# C(A) = [CAO]
# D(B) = [DBAO]
# E(C) = [ECAO]

# F(D,E) = merge(D(B) + E(C))
#         = [F] + [DBAO] + [ECAO]
#       F = [DBAO] + [ECAO]
#     FD   = [BAO] + [ECAO]
#     FDB = [AO] + [ECAO]
#     FDBE = [AO] + [CAO]
#     FDBEC= [AO] + [AO]
#     FDBECA= [O] + [O]
#     FDBECAO

# 算法的内容
   # 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
   # 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,...
   # merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个
               # 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
               # 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
# 广度优先遵循C3算法,要会用mro,会查看顺序
# 经典类 - 深度优先 新式类 - 广度优先
super()
class A(object):
   def func(self):
       print('A')
class B(A):
   def func(self):
       super().func()
       print('B')
class C(A):
   def func(self):
       super().func()
       print('C')
class D(B,C):
   def func(self):
       super().func()  # 找父类总是优先找离自己最近的一个
       # super(D,self).func()
       print('D')
D().func()
# D,B,C,A
# super是按照mro顺序来寻找当前类的下一个类
# 在py3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法
# 在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名()
# 这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法
# 在py2的经典类中,并不支持使用super来找下一个类

# 在D类中找super的func,那么可以这样写 super().func()
# 也可以这样写 super(D,self).func() (并且在py2的新式类中必须这样写)
# 在单继承的程序中,super就是找父类
class User:
   def __init__(self,name):
       self.name = name
class VIPUser(User):
   def __init__(self,name,level,strat_date,end_date):
       # User.__init__(self,name)
       super().__init__(name)              # 推荐的
       # super(VIPUser,self).__init__(name)
       self.level = level
       self.strat_date = strat_date
       self.end_date = end_date

太白 = VIPUser('太白',6,'2019-01-01','2020-01-01')
print(太白.__dict__)

 

7 抽象类 【为什么要用抽象类 : 为了规范子类必须实现和父类的同名方法】

# 普通的类

# 不需要模块的
# class 父类:
#     def 子类必须实现的方法名(self,参数们):
#         raise NotImplementedError('提示信息')
# class 子类(父类):
#     def 父类要求实现的方法(self,参数们):
#         print('''code''')


# 抽象类 是一个开发的规范 约束它的所有子类必须实现一些和它同名的方法
# 支付程序
   # 微信支付 url连接,告诉你参数什么格式
       # {'username':'用户名','money':200}
   # 支付宝支付 url连接,告诉你参数什么格式
       # {'uname':'用户名','price':200}
   # 苹果支付
class Payment:     # 抽象类
   def pay(self,money):
       '''只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法'''
       raise NotImplementedError('请在子类中重写同名pay方法') # 主动抛出异常,主要是给程序员看

class Alipay(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'uname':self.name,'price':money}
       # 想办法调用支付宝支付 url连接 把dic传过去
       print('%s通过支付宝支付%s钱成功'%(self.name,money))

class WeChat(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'username':self.name,'money':money}
       # 想办法调用微信支付 url连接 把dic传过去
       print('%s通过微信支付%s钱成功'%(self.name,money))

class Apple(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'name': self.name, 'number': money}
       # 想办法调用苹果支付 url连接 把dic传过去
       print('%s通过苹果支付%s钱成功' % (self.name, money))

aw = WeChat('alex')
aw.pay(400)
aa = Alipay('alex')
aa.pay(400)
# 归一化设计
def pay(name,price,kind):
   if kind == 'Wechat':
       obj = WeChat(name)
   elif kind == 'Alipay':
       obj = Alipay(name)
   elif kind == 'Apple':
       obj = Apple(name)
   obj.pay(price)

pay('alex',400,'Wechat')
pay('alex',400,'Alipay')
pay('alex',400,'Apple')

appa = Apple('alex')
appa.pay(500)
# 实现抽象类的另一种方式,约束力强,依赖abc模块

# 需要模块的
# from abc import ABCMeta,abstractmethod
# class 父类(metaclass = ABCMeta):
#     @abstractmethod
#     def 子类必须实现的方法名(self,参数们):pass
# class 子类(父类):
#     def 父类要求实现的方法(self,参数们):
#         print('''code''')




from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
   @abstractmethod
   def pay(self,money):
       '''只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法'''
       raise NotImplementedError('请在子类中重写同名pay方法')

class Alipay(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'uname':self.name,'price':money}
       # 想办法调用支付宝支付 url连接 把dic传过去
       print('%s通过支付宝支付%s钱成功'%(self.name,money))

class WeChat(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'username':self.name,'money':money}
       # 想办法调用微信支付 url连接 把dic传过去
       print('%s通过微信支付%s钱成功'%(self.name,money))

WeChat('alex')

 

 

__bases__在Python中,每一个类有一个__bases__属性,列出其基类
class A:pass
print(A.__bases__)
class C:pass
print(C.__bases__)
class B(A,C):pass
print(B.__bases__)
type()查看类型不会认为子类是父类类型,不考虑继承关系
class Foo:
   pass

obj = Foo()

if type(obj) == Foo:
   print('obj是Foo类的对象')
isinstance会认为子类是父类类型,考虑继承关系
class Base(object):
   pass

class Foo(Base):
   pass

obj = Foo()

print(isinstance(obj,Foo))  # 判断obj是否是Foo类或其基类的实例(对象)
print(isinstance(obj,Base)) # 判断obj是否是Base类或其基类的实例(对象)
from types import FunctionType,MethodType
# FunctionType : 函数
# MethodType : 方法
class A:
   def func(self):
       print('in func')

print(A.func)  # 函数 函数对象内存地址
a = A()
print(a.func)  # 方法 绑定方法a.func的地址
print(isinstance(a.func,FunctionType))
print(isinstance(a.func,MethodType))
print(isinstance(A.func,FunctionType))
print(isinstance(A.func,MethodType))
# 了解要用去查
class A:
   role = '法师'
   def func1(self):pass
   def func2(self):pass
class B:pass
class C(B,A):pass
print(A.__base__)
print(C.__base__)
print(C.__bases__)
print(A.__dict__)
print(A.__name__)
print(A.__class__)
print(B.__class__)
print(C.__class__)
print(C.__module__)
区别1
import module 引用共享变量时,要使用module.变量名。

而from module import * 直接使用变量名即可

区别2(有点绕)
import module方式操作module的变量时,本地不会创建新变量,操作的是目标模块的变量!

from module import *方式操作module变量时,实质上是在本地创建一个与目标模块相同的变量名,并且默认与目标模块变量指向同一个内存空间。


import module
module.a = [1,2,3]
print(module.a)

from module import a
print(a)

输出:
[1, 2, 3]
[1, 2, 3]


from module import a
a = [1,2,3]
print(a)

import module
print(module.a)

输出:
[1, 2, 3]  # 结果不同了!
[]

因为!from module import 方式是自己创建了一个自己的变量a指向module.a的内存空间。当执行命令a = [1,2,3]时,变量a赋值了,重新分配了内存空间。并不是module文件里的a变量重新分配空间,所以odule文件里的a变量的值没有变化!

而import module方式是操作module文件里面a的变量,即使进行了赋值,重新分配了内存空间,但是他还是module里面的变量。所以当别人导入module的时候,module.a的值就是[1,2,3]了!
__doc__获取函数注释
def func():
   '''
  这个函数主要是用来卖萌
  :return:
  '''
   pass

print(func.__doc__)

class Cat:
   '''
  这个类是用来描述游戏中的猫咪角色
  '''
   pass
print(Cat.__doc__)

8 多态(多种形态/多种类型)鸭子模型

# Python
def func(arg):
   v = arg[-1] # arg.append(9)
   print(v)

# java
def func(str arg):
   v = arg[-1]
   print(v)

   
class Payment:pass
class WeChat(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'username':self.name,'money':money}
       # 想办法调用微信支付 url连接 把dic传过去
       print('%s通过微信支付%s钱成功'%(self.name,money))

class Apple(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'name': self.name, 'number': money}
       # 想办法调用苹果支付 url连接 把dic传过去
       print('%s通过苹果支付%s钱成功' % (self.name, money))

#JAVA
def pay(Payment a, int b):
   a.pay(b)
obj = Apple('alex')
pay(obj,400)
obj = WeChat('alex')
pay(obj,400)

# 一个类型表现出来的多种状态
# 支付 表现出的 微信支付和苹果支付这两种状态
# 在java情况下: 一个参数必须制定类型
# 所以如果想让两个类型的对象都可以传,那么必须让这两个类继承自一个父类,在制定类型的时候使用父类来指定

面试题:什么是鸭子模型。

对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法)。
这就是鸭子模型,类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们要想的类型)

迭代器协议只要有 __iter__ __next__方法就是迭代器
  • super

# 在py3中怎么用?
# 在py3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法

#在py2(新式类/经典类)中怎么用?
#在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名(),这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法,在py2的经典类中,并不支持使用super来找下一个类

class A(object):
   def func(self):
       print('A')
class B(A):
   def func(self):
       super().func()
       print('B')
class C(A):
   def func(self):
       super().func()
       print('C')
class D(B,C):        # 广度优先
   def func(self):
       super().func()
       # super(D,self).func()
       print('D')
# D().func()
# D,B,C,A  

# super是按照mro顺序来寻找当前类的下一个类
# 在D类中找super的func,那么可以这样写 super().func()
# 也可以这样写 super(D,self).func() (并且在py2的新式类中必须这样写)

9 封装:就是把属性或者方法装起来【成员修饰符】

# 广义 :把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
# 狭义 :把属性和方法藏起来,外面不能调用,只能在内部偷偷调用

class User:
   def __init__(self,name,passwd):
       self.usr = name
       self.__pwd = passwd  # 私有的实例变量/私有的对象属性
alex = User('alex','sbsbsb')
print(alex.__pwd)  # 报错
print(alex.pwd)    # 报错

# 给一个名字前面加上了双下划綫的时候,这个名字就变成了一个私有的,所有的私有的内容或者名字都不能在类的外部调用,只能在类的内部使用了

class User:
   def __init__(self,name,passwd):
       self.usr = name
       self.__pwd = passwd  # 私有的实例变量/私有的对象属性
   def get_pwd(self):       # 表示的是用户不能改只能看 私有 + 某个get方法实现的
       return self.__pwd
   def change_pwd(self):    # 表示用户必须调用我们自定义的修改方式来进行变量的修改 私用 + change方法实现
       pass
class User:
   __Country = 'China'   # 私有的静态变量
   def func(self):
       print(User.__Country)  # 在类的内部可以调用
print(User.Country)  # 报错 在类的外部不能调用
print(User.__Country)# 报错 在类的外部不能调用
User().func()
import  hashlib
class User:
   def __init__(self,name,passwd):
       self.usr = name
       self.__pwd = passwd  # 私有的实例变量
   def __get_md5(self):     # 私有的绑定方法
       md5 = hashlib.md5(self.usr.encode('utf-8'))
       md5.update(self.__pwd.encode('utf-8'))
       return md5.hexdigest()
   def getpwd(self):
       return self.__get_md5()
alex = User('alex','sbsbsb')
print(alex.getpwd())

# 所有的私有化都是为了让用户不在外部调用类中的某个名字,如果完成私有化 那么这个类的封装度就更高了 封装度越高各种属性和方法的安全性也越高 但是代码越复杂
如何变形,在哪里变形
# 加了双下划线的名字为啥不能从类的外部调用了?
class User:
   __Country = 'China'   # 私有的静态变量
   __Role = '法师'   # 私有的静态变量
   def func(self):
       print(self.__Country)  # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形
print(User._User__Country)
print(User._User__Role)
# __Country -->'_User__Country': 'China'
# __Role   -->'_User__Role': '法师'
# User.__aaa = 'bbb' # 在类的外部根本不能定义私有的概念
# 强制访问私有成员

class Foo:
   def __init__(self,name):
       self.__x = name


obj = Foo('alex')

print(obj._Foo__x) # 强制访问私有实例变量

 

# 私有的内容能不能被子类使用呢? 不能
class Foo(object):
   def __init__(self):
       self.func()
   def func(self):
       print('in Foo')
class Son(Foo):
   def func(self):
       print('in Son')
Son()
in Son

class Foo(object):
   def __init__(self):
       self.__func()
   def __func(self):
       print('in Foo')
class Son(Foo):
   def __func(self):
       print('in Son')
Son()
in Foo


class Foo(object):
   def __func(self):
       print('in Foo')
class Son(Foo):
   def __init__(self):
       self.__func()  # 报错
Son()

在其他语言中的数据的级别都有哪些?在python中有哪些? public 公有的 类内类外都能用,父类子类都能用 python支持 protect 保护的 类内能用,父类子类都能用,类外不能用 python不支持 private 私有的 本类的类内部能用,其他地方都不能用 python支持

装饰器函数

property:把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
import time
class Person:
   def __init__(self,name,birth):
       self.name = name
       self.birth = birth
   @property
   def age(self):   # 装饰的这个方法 不能有参数,把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
       return time.localtime().tm_year - self.birth

太白 = Person('太白',1998)
print(太白.age)

# property的第二个应用场景 : 和私有的属性合作的
class User:
   def __init__(self,usr,pwd):
       self.usr = usr
       self.__pwd = pwd
   @property
   def pwd(self):
       return self.__pwd

alex = User('alex','sbsbsb')
print(alex.pwd)
class Goods:
   discount = 0.8
   def __init__(self,name,origin_price):
       self.name = name
       self.__price = origin_price
   @property
   def price(self):
       return self.__price * self.discount

apple = Goods('apple',5)
print(apple.price)


# property进阶
class Goods:
   discount = 0.8
   def __init__(self,name,origin_price):
       self.name = name
       self.__price = origin_price
   @property
   def price(self):
       return self.__price * self.discount

   @price.setter
   def price(self,new_value):
       if isinstance(new_value,int):
           self.__price = new_value

apple = Goods('apple',5)
print(Goods.apple)   # 得到的是property对象地址
print(apple.price)   # 调用的是被@property装饰的price
apple.price = 10    
print(apple.price)   # 调用的是被setter装饰的price


class Goods:
   discount = 0.8
   def __init__(self,name,origin_price):
       self.name = name
       self.__price = origin_price
   @property
   def price(self):
       return self.__price * self.discount

   @price.setter
   def price(self,new_value):
       if isinstance(new_value,int):
           self.__price = new_value

   @price.deleter
   def price(self):
       del self.__price
apple = Goods('apple',5)
print(apple.price)
apple.price = 'ashkaksk'
del apple.price   # 并不能真的删除什么,只是调用对应的被@price.deleter装饰的方法而已
print(apple.price)
classmethod 把一个对象绑定的方法 修改成一个 类方法
  • 可以用对象和类调用对象.类方法() (不推荐)

class Goods:
   __discount = 0.8  # 私有静态变量

   def __init__(self):
       self.__price = 5  # 私有的实例变量,外部不可使用
       self.price = self.__price * self.__discount

   @classmethod  # 把一个对象绑定的方法 修改成一个 类方法
   def change_discount(cls, new_discount):
       cls.__discount = new_discount


obj = Goods()
print(obj.price) # 直接使用实例变量

Goods.change_discount(0.6)  # 类方法可以通过类名调用
apple = Goods()
print(apple.price)
apple.change_discount(0.5)  # 类方法可以通过对象名调用
apple2 = Goods()
print(apple2.price)



# @classmethod   # 把一个对象绑定的方法 修改成一个 类方法
# 第一,在方法中仍然可以引用类中的静态变量
# 第二,可以不用实例化对象,就直接用类名在外部调用这个方法
# 什么时候用@classmethod?
# 1.定义了一个方法,默认传self,但这个self没被使用
# 2.并且你在这个方法里用到了当前的类名,或者你准备使用这个类的内存空间中的名字的时候
import time


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

   @classmethod  # 装饰器
   def today(cls):
       t = time.localtime()
       return time.strftime(f'{t.tm_year}-{t.tm_mon}-{t.tm_mday}')


date = Date.today()
print(date)
@staticmethod 被装饰的方法会成为一个静态方法
  • 可以对象名调用和类名调用

class User:
   pass
   @staticmethod
   def login(a,b):      # 本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加@staticmethod装饰器就可以了
       print('登录的逻辑',a,b)
       # 在函数的内部既不会用到self变量,也不会用到cls类

obj = User()
User.login(1,2)
obj.login(3,4)
class A:
   country = '中国'   # 静态变量

   def func(self):
       print(self.__dict__)

   @classmethod
   def clas_func(cls):
       print(cls)

   @staticmethod
   def stat_func():  # 就是把一个普通函数拿到类中使用
       print('普通函数')

   @property
   def name(self):
       return 'wahaha'
   
   
# @classmethod 把一个对象绑定的方法 修改成一个 类方法  
A.clas_func()  # 可以用类名调用
obj = A()
obj.clas_func() # 可以可以用对象名调用
obj2 = A()

# @staticmethod   被装饰的方法会成为一个静态方法 【不重要】
obj = A()
A.stat_func()  # 可以用类名调用
obj.stat_func() # 可以可以用对象名调用


# @property 把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
obj = A()
print(obj.name)  # 调用不用加括号

 

 

10 反射

用字符串数据类型的名字 来操作这个名字对应的函数\实例变量\绑定方法\各种方法

有些时候 你明明知道一个变量的字符串数据类型的名字,你想直接调用它,但是调不到,使用反射

class Foo(object):
   def get(self):
       pass

obj = Foo()
# if hasattr(obj,'post'):
#     getattr(obj,'post')

v1 = getattr(obj,'get',None) # 推荐 如果没有该绑定方法,就不会报错,返回None
print(v1)

 

 

1.反射对象的 实例变量

class Person:
   def __init__(self,name,age):
       self.name = name
       self.age = age
   def qqxing(self):    # 绑定方法
       print('qqxing')

alex = Person('alex',83)
wusir = Person('wusir',74)
ret = getattr(alex,'name')  # 反射类的实例变量
print(ret)
ret = getattr(wusir,'name')
print(ret)
ret = getattr(wusir,'qqxing')  # 反射类的绑定方法
ret()

2 被导入的模块【所有变量】

# a.py


class Wechat:pass
class Alipay:pass

def sww():
   print('爽歪歪')
lst = [1,2,3,4,5]
dic = {'k':'v'}
we = Wechat()




import a   # 引用模块中的任意的变量
print(getattr(a,'sww'),a.sww)
getattr(a,'sww')()
print(getattr(a,'lst'),a.lst)
print(getattr(a,'dic'),a.dic)
print(getattr(a,'we'),a.we)





import sys # 反射本模块中的名字
cat = '小a'
dog = '小b'
def pig():
   print('小p')
print(getattr(sys.modules['__main__'],'cat'))
print(getattr(sys.modules['__main__'],'dog'))
getattr(sys.modules['__main__'],'pig')()
import a
print(a.Wechat)
print(a.Alipay)
# 对象名.属性名 ==> getattr(对象名,'属性名')
# a.Alipay ==> getattr(a,'Alipay')
print(getattr(a, 'Alipay'))
print(getattr(a, 'Wechat'))




import a
import sys
print(sys.modules)
print(sys.modules['a'].Alipay)
print(a.Alipay)
print(getattr(a,'Alipay'))
print(getattr(sys.modules['a'],'Alipay'))

wahaha = 'hahaha'
print(getattr(sys.modules['__main__'],'wahaha'))

3 反射类的 静态变量/其他方法

class A:
   Role = '治疗'
   def __init__(self):
       self.name = 'alex'
       self.age = 84
   def func(self):
       print('wahaha')
       return 666

a = A()
print(getattr(a,'name')) # 反射对象的实例变量
print(getattr(a,'func')()) # 反射对象的绑定方法
print(getattr(A,'Role'))

4 模块:importlib

根据字符串的形式导入模块。

模块 = importlib.import_module('utils.redis')

 

 

 

例子

class Payment:pass
class Alipay(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'uname':self.name,'price':money}
       print('%s通过支付宝支付%s钱成功'%(self.name,money))

class WeChat(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'username':self.name,'money':money}
       print('%s通过微信支付%s钱成功'%(self.name,money))

class Apple(Payment):
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       dic = {'name': self.name, 'number': money}
       print('%s通过苹果支付%s钱成功' % (self.name, money))

class QQpay:
   def __init__(self,name):
       self.name = name
   def pay(self,money):
       print('%s通过qq支付%s钱成功' % (self.name, money))
import sys
def pay(name,price,kind):
   class_name = getattr(sys.modules['__main__'],kind)
   obj = class_name(name)
   obj.pay(price)
   # if kind == 'Wechat':
   #     obj = WeChat(name)
   # elif kind == 'Alipay':
   #     obj = Alipay(name)
   # elif kind == 'Apple':
   #     obj = Apple(name)
   # obj.pay(price)

pay('alex',400,'WeChat')
pay('alex',400,'Alipay')
pay('alex',400,'Apple')
pay('alex',400,'QQpay')
  • hasattr判断对象是否包含对应的属性

  • callable判断对象是否可调用

  • getattr 从字符串格式的属性名中获取对应的属性值

class A:
   Role = '治疗'
   def __init__(self):
       self.name = 'alex'
       self.age = 84
   def func(self):
       print('wahaha')
       return 666

a = A()
print(hasattr(a,'sex'))
print(hasattr(a,'age'))
print(hasattr(a,'func'))
if hasattr(a,'func'):
   if callable(getattr(a,'func')): # callble判断对象是否可调用
       getattr(a,'func')()
  • __call__当对象像函数一样被调用时,就相当于执行它的__call__方法

class test:
   def __call__(self,*args,**kwargs)
  print('shot')
       
t1 = test()
t1()
# test()()
  • __len__获取对象的长度,就想当于执行了它的__len__方法

class Students(object):
   def __init__(self, *args):
       self.names = args

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


obj = Students('alex', 'wusir', '太白')
print(len(obj))
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
class A:
   def __new__(cls, *args, **kwargs):   # 构造方法
       # o = super().__new__(cls)
       o = object.__new__(cls)
       print('执行new',o)
       return o
   def __init__(self):
       print('执行init',self)
A()

# 实例化的时候
# 先创建一块对象的空间,有一个指针能指向类 --> __new__
# 调用init --> __init__

单利模式

# 设计模式 -- 单例模式
# 一个类 从头到尾 只会创建一次self的空间
class Baby:
   __instance = None
   def __new__(cls, *args, **kwargs):
       if cls.__instance is None:
           cls.__instance = super().__new__(cls)
       return cls.__instance
   def __init__(self,cloth,pants):
       self.cloth = cloth
       self.pants = pants
b1 = Baby('红毛衣','绿皮裤')
print(b1.cloth)
b2 = Baby('白衬衫','黑豹纹')
print(b1.cloth)
print(b2.cloth)
class Singleton(object):
   """
  单例模式
  """
   instance = None

   def __new__(cls, *args, **kwargs):
       if not cls.instance:
           cls.instance = object.__new__(cls)  
       return cls.instance

obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)
str和repr
  • __str__如果定义了__str__(self)方法,那么就会打印从这个方法中return的数据。__str__方法通常返回一个字符串,作为这个对象的描述信息

  • __repr__str的备胎,但是他自己%r或者repr的时候只显示这个方法的返回值

class Course:

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

   def __str__(self):
       return ','.join([self.name,str(self.price),self.period])


python = Course('python', 21800, '6 months')
linux = Course('linux', 19800, '5 months')
mysql = Course('mysql', 12800, '3 months')
go = Course('go', 15800, '4 months')
print(go)
lst = [python,linux,mysql,go]
for index, c in enumerate(lst, 1):
   print(index, c)
num = int(input('>>>'))
course = lst[num - 1]

print('恭喜您选择的课程为 %s 价格%s元' % (course,course.price))

class clas:
   def __init__(self):
       self.student = []
   def append(self,name):
       self.student.append(name)
   def __str__(self):
       return str(self.student)

py22 = clas()
py22.append('大壮')
print(py22)
print(str(py22))
print('我们py22班 %s'%py22)
print(py22)
py22.append('大壮')
print(py22)

# 在打印一个对象的时候 调用__str__方法
# 在%s拼接一个对象的时候 调用__str__方法
# 在str一个对象的时候 调用__str__方法
class clas:
   def __init__(self):
       self.student = []

   def append(self, name):
       self.student.append(name)

   def __repr__(self):
       return str(self.student)

   def __str__(self):
       return 'aaa'


py22 = clas()
py22.append('大壮')
print(py22)
print(str(py22))
print('我们py22班 %s' % py22)
print('我们py22班 %r' % py22)
print(repr(py22))
# 当我们打印一个对象 用%s进行字符串拼接 或者str(对象)总是调用这个对象的__str__方法
# 如果找不到__str__,就调用__repr__方法
# __repr__不仅是__str__的替代品,还有自己的功能
# 用%r进行字符串拼接 或者用repr(对象)的时候总是调用这个对象的__repr__方法
上下文管理【面试题】(__enter__
class Foo(object):
   def __enter__(self):
       self.x = open('a.txt',mode='a',encoding='utf-8')
       return self.x
   def __exit__(self, exc_type, exc_val, exc_tb):
       self.x.close()

with Foo() as ff:
   ff.write('alex')
   ff.write('alex')
   ff.write('alex')
   ff.write('alex')
# class Context:
#     def __enter__(self):
#         print('进入')
#         return self
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('推出')
#
#     def do_something(self):
#         print('内部执行')
#
# with Context() as ctx:
#     print('内部执行')
#     ctx.do_something()


class Foo(object):
   def do_something(self):
       print('内部执行')

class Context:
   def __enter__(self):
       print('进入')
       return Foo()

   def __exit__(self, exc_type, exc_val, exc_tb):
       print('推出')

with Context() as ctx:
   print('内部执行')
   ctx.do_something()
两个对象相加
val = 5 + 8
print(val)

val = "alex" + "sb"
print(val)

class Foo(object):
   def __add__(self, other):
       return 123
   
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2
print(val)

特殊成员:就是为了能够快速实现执行某些方法而生。

 

posted @ 2021-03-26 08:53  Jack_Gao  阅读(131)  评论(0)    收藏  举报