面向对象

一,概述:

  • 面向过程:根据业务逻辑从上到下写垒代码
  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

面向对象设计:

def DOG(name,gender,type):
    def jiao(dog):
        print('一条狗%s,汪汪汪'%dog['name'])
    def chi(dog):
        print('一条%s狗%s在吃屎'%(dog['type'],dog['name']))
    def init():
        dog1 = {
            'name' :name,
            'gender':gender,
            'type':type,
            'jiao':jiao,
            'chi':chi
        }
        return dog1
    return init()

d1 = DOG('吴岑','gong','藏獒')
d2 = DOG('xiexiexie','mu','大金毛')
# print(d1)
# print(d2)
d1['jiao'](d1)
d1['chi'](d1)
View Code

 

类:把一类事物的相同的特征和动作整合在一起就是类,类是一个抽象的概念。

对象:就是基于类而创建的一个具体的事物(具体存在的),也是特征和动作整合在一起。

属性:数据属性(特征)  ,  函数属性(动作)

实例化: 就是把一个实例传给 类。

 

面向对象编程:

# 声明类

class Chinese:
    '这是一个中国人类'
    dang = '中党'
    def yong_kuai_zi(self):
        print('中国人%s用筷子吃饭'%self)
    def cha_dui():
        print('中国人喜欢插队')

# print(Chinese)     ## <class '__main__.Chinese'>   类名
# print(Chinese.dang)   # 使用点调用
Chinese.yong_kuai_zi('goulonghui')

## 类的属性字典 Chinese.__dict__
# print(Chinese.__dict__)
# Chinese.__dict__['dang']
# Chinese.__dict__['yong_kuai_zi']('zhangqian')
# Chinese.__dict__['cha_dui']()
View Code

对象类的相关知识:

'''
1.数据属性
2.函数属性
'''

class chinese:
    '这是一个中国人类'
    dang = '中场单党'
    def __init__(self,name,age,gender):
        self.mingzi = name     #p1.mingzi=name
        self.nianling = age      #p1.nianji=age
        self.xingbie = gender
    def suiditutang(self):
        print('%s喜欢随地吐痰' %self.mingzi)
    def chadui(self):
        print('%s插到了一个年龄是%s的人前面' %(self.mingzi,self.nianling))

p1 = chinese('alex','55','')   #--->__init__(self,name,age,gender)       p1 传给了self
print(p1.__dict__)     ### {'mingzi': 'alex', 'nianling': '55', 'xingbie': '男'}
print(p1.__dict__['mingzi'])    ###  alex
print(p1.mingzi)                ### alex  实质就是去得到的p1字典中取值
## chinese.mingzi       ### 报错  类属性访问不了 实例属性
print(p1.dang)       ### 中场单党    # 风湿理论找上级参数   即为 实例属性 可访问类属性

chinese.suiditutang(p1)   ### alex喜欢随地吐痰
chinese.chadui(p1)       ### alex插到了一个年龄是55的人前面

p1.chadui()          ### alex插到了一个年龄是55的人前面    / 自动给chadui()函数传入了 p1

增删改查:

class Chinese:
    dang = '中党'
    def play_ball(self):
        print('%s正在打球' %self.name)
    def eat(self,food):
        print('%s正在吃%s'%(self.name,food))
    def __init__(self,name):
        self.name = name

p1 = Chinese('alex')
# 查看
print(Chinese.dang)    # 中党
print(Chinese.play_ball)   ## <function Chinese.play_ball at 0x0000000001E7A8C8>

# 修改
Chinese.dang = 'guomigndang'
print(Chinese.dang)             ## guomigndang

def test(self):
    print('来自test函数')
Chinese.play_ball = test
p1.play_ball()          ### 来自test函数

## 增加

Chinese.country = 'Japan'
print(Chinese.country)     ### Japan

Chinese.new_test = test
print(Chinese.__dict__)    ##  'new_test': <function test at 0x0000000001D03E18>


### 删除

del Chinese.dang
del Chinese.new_test
print(Chinese.__dict__)
类的增删改查
class Chinese:
    country='China'
    def __init__(self,name):
        self.name=name

    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))
p1=Chinese('alex')
print(p1.__dict__)

### 查看
print(p1.name)  ### alex
print(p1.play_ball)   ### <bound method Chinese.play_ball of <__main__.Chinese object at 0x00000000027E9630>>

## 增加
p1.__dict__['sex'] = 'nan'
print(p1.__dict__)          #  {'name': 'alex', 'sex': 'nan'}

### #不要修改底层的属性字典

p1.__dict__['name'] = 'alvin'
print(p1.__dict__)   ##  {'name': 'alvin', 'sex': 'nan'}
print(p1.name)    ### alvin

## 删除
del p1.name
print(p1.__dict__)     ##{'sex': 'nan'}
实例的增删改查 

特别注意

在面向对象中,程序逐行运行时,遇到一个类,就会在内存中开辟一个空间,这个空间的id就是类的地址,
同时会把这类中的静态属性的变量名和动态方法的地址,以及初始化函数__init__的地址放进去;
在实例化一个类产生对象的时候,每遇到一次实例化,就在内存中开辟一个空间(这个空间和第一次开辟的类的的空间不同),同时
把这空间和实例的对象obj,还有self同时对应起来;让后会在其中储存一个类的对象指针(相当于储存了类名),然后在进行实例化,执行__init__方法,把传入的变量(如self.name = name)
存在在其中;
因为有了这个类的对象指针,才使得不同的实例都可以调用类的属性和方法
面向对象-执行中内存的分配

# class Chinese:
#     country='China'
#     def __init__(self,name):
#         self.name=name
#
#     def play_ball(self,ball):
#         print('%s 正在打 %s' %(self.name,ball))
# p1=Chinese('alex')
# print(p1.country)
# p1.country='日本'     ### 写到实例属性的 属性字典中,不影响类的country
# print('类的--->',Chinese.country)
# print('实例的',p1.country)


# country='中国'
# class Chinese:
#     def __init__(self,name):
#         self.name=name
#
#     def play_ball(self,ball):
#         print('%s 正在打 %s' %(self.name,ball))
# p1=Chinese('alex')
# print(p1.country)    找类的属性       country不是类,所以找不到



# country='中国'
# class Chinese:
#     def __init__(self,name):
#         self.name=name
#
#     def play_ball(self,ball):
#         print('%s 正在打 %s' %(self.name,ball))
#
# def shi_li_hua():
#     name=input('>>: ')
#     p1=Chinese(name)
#     # print(p1.country)
#     print(p1.name)
# shi_li_hua()



# country='中国-------------------'
# class Chinese:
#     country='中国'
#     def __init__(self,name):
#         self.name=name
#         print('--->',country)     ##  非点调用,不找类和实例的属性
#
#     def play_ball(self,ball):
#         print('%s 正在打 %s' %(self.name,ball))
#
# print(Chinese.__dict__)
# print(Chinese.country)
# p1=Chinese('alex')
# print('实例--------》',p1.country)     ###  还有用点调用时才会找实例 和类 的 属性字典

# Chinese.
# p.


###--------注意--------------------
class Chinese:
    l = ['a','b']
    country = '中国'
    def __init__(self, name):
        self.name=name

    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))

p1 = Chinese('alex')
print(Chinese.l)    ### ['a', 'b']

print(p1.l)    ###['a', 'b']

# p1.l = [1,2]    ###  添加新的列表到实例属性字典中
# print(p1.l)    ### ['a', 'b']
# print(p1.__dict__)     ###{'name': 'alex', 'l': [1, 2]}

p1.l.append('c')    ###  添加元素 c 到类的属性字典中
print(Chinese.l)     ### ['a', 'b', 'c']
面向对象里调用变量时的坑
#!/usr/bin/env python
# -*- coding:utf8 -*-
# __author__ = 'glh'

import time


class Person:
    def __init__(self, name, sex, hp, ad):  # 初始化方法
        self.name = name
        self.kind = sex
        self.hp = hp
        self.ad = ad

    def attack(self, dog):
        print('%s攻击了%s' % (self.name, dog.name))
        dog.hp -= self.ad
        if dog.hp <= self.ad:
            print('%s剩余血量为%s,%sgg思密达' % (dog.name, dog.hp, dog.name))
        else:
            print('%s掉了%s点血,%s剩余血量为%s' % (dog.name, self.ad, dog.name, dog.hp))


class Dog:
    country = 'china'  # 静态属性

    def __init__(self, name, kind, hp, ad):  # 初始化方法
        self.name = name
        self.kind = kind
        self.hp = hp
        self.ad = ad

    def bite(self, people):
        print('%s攻击了%s' % (self.name, people.name))
        people.hp -= self.ad
        if people.hp <= self.ad:
            print('%s剩余血量为%s,%sgg思密达' % (people.name, people.hp, people.name))
        else:
            print('%s掉了%s点血,%s剩余血量为%s' % (people.name, self.ad, people.name, people.hp))


d1 = Dog('松松gou', '藏獒', 100, 5)
d2 = Dog('小蝌蚪gou', '金毛', 100, 5)
p1 = Person('alex人', 'nv', 50, 20)

p1.attack(d1, d2)
Person.attack(d1, d2)   注意



while 1:
    time.sleep(1)
    p1.attack(d1)
    if d1.hp < 0:
        break
    time.sleep(0.5)
    d1.bite(p1)
    if p1.hp < 0:
        break
人狗大战

静态属性,静态方法,类方法

method        方法 —— 函数               由实例化对象去调用
property      伪装成属性的方法 —— 特性     由实例化对象去调用,类调用时,不加(),打印的时该方法的内存地址
classmethod   类方法                     由类调用,只使用类中的静态属性,或者类方法,或者静态方法的时候用;注意:实例对象也可以调用,但没什么意义
staticmethod  静态方法                   由类调用,一个方法既不会用到对象的资源(属性),也不会用到类的资源(属性),相当于一个普通函数
class Circle:
    def __init__(self, r):
        self.r = r

    @property  # 将动态方法伪装成静态属性
    def area(self):   # 这里的area应该为Circle类的属性,但是又要通过计算得到,所以把他伪装成静态属性
        return self.r ** 2 * pi

    @property
    def perimeter(self):
        return 2 * pi * self.r


# c2 = Circle(3)
# print(c2.perimeter)  # 18.84955592153876
# print(c2.area)  # 28.274333882308138
静态属性-property
# 修改一个把动态方法伪装成静态属性的属性中的私有属性时用@x.setter
class Goods:
    def __init__(self, discount, origin_price):
        self.__discount = discount
        self.__price = origin_price

    @property
    def price(self):
        return self.__discount * self.__price


print(Goods.price)
apple = Goods(0.8, 10)
print(apple.price)
apple.__price = 12  # 这样修改只能时添加一个叫__price的实例 属性,并没有真正的修改掉原来的__price(相当于_Goods__price)
apple._Goods__price = 12  # 这样才能修改,不过python中一般不这么用,所以只能采用setter方法了
print(apple.price)


class Goods:
    def __init__(self, discount, origin_price):
        self.__discount = discount
        self.__price = origin_price

    @property
    def price(self):
        return self.__discount * self.__price

    @price.setter
    def price(self, new):
        self.__price = new


apple = Goods(0.8, 10)
print(apple.price)
apple.price = 12  # 看到这里 = 就去执行 被@price.setter 装饰的price方法 ,在该函数中进行了修改操作,
#                       实在类的内部对私有属性修改的
print(apple.price)  # 9.600000000000001

property中的setter用法
property中的setter用法
# 删除一个被property装饰的方法时,用@x.deleter
class A:
    def __init__(self, path):
        self._f = open(path, 'w', encoding='utf-8')

    @property
    def f(self): return self._f

    @f.deleter
    def f(self):
        self.close()  # 所有的借用操作系统的资源,在删除一个变量之前都必须先归还资源
        del self._f

    def write(self, comment):
        self._f.write(comment)

    def close(self):
        self._f.close()


# obj = A('a.txt')

# print(obj.f)
# del obj.f
# print(obj.f)

property中的deleter用法
property中的deleter用法
class Room:
    colour = 'haungse'
    def __init__(self,name,owner,length,width,height):
        self.name = name
        self.owner = owner
        self.length = length
        self.width = width
        self.height = height
    @classmethod                      ## 类的方法
    def tell_info(cls):    ### 用点调用时默认自动将类传给 cls
        print(cls)     ###  相当于 Room
        print(cls.colour)       ###  相当于 Room.colour

Room.tell_info()
类方法-classmethod
class Room:
    colour = 'haungse'
    def __init__(self,name,owner,length,width,height):
        self.name = name
        self.owner = owner
        self.length = length
        self.width = width
        self.height = height
    @staticmethod                     ## 类的工具包  无self 和 cls ,不能调用实例和类属性
    def wash_body(a,b,c):
        print('%s,%s,%s正在洗澡' %(a,b,c))     ###  相当于 Room

Room.wash_body('z','g','e')
r1 = Room('zhaoxinjingdou','goulognhui',100,100,2)
r1.wash_body('z','g','e')
# r2 = Room('yufenhuayuan0','zhanggqian',10,10,200)
静态方法-staticmethod

二,组合 

class Head:
    print('form Head')
    pass

class Finger:
    pass

class Person:
    def __init__(self,name):
        self.name = name
        self.head = Head()       ## 组合的 就是给类的数据属性(初始化函数)中 添加了一个 其他类的对象
        self.finger = Finger()

p1 = Person('goulonghui')
p1.head    ## form Head
###  ------- 选课系统 ------
class School:
    def __init__(self,name,addr):
        self.name = name
        self.addr = addr

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

class Techer:
    def __init__(self,name,salary,school):
        self.name = name
        self.salary = salary
        self.school = school

s1 = School('oldboy','北京')
s2 = School('oldboy','南京')
s3 = School('oldboy','东京')

t1 = Techer('武沛奇', '30000',s1 )
t2 = Techer('林海峰', '30000',s2 )
t3 = Techer('元昊', '30000',s3)

msg = '''
1,oldboy,北京,武沛奇
2,oldboy,南京,林海峰
3,oldboy,东京,元昊
'''
while True:
    print(msg)
    menu_dic = {
        '1':s1,
        '2':s2,
        '3':s3
    }
    techer_dic = {
        '1':t1,
        '2':t2,
        '3':t3
    }
    chioce = input('请输入学校:' )
    school_obj = menu_dic[chioce]
    techer_obj = techer_dic[chioce]

    name = input('课程名:')
    price = input('价格:')
    new_course = Course(name,price,school_obj,techer_obj)
    print('%s学校的%s老师教授的%s课程'%(new_course.school.name,new_course.techer.name,new_course.name))
简单选课系统
#!/usr/bin/env python
# -*- coding:utf8 -*-
# __author__ = 'glh'

# 学生类 课程类


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


class Student:
    def __init__(self, name, sex, phone, course):
        self.name = name
        self.sex = sex
        self.phone = phone
        self.course = course


c1 = Course('python', 20000, 6)
c2 = Course('linux', 15000, 5)
s1 = Student('苟陇辉', '', '18829037944', c1)
print(s1.course.name)


 # 圆环 圆形
from math import pi


class Circle:
    def __init__(self, radius):
        self.r = radius

    def area(self):
        return pi*self.r*self.r

    def per(self):
        return 2*pi*self.r


class Ring:
    def __init__(self, out_r, in_r):
        self.out_r = Circle(out_r)
        self.in_r = Circle(in_r)

    def area(self):
        return '圆形的面积是%s' % (self.out_r.area() - self.in_r.area())

    def per(self):
        return '圆形的周长是{}'.format(self.out_r.per() + self.in_r.per())


print(Ring(10, 5).area())
print(Ring(10, 5).per())
组合练习

三,继承

 继承
    #   父类也称为基类

# class Parent1:
#     pass
# class Parent2:
#     pass
#
# class Son(Parent1):    ## 单继承
#     pass
#
# class Son(Parent1,Parent2):   #  多继承
#     pass

# class Father:
#     money = 200000
#     def __init__(self,name):
#         self.name = name
#     def hit_son(self,name):
#         print('%s正在打儿子'%self.name)
#
# class Son(Father):
#     money = 1200
#     pass
#
# s1 = Son('alex')
# s1.hit_son(s1)    ###alex正在打儿子
# print(s1.money)    ### 1200
# print(Father.money)  ### 200000     找方法时 先在自己属性字典里面找,自己没有时,再去父类里找
  1 #!/usr/bin/env python
  2 # -*- coding:utf8 -*-
  3 # __author__ = 'glh'
  4 
  5 # 利用函数模拟抽象类 和接口类继承
  6 
  7 
  8 # class WeChatpay:
  9 #     def pay(self, money):
 10 #         print('微信支付了%s元' % money)
 11 #
 12 #
 13 # class Alipay():
 14 #     def fuqian(self, money):
 15 #         print('支付宝支付了%s元' % money)
 16 #
 17 #
 18 # def payment(obj, money): return obj.pay(money)  # 归一化  为了规范
 19 #
 20 #
 21 # w1 = WeChatpay()
 22 # A1 = Alipay()
 23 # payment(w1, 100)  # 可以执行
 24 # payment(A1, 100)  # AttributeError: 'Alipay' object has no attribute 'pay' 因为Alipay类中没有实现pay方法
 25 # 抽象继承
 26 # 抽象类 :
 27     # 在类的位置指定metaclass 是ABCMeta
 28     # 在指定的方法上面添加@abstractmethod装饰器
 29 # 目的:规范所有继承这个类的子类 必须实现被@abstractmethod装饰器装饰的这个方法
 30 # 特点:抽象类和接口类不能被实例化
 31 from abc import ABCMeta,abstractmethod
 32 
 33 
 34 class Pay(metaclass=ABCMeta):   # 相当于制定了一个规范,该规范指定继承它的类都必须实现pay方法,要不然无法实例化(会报错)
 35     @abstractmethod
 36     def pay(self): pass
 37 
 38 
 39 class WeChatpay(Pay):
 40     def pay(self, money):
 41         print('微信支付了%s元' % money)
 42 
 43 
 44 class Alipay(Pay):
 45     def fuqian(self, money):
 46         print('支付宝支付了%s元' % money)
 47 
 48 
 49 # W1 = WeChatpay()  # 可正常实例化,因为WeChatpay类中实现了pay方法
 50 # A1 = Alipay()  # 不能实例化,因为Alipay类中没有实现了pay方法,实例化会报错 
 51 # TypeError: Can't instantiate abstract class Alipay with abstract methods pay
 52 
 53 
 54 # 接口类继承
 55 # 规范
 56 # 接口类
 57 # python天生支持多继承
 58 # java语言是不支持多继承的
 59 from abc import ABCMeta,abstractmethod
 60 
 61 
 62 class Walk_Animal(metaclass=ABCMeta):
 63     @abstractmethod
 64     def walk(self):pass
 65 
 66 
 67 class Fly_Animal(metaclass=ABCMeta):
 68     @abstractmethod
 69     def fly(self):pass
 70 
 71 
 72 class Swim_Animal(metaclass=ABCMeta):
 73     @abstractmethod
 74     def swim(self):pass
 75 
 76 
 77 class Tiger(Walk_Animal,Swim_Animal):  # 可同时继承2个规范
 78     def walk(self):
 79         print('walk')
 80         
 81     def swim(self):
 82         print('swim')
 83 
 84 
 85 class Parrot:
 86     def walk(self):
 87         print('walk')
 88         
 89     def fly(self):
 90         print('fly')
 91 
 92 
 93 class Swan:
 94     def walk(self):
 95         print('walk')
 96         
 97     def fly(self):
 98         print('fly')
 99         
100     def swim(self):
101         print('swim')
抽象继承和接口继承
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.

在python3中,子类执行父类的方法也可以直接用super方法.

class A:
    def hahaha(self):
        print('A')

class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print('B')

a = A()
b = B()
b.hahaha()
super(B,b).hahaha()
子类调用父类中的方法的三种方式

归一化

继承顺序(钻石继承)

1、Python的类可以继承多个类,Java和C#中则只能继承一个类

2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

 

  • 当类是经典类时,多继承情况下,会按照深度优先方式查找
  • 当类是新式类时,多继承情况下,会按照广度优先方式查找

经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

 

class D:

    def bar(self):
        print 'D.bar'


class C(D):

    def bar(self):
        print 'C.bar'


class B(D):

    def bar(self):
        print 'B.bar'


class A(B, C):

    def bar(self):
        print 'A.bar'

a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
经典类多继承
class D(object):

    def bar(self):
        print 'D.bar'


class C(D):

    def bar(self):
        print 'C.bar'


class B(D):

    def bar(self):
        print 'B.bar'


class A(B, C):

    def bar(self):
        print 'A.bar'

a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
新式类多继承

注意: 在新式类可使用print(F.__mro__)或者(F.mro())来查看顺序。

# super
class A:
    def func(self):
        print('A')
class B(A):
    def func(self):
        print('B')
        super().func()
class C(A):
    def func(self):
        print('C')
        super().func()
class D(B,C):
    def func(self):
        print('D')
        super().func()

# D().func()  D.mro()
# B().func()
# print(B.mro())
# super并不是单纯的找父类,和mro顺序是完全对应的
super()去调用父类中的方法时,也按照MRO列表顺序去找
# C3算法 归并算法
class A(object): pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(C): pass
class F(D, E): pass

print(F.__mro__)
# 第一步先找到继承的父类的MRO
# D = [D, B, A, O]
# E = [E, C, A, O]
# 第二步 把父类这两个MRO 和 DE 进行归并
# 取每个表表头 并且其他表去掉表头的部分不能含有我们要取的那个表头
# 如果不满走就去取第二个表头
# merge([DBAO], [ECAO], [DE])
# FD merge([BAO], [ECAO], [E])
# FDB merge([AO], [ECAO], [E])
# FDBE merge([AO], [CAO])
# FDBEC merge([AO], [AO])
# FDBECAO

# merge([AO], [OA])
C3算法 归并算法

四,多态

# python 天生支持多态
# 多态:由不同的类实例化得到的对象调用同一个方法,执行的逻辑不同。
class H2O:
    def __init__(self,name,temperature):
        self.name = name
        self.temperature = temperature
    def turn_ice(self):
        if self.temperature < 0:
            print('')
        elif self.temperature >0 and self.temperature <100:
            print('')
        else:
            print('水蒸气')

class Water(H2O):
    pass
class Ice(H2O):
    pass
class Steam(H2O):
    pass
W1 = Water('',50)    ##  产生三个不同类的实例化对象
I1 = Ice('',-20)
S1 = Steam('水蒸气',105)
W1.turn_ice()       ###  以下三个不同类实例化的对象 调用同一个方法
I1.turn_ice()
S1.turn_ice()
多态

五,封装

 1  封装 : 意义在于隐藏
 2 #①: 第一层面封装:将属性(数据属性 和 函数属性)封装在类中 在调用模块时只能看见可调用的类名 ,内部的具体逻辑看不见
 3 #第二层面的封装:
 4 #  ②:python 约定以一个_下划线开头的属性,是隐藏在内部的,外部不调用(但是Python不会阻止你调用,可以调用)
 5 #③ :以 两个 __下划线开头的属性,python会自动做一个重命名的操作,变为_类名__属性方法名
 6 
 7 # class People:
 8 #     __from = 'earth'
 9 #     def __init__(self,name):
10 #         self.name = name
11 # print(People.__dict__)     ###  '_People__from': 'earth'
12 # p1 = People('goulonghui')
13 # print(p1._People__from)    ## earth
14 
15 ##  第三层面的封装:明确区分内外,定义一个访问借口,供外部调用,(即接口函数)
16 class Room:
17     def __init__(self,name,length,width,height):
18         self.name = name
19         self.__length = length
20         self.height = height
21         self.__width = width
22     def area(self):    ### 接口函数
23         return self.__length * self.__width
24 
25 R1 = Room('厨房',100,100,1000)
26 # print(R1.__length)   ## 找不到
27 # print(R1._Room__length)    ## 可以调用
28 print(R1.area())    ##  接口函数调用 10000
class Student:
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd

    def __getpwd(self):  # 把方法封装成私有的
        return self.__pwd

    def login(self):  # 接口函数
        return self.__pwd


s1 = Student('gou', 123)
# print(s1._Student__pwd)
# print(s1._Student__getpwd())  # 可以调到,但是一般不这么用
print(s1.login())  # 可通过接口函数去调用
把方法封装成私有的

六,反射

# 反射(即自省):程序可以访问,检测和修改它本身状态或行为的一种能力。

# 四个可以实现自省的函数
class People:
    tui = '两条腿'
    def __init__(self,name):
        self.name = name
    def eat(self):
        print('%s再吃'%self.name)
p1 = People('')
# 1、 hasattr(x,y)   #  判断对象x中有么有一个y的方法
print(hasattr(p1,'tui'))  # True# 1、 hasattr(x,y)   #  判断对象x中有么有一个y的方法
print(hasattr(p1,'eat'))  #  True

# 2、 getattr(x,y)   #  查找对象x中y的值
print(getattr(p1,'tui'))   ## 两条腿
print(getattr(p1,'eat'))    ##  <bound method People.eat of <__main__.People object at 0x0000000001E89B38>>
getattr(p1,'eat')()    ## 苟再吃  加上()可以运行
print(getattr(p1,'sdd','属性不存在'))   #  defalut = 属性不存在     defalut 默认为None   找不到时不写defalut 程序报错

# 3、 setattr(x,y)   #  在x中创建或修改y的值
setattr(p1,'tui','大长腿')
print(p1.__dict__)  # 修改 {'name': '苟', 'tui': '大长腿'}
setattr(p1,'gebo','细胳膊')
print(p1.__dict__)   #  创建 {'name': '苟', 'tui': '大长腿', 'gebo': '细胳膊'}

# 4、 delattr(x,y)   #  在x中删除y的值
delattr(p1,'gebo')
print(p1.__dict__)  #删除   {'name': '苟', 'tui': '大长腿'}

 

# 为什么用反射?
class FTPclient:
    def __init__(self,addr):
        self.addr = addr
        print('正在连接服务器%s'%self.addr)
    # def put(self):
    #     print('正在上传\n请等待')
F1 = FTPclient('196.168.56.67')
if hasattr(F1,'put'):
    func_put = getattr(F1,'put')
    func_put()
else:
    print('不存在此方法,使用其他逻辑')
# 使用__import__,调用,传入字符串
# module_t = __import__('m1.test')
# print(module_t)    ###  <module 'm1' from 'D:\\pythontest\\glh14 面向对象3\\m1\\__init__.py'>
# ##  只找到顶级模块m1
# # 调用时 当做m1调用
# module_t.test.test1()   ## test1
# module_t.test._test2()   ### _test2

# 注意
#
from m1.test import *    #  * 不能导入私有函数(即一下划线开头的)
#
# # test1()   ### test1
# # _test2()   ## name '_test2' is not defined   无法调用
#
# from m1.test import test1,_test2
# _test2()    ###   #  _test2


import importlib  ### 直接找到模块下的方法
m = importlib.import_module('m1.test')
print(m)   ## <module 'm1.test' from 'D:\\pythontest\\glh14 面向对象3\\m1\\test.py'>

m.test1()   ## test1
底层基于反射实现:动态导入模块

七,双划线attr方法

class Foo:
    def __init__(self,name):
        self.name = name
    def __getattr__(self, item):      ###  找属性不存在时,会触发该函数的运行,若无该函数,则会报错
        print('你找的属性%s不存在'%item)

#
# f1 = Foo('alex')
# print(f1.name)  ##   alex
# f1.age    ### 你找的属性age不存在

    def __setattr__(self, key, value):        ###  设置时 属性不存在时,执行该函数
        print('执行setattr',key,value)
        if type(value) is str:
            print('kaishishezhi')
            # self.key = value    ##  会触发__setattr__ ,函数无限递归
            self.__dict__[key] = value
        else:
            print('%s类型错误'%value)
# f1 = Foo('alex')
# f1.age = 18       ###  18类型错误
# f1.new_age = '18'   ###  kaishishezhi

    def __delattr__(self, item):   ### 删除时会触发
        # del self.name    ###  无限递归
        self.__dict__.pop(item)
f1 = Foo('alex')     ## 实例化执行函数__setattr__
print(f1.__dict__)      ## {'name': 'alex'}
del f1.name
print(f1.__dict__)    ###  {}  为空

八,继承的方式包装标准类型

class List(list):
    def append(self,object):    ##  为标准类型的list类添加方法append,只能添加字符串类型的进去
        if type(object) is str:
            # self.append(object)    此时的append是子类List的append 方法,还没定义好,故要调用类的append方法
            super().append(object)
        else:
            print('只能添加字符串类型')

    def show_midle(self):     ##  为标准类型的list类添加方法,找最中间字符
        mid_index = int(len(self)/2)
        return self[mid_index]

L1 = List('helloword')
# print(L1,type(L1))   # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd'] <class '__main__.List'>
# print(L1.show_midle())

print(L1.append(11111111111))   # 只能添加字符串类型
L1.append('sd') #  只能加字符串类型
print(L1)    ## ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd', 'sd']

九,授权

# class FileHandle:
#     def __init__(self,filename,mode = 'r',encoding = 'utf-8'):
#         self.file = open(filename,mode,encoding=encoding)
#         self.mode = mode
#         self.encoding = encoding
#     def __getattr__(self, item):
#         # 这里需要调用 文件read 方法
#         return getattr(self.file,item)
#
# F1 = FileHandle('a.txt','r+')
# print(F1.read)    # 触发getattr方法 ## <built-in method read of _io.TextIOWrapper object at 0x0000000002049A68>
# print(F1.write)    # 触发getattr方法 ##<built-in method write of _io.TextIOWrapper object at 0x0000000002029A68>
# F1.write('111111\n22222')    ###  在a.txt文件中写 111111\n 222222

#---------------------加上修改功能----------------------
import time
class FileHandle:
    def __init__(self,filename,mode = 'r',encoding = 'utf-8'):
        self.file = open(filename,mode,encoding=encoding)
        self.mode = mode
        self.encoding = encoding
    def write(self,line):
        t = time.strftime('%Y-%m-%d %X',time.localtime())
        self.file.write('%s %s'%(t,line))
    def __getattr__(self, item):
        # 这里需要调用 文件read 方法
        return getattr(self.file,item)

F1 = FileHandle('a.txt','r+')
print(F1.read)    # 触发getattr方法 ## <built-in method read of _io.TextIOWrapper object at 0x0000000002049A68>
print(F1.write)   # 触发自己类里的write方法
F1.write('cpu负载过高\n')    ###  在a.txt文件中写 111111\n 222222
time.sleep(1)
F1.write('内存剩余不足\n')
time.sleep(1)
F1.write('硬盘空间不足\n')

十,isinstance,issubclass,__getattribute__ 方法

class Foo:
    def __init__(self,x):
        self.x = x
# f1 = Foo(4)
# print(isinstance(f1,Foo))   ## True  判断一个对象 是否为 一个类 的属性

class Bar(Foo):
    def __init__(self,y):
        self.y = y
# print(issubclass(Bar,Foo))  ##True  判断一个类是否为另一个类的子类


class Test:
    def __init__(self,x):
        self.x = x
    def __getattr__(self, item):
        print('执行__getattr_')

    def __getattribute__(self, item):
        print(' 执行__getattribute__')
        raise AttributeError('出错了')

t1 = Test(4)
t1.xxxx    ## 当__getattr__和__getattribute__同时存在时,找不存在的属性时,只会执行__getattribute__,
          ## 除非__getattribute__在执行过程中抛出异常AttributeError,则执行__getattr__
View Code

十一,双划线item方法

class Foo:
    def __getitem__(self, item):
        print('__getitem__')
        return self.__dict__[item]
    def __setitem__(self, key, value):
        print('__setitem__')
        self.__dict__[key] = value
    def __delitem__(self, key):
        print('__delitem__')
        self.__dict__.pop(key)
f1 = Foo()
f1['name'] = 'alex'  ## 执行__setitem__
f1['age'] = 18     ## 执行__setitem__

f1['name']     ## 执行__getitem__
print(f1['name'])   ## alex

print(f1.__dict__)   ## {'name': 'alex', 'age': 18}
del f1['name']      ## 执行__delitem__
print(f1.__dict__)   ##   {'age': 18}

##  用[]字典的方式调用时,触发item系列,用点调用时,触发attr方法
#!/usr/bin/env python
# -*- coding:utf8 -*-
# __author__ = 'glh'

from collections import namedtuple
Card = namedtuple('Card', ['rank', 'suit'])


class FranchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = ['红心', '方快', '梅花', '黑桃']

    def __init__(self):
        self.cards = [Card(rank, suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits]

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

    def __getitem__(self, item): return self.cards[item]

    def __setitem__(self, key, value):
        self.cards[key] = value


deck = FranchDeck()
# print(deck[0])
# print(deck)

# print(len(deck))

# for card in deck:
#     print(card)

from random import choice,shuffle
# print(deck[choice(range(len(deck.cards)))])
# print(deck[choice(range(len(deck.cards)))])

# print(choice(deck))# 这里依赖与类中实现__len__, __getitem__方法,其中一个要是没有实现,就不行

shuffle(deck)  # 这里依赖与类中实现__len__, __getitem__, __setitem__方法,其中一个要是没有实现,就不行
print(deck[0:10])
应用-纸牌游戏

十二,__str__ , __repr__ __, __format__方法

class Foo:
    def __init__(self,name):
        self.name = name
f1 = Foo('GOULONGHUI')
print(f1)     ### 显示<__main__.Foo object at 0x0000000001E295F8>

class Foo:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return '名字是%s'%self.name
f1 = Foo('GOULONGHUI')
print(f1)    ## 显示 名字是GOULONGHUI
__str__
# 用于python解释器中,直接使用f1查看,而————__str__使用print命令查看
class Foo:
    def __init__(self,name):
        self.name = name
    def __repr__(self):
        return '名字是%s'%self.name
f1 = Foo('GOULONGHUI')
print(f1)    ## 显示 名字是GOULONGHUI      先找__str__,找不到时,用__repr__替代


class Foo:
    def __init__(self,name):
        self.name = name
    def __str__(self):      ##  二者并存时,找__str__
        return '名字是%s'%self.name
    def __repr__(self):
        return '名字是%s'%self.name     ### 二者都必须return,且,return的必须是字符串,否则抛出异常

f1 = Foo('GOULONGHUI')
print(f1)   ##名字是GOULONGHUI
__repr__
format_dict = {
    'Y:M:D': '{0.year}:{0.month}:{0.day}',
    'Y-M-D': '{0.year}-{0.month}-{0.day}',
    'YMD': '{0.year}{0.month}{0.day}'
}
class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    def __format__(self, format_spec):
        # print(format_spec)
        if not format_spec or format_spec not in format_dict:
            format_spec = 'YMD'
        fm = format_dict[format_spec]
        return fm.format(self)

d1 = Date(2018,3,14)
format(d1,'Y:M:D')  ### 执行__format__ 属性
print(format(d1,'Y:M:D'))   ##  2018:3:14
print(format(d1,'Y-M-D'))   ## 2018-3-14
print(format(d1,'YMD'))   ### 2018314
print(format(d1))    ##### 2018314
print(format(d1,'sfsfsfsf'))## ### 2018314
__format__

 十三,__slots__方法

class Foo:
    __slots__ = ['name','age']

f1 = Foo()
f2 = Foo()
# f1.__dict__  ###  报错,slots 方法替代了__dict__
f1.name = 'alex'
print(f1.name)    ##  alex
f1.age = 18
print(f1.age)     ##  18
# f1.gender = 'women'  ##  只能调用slots设置的方法

f2 .name = 'goulognhui'
print(f2.name)
f2.age = 19
print(f2.age)    ##
View Code

__module__    p1.__module__   表示当前操作的对象p1在那个模块。

__class__        p1.__class__    表示当前操作的对象p1的类是什么。

十四,__call__ 方法

## __call__
class Foo:
    def __call__(self, *args, **kwargs):
        print('实例执行啦')

f1 = Foo()  ##  本质也是在调用产生类的那个大类下的__call__方法
f1()    ###  实例执行啦   # 加上 __call__方法后才能运行

十五,__len__ , __eq__,__hash__方法

# 2 内置函数的len函数时依赖类中的__len__
class Student:
    def __init__(self, name_list):
        self.name_list = name_list

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


s1 = Student(['gou', 'guan'])
print(len(s1))
__len__
# 3 __eq__ 判断值是否相等时,依赖__eq__的结果

#  应用:公司录入员工信息了,要是某个人入职时是一份工作,一段时间后又要换其他工作,
#         这时候又要在录一次信息,导致该员工信息录入多次

# class Person:
#     def __init__(self, name, sex, age):
#         self.name = name
#         self.sex = sex
#         self.age = age
#
#     def __eq__(self, other):
#         if type(self) == type(other) and \     # 验证type,必须是同一个类的实例对象比较
#                 self.name == other.name and\
#                 self.sex == other.sex:
#             return True
#         else:
#             return False


# p1 = Person('gou', 'nan', 18)
# p2 = Person('gou', 'nan', 20)
#
# print(p1 == p2)
__eq__
# 面试题
# 如果两个对象的name 和 sex相同,那么这两个对象就是相同的对象,创建100个对象,去掉相同的对象

class Person:
    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age

    def __hash__(self):
        return hash(self.name + self.sex)

    def __eq__(self, other):
        if type(self) == type(other) and \
                self.name == other.name and\
                self.sex == other.sex:
            return True
        else:
            return False


# person_list = [Person('gou', 'nan', i) for i in range(100)]
# print(set(person_list))

# 总结
# 集合去重,首先是比较2个值的哈希值是否相同,如果两个值的哈希值不同,表示不是重复的,直接储存,要是2个值的哈希值相同,
#       再去比较这两个值的 '值' 是否相同,如果不同,直接储存下来,
#       如果相同,会把其中一个值做一些处理(比如加上1等),让这两个值不同,储存下来.

# 比较2个对象的哈希值时,该对象的类中必须实现__hash__方法,才能比较
# 比较2个对象的值是否相同时,依赖__eq__的结果
__hash__和 __eq__应用(集合去重)

十六,__new__构造方法

1 # 一个类实例化的时候,先去调用的自己类中__new__(自己类中也是调用的object类)或者父类中的__new__构造方法,产生一个self实例对象,然后才会去执行自己的或者父类的__init__方法,给self实例每一个对象属性.
class A:
    def __init__(self):
        print('init')

    def __new__(cls, *args, **kwargs):
        print('new')
        self = object.__new__(cls)
        return self


# a = A()
# __new__   构造方法
# __init__  初始化方法
__new__
 1 # 创造一个类,这个类始终只有一个实例  --- 单例模式
 2 # 设计模式 --->  java开发过程中的一种规范或者设计范式
 3 # 单例模式就是一种最简单的设计模式
 4 
 5 # 什么是只有一个实例, 就是每次实例化创造的对象都是一块内存空间,就是不能开辟新的空间,只有一个空间
 6 class Foo:
 7     __instance = None
 8 
 9     def __init__(self, name):
10         self.name = name
11 
12     def __new__(cls, *args, **kwargs):
13         if not cls.__instance:
14             cls.__instance = object.__new__(cls)
15         return cls.__instance
16 
17 
18 # f1 = Foo('alex')  # 创造了一个实例
19 # f2 = Foo('egon')  # 第二次拿到的实例还是上一个实例,只是重新赋值了
20 # print(f1)  # <__main__.Foo object at 0x000001F55533FE10>
21 # print(f2)  # <__main__.Foo object at 0x000001F55533FE10>
22 # print(f1.name)  # egon
23 # print(f2.name)  # egon
单例模式-一种设计模式

十七,__del__析构方法

# __del__  析构方法
# 对应着一个对象的删除.

# 2个层面
# python解释器
#    能够主动回收不用的变量
#    在程序结束的时候所有的数据都会被清除
# 如果用户主动删除某个变量
#     那么这个变量就会主动的被清除
# 无论上述那种方式,再删除一个变量之前都会主动的执行析构方法 __del__

class B:
    def __del__(self):
        print('执行我了')


b = B()  # 这段程序运行结束,python垃圾回收,把b删除了,就执行了 __del__ 方法


手动删除
class B:
    def __del__(self):
        print('执行我了')


b = B()
del b  # 调用__del__方法,从内存中将b删除

# 实际应用
class B(object):
    def __init__(self, path):
        self.f = open(path)

    def __del__(self):
        print('执行我了')
        self.f.close()  # 删除之前做收尾工作,在这里比如删除文件句柄之前关闭文件


b = B('file')  # 垃圾回收时,或者手动删除对象,即文件句柄时,在__del__中把文件先关掉,
                    
del b

__del__ 析构方法
__del__ 析构方法

十八,迭代器协议

# class Foo:
#     def __init__(self,n):
#         self.n = n
#     def __iter__(self):
#         return self
#     def __next__(self):
#         if self.n == 3:
#             raise StopIteration('终止了')
#         self.n += 1
#         return self.n
#
# f1 = Foo(1)
# # print(f1.__next__())
# # print(f1.__next__())
# # print(f1.__next__())
#
# for i in f1:
#     print(i)
迭代器
class Fibo:
    def __init__(self):
        self._a = 1
        self._b = 1
    def __iter__(self):
        return self
    def __next__(self):
        if self._a >100:
            raise StopIteration('终止了')
        self._a,self._b = self._b,self._a + self._b   ##  同时进行
        return self._a
f1 =Fibo()
print(f1.__next__())
print(f1.__next__())
print(f1.__next__())
print(f1.__next__())
print('------->')
for i in f1:   # 接着上一个next循环下一个
    print(i)
实现斐波那契数列

十九,描述符 __get__ ,__set__, __delete__:

  • 描述符的本质就是一个新式类,在这个新式类中,至少实现了__get__ __set__ __delete__中的一个,也被称为描述符协议。
  • __get__() 调用一个属性是触发;__set__()为一个属性赋值时触发;__delete__()采用del删除属性时触发
  • 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的属性,不能定义到构造函数(初始化函数)中)

 注意:描述符分为数据描述符和非数据描述符,数据描述符至少实现了__get__ __set__ 方法,非数据描述符只有__get__ 方法

class Foo:
    def __get__(self, instance, owner):
        print('执行get')
    def __set__(self, instance, value):
        print('执行set')
    def __delete__(self, instance):
        print('执行delete')

class Bar:
    x = Foo()     ###  在另外的类中属性中,必须描述在类属性中
    # def __init__(self):
    #     self.x = 1       ##  这里实质也是在调用Foo里的set 描述符

b1 = Bar()
b1.x    ### 执行get   ##另外的类实例的对象 调用时运行
View Code
# class Foo:
#     def __get__(self, instance, owner):
#         print('执行get')
#     def __set__(self, instance, value):
#         print('执行set')
#     def __delete__(self, instance):
#         print('执行delete')
#
# class Bar:
#     x = Foo()

# ---------- 类属性大于数据描述符---------
# Bar.x = 1     # 设置了一个类属性 不执行__set__方法,类属性优先级高于数据描述符,
# print(Bar.__dict__)    ##  'x': 1
# print(Bar.x)    ##  1

# ------------- 数据描述符大于实例属性------

# b1 = Bar()
# b1.x  ###  执行get  #执行了__get__方法,数据描述符优先级高于实例属性
# print(b1.__dict__)  # 为空{}

# -------------实例描述符大于非数据描述符------------
# class Foo:
#     def __get__(self, instance, owner):
#         print('执行get')
#
# class Bar:
#     x = Foo()

# b1 = Bar()
# b1.x = 111111111111  ## 不执行__set__方法,因为非数据描述符中就没有__set__方法,
# print(b1.__dict__)   # 加到自己的属性字典了{'x': 111111111111}

#-----------------非数据描述符大于找不到触发__getattr__()方法
class Foo:
    def __get__(self, instance, owner):
        print('执行get')

class Bar:
    x = Foo()
    def __getattr__(self, item):
        print('__getattr__')
b1 = Bar()
b1.xxxxxxxxxxxxxxxxxxxxx   ## __getattr__  执行__getattr__方法
描述符的优先级

优先级:

  1. 类属性
  2. 数据描述符
  3. 实例属性
  4. 非数据描述符
  5. 找不到的属性触发__getattr__方法
posted @ 2018-03-08 00:46  Mr.GLH  阅读(372)  评论(0)    收藏  举报
Top↑