Python面向对象编程

1 面向对象编程概念总结

面向过程的编程是为了解决问题而一步步的按照流水线的方法进行编程,编程实现相对容易,但可扩展性较差,因为往往牵一发动全身。
面向对象的编程是注重概括和提炼,先将需求提炼为类(类里有初始化函数、数据属性和函数属性);然后再通过具体对象使用类的这些资源,即实例化。
学习面向对象编程需要了解面向对象设计的核心本质思想,透过现象看本质,理解了面向对象设计的概念,使用类和对象进行面向对象的编程自然水到渠成。

2 python中关于OOP的常用术语

2.1 抽象/实现

抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型的数据属性,还定义了这些数据的接口。
对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明而且无关的。

2.2 封装/接口

封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。通过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员允许这些操作。作为实现的 一部分,客户端根本就不需要知道在封装之后,数据属性是如何组织的。在Python中,所有的类属性都是公开的,但名字可能被“混淆”了,以阻止未经授权的访问,但仅此而已,再没有其他预防措施了。这就需要在设计时,对数据提供相应的接口,以免客户程序通过不规范的操作来存取封装的数据属性。
注意:封装绝不是等于“把不想让别人看到、以后可能修改的东西用private隐藏起来”
真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明
(注意:对外透明的意思是,外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在)

2.3 合成

合成扩充了对类的 述,使得多个不同的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,比如一个类由其它类组成,更小的组件也可能是其它的类,数据属性及行为, 所有这些合在一起,彼此是“有一个”的关系。

2.4 派生/继承/继承结构

派生描述了子类衍生出新的特性,新类保留已存类类型中所有需要的数据和行为,但允许修改或者其它的自定义操作,都不会修改原类的定义。
继承描述了子类属性从祖先类继承这样一种方式
继承结构表示多“代”派生,可以述成一个“族谱”,连续的子类,与祖先类都有关系。

2.5 泛化/特化

基于继承
泛化表示所有子类与其父类及祖先类有一样的特点。
特化描述所有子类的自定义,也就是,什么属性让它与其祖先类不同。

2.6 多态与多态性

多态指的是同一种事物的多种状态:水这种事物有多种不同的状态:冰,水蒸气
多态性的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。
冰,水蒸气,都继承于水,它们都有一个同名的方法就是变成云,但是冰.变云(),与水蒸气.变云()是截然不同的过程,虽然调用的方法都一样

2.7 自省/反射

自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像__dict__,name__及__doc

3 面向对象编程实现

3.1 类与对象实例化

class Human:    #类以class开头,类名一般习惯首字母大写
    def __init__(self,name,age,sex):    #这是初始化函数,对象实例化的时候对象p1或p2将传入self
        self.name = name
        self.age = age
        self.sex = sex
        #类的初始化函数默认return none,在定义类初始化函数的时候请不要return,引用类的时候首先会为类执行初始化函数。
    home = 'earth'    #类的数据属性
    def study_knowledge(self):    #类的函数属性
        print( '%s is studying' %self.name )
    def play_ball(self):
        print( '%s is play' %self.name )

p1 = Human('张三',18,'man')    #实例化 对象引用类
p2 = Human('李四',31,'man')

3.2 类的特殊属性

#python为类内置的特殊属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

3.3 类的增删改查

class Human:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    home = 'earth'
    def study_knowledge(self):
        print( '%s is studying' %self.name )
    def play_ball(self):
        print( '%s is play' %self.name )

#1. 实例化
p1 = Human('张三',18,'man')
p2 = Human('王五',31,'man')

#2. 增加类的数据属性
Human.base = 'water'
print(Human.base)

#3. 修改类的数据属性
Human.home = 'universe'
print(Human.home)

#4. 删除类的数据属性
print(Human.__dict__)
del Human.home
print(Human.__dict__)

#5. 增加类的函数属性
def Fly_plane(self,plane):
    print('%s 在开%s' %(self.name,plane))
Human.Fly = Fly_plane
Human.Fly(p1,'F22')
p2.Fly('J20')

#6. 修改类的函数属性
def test(self):
    print('test')
Human.play_ball = test
p1.play_ball()

#7. 删除类的函数属性
del Human.play_ball
print(Human.__dict__)

#8. 特殊方法增加类的数据属性
#全局变量中已经有x和y的变量定义
x=11
y=22
Human.x = 10
Human.y =20

3.4 实例属性的增删改查

class Human:
    def __init__(self,name):
        self.name = name
    home = 'earth'
    def study_knowledge(self):
        print( '%s is studying' %self.name )
    def play_ball(self):
        print( '%s is play' %self.name )

#1. 实例化
p1 = Human('张三')
print(p1.__dict__)

#2. 查看实例的属性
print(p1.name)
print(p1.play_ball)
p1.play_ball()

#3. 增加实例的数据属性
p1.age = 18
print(p1.__dict__)
print(p1.age)

#增加实例的函数属性(了解并忘记)
#实例没有函数属性,实例的函数属性是调用类的函数属性
def test(self):
    print('我是实例的函数')
p1.test = test
print(p1.__dict__)
print(p1.test)
p1.test(p1) #违反class的语法原则,所以此处需要传入实例p1
#class只有实例在调类的方法的时候才会自动传入self参数

#不要修改底层的字典结构(了解原理即可)
p1.__dict__['sex']='man'
print(p1.__dict__)
print(p1.sex)

#4. 修改实例属性
p1.age=22
print(p1.age)

#5. 删除实例属性
del p1.age
print(p1.__dict__)

3.5 静态属性

#静态属性既可以访问实例的属性,也可以访问类的属性。
class Home:
    x = 1
    def __init__(self,name,owner,long,width):
        self.name = name
        self.ower = owner
        self.long = long
        self.width = width
    @property
    def cal_area(self):
        return self.long * self.width

p1 = Home('畅春园','康熙',1000,600)

p1.cal_area
print(p1.cal_area)

3.6 类方法

#类方法可以访问类的数据属性和类的函数属性,但是不能访问实例属性。
class Home:
    tag = 100
    def __init__(self,name,owner,long,width):
        self.name = name
        self.ower = owner
        self.long = long
        self.width = width
    @classmethod
    def tell_info(cls):
        print(cls)
        print(cls.tag)

Home.tell_info()

3.7 静态方法

#静态方法只是名义上归属类管理,不能使用类属性或者实例属性,只是类的工具包。
class Home:
    tag = 100
    def __init__(self,name,owner,long,width):
        self.name = name
        self.ower = owner
        self.long = long
        self.width = width
    @staticmethod
    def test(a,b,c):
        print('%s %s %s在吃饭' %(a,b,c))

Home.test('小名','小黄','小李')

3.8 组合

class Hand:
    pass

class Foot:
    pass

class Trunk:
    pass

class Head:
    pass

class Person:
    def __init__(self,id_num,name):
        self.id_num=id_num
        self.name=name
        self.hand=Hand()
        self.foot=Foot()
        self.trunk=Trunk()
        self.head=Head()
p1=Person('111111','alex')

print(p1.__dict__)
class School:
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr


    def zhao_sheng(self):
        print('%s 正在招生' %self.name)

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



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


# c1=Course('linux',10,'1h',s1)

msg='''
1 Test 北京校区
2 Test 南京校区
3 Test 东京校区
'''
while True:
    print(msg)
    menu={
        '1':s1,
        '2':s2,
        '3':s3
    }
    choice=input('选择学校>>: ')
    school_obj=menu[choice]
    name=input('课程名>>: ')
    price=input('课程费用>>: ')
    period=input('课程周期>>: ')
    new_course=Course(name,price,period,school_obj)
    print('课程【%s】属于【%s】学校' %(new_course.name,new_course.school.name))

3.9 继承

3.9.1 继承举例

class Dad:
    '这个是爸爸类'
    money=10
    def __init__(self,name):
        print('爸爸')
        self.name=name
    def hit_son(self):
        print('%s 正在打儿子' %self.name)

class Son(Dad):
    money = 1000000000009
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def hit_son(self):
        print('来自儿子类')
# print(Son.money)
# Son.hit_son()
# print(Dad.__dict__)
# print(Son.__dict__)
s1=Son('alex',18)
s1.hit_son()
# print(s1.money)
# print(Dad.money)
# print(s1.name)
# print(s1.money)
# print(s1.__dict__)
# s1.hit_son()

3.9.2 接口继承

#基类的接口没必要实现内部逻辑,它只是用来规范子类的。
#基类接口类没必要实例化。
import abc
class All_file(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def read(self):
        pass

    @abc.abstractmethod
    def write(self):
        pass

class Disk(All_file):
    def read(self):
        print('disk read')

    def write(self):
        print('disk write')

class Cdrom(All_file):
    def read(self):
        print('cdrom read')

    def write(self):
        print('cdrom write')


class Mem(All_file):
    def read(self):
        print('mem read')

    def write(self):
        print('mem write')
#
m1=Mem()
m1.read()
m1.write()

3.9.3 继承顺序

Python中子类可以同时继承多个父类,如类A可以同时继承B、C、D三个类。
经典类按照深度优先的顺序查找(Python2中默认是经典类,如果Python2要实现新式类,需要在类中继承object);
新式类按照广度优先的顺序查找(python3中默认就是新式类);
F.mro() #等同于F.mro,可以通过这个方法查看新式类的继承顺序。

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

3.10 子类调用父类的方法

3.10.1 明确指出父类名字

不推荐该方法,扩展性不强。

class Vehicle:
    Country='China'
    def __init__(self,name,speed,load,power):
        self.name=name
        self.speed=speed
        self.load=load
        self.power=power
    def run(self):
        print('开动啦')
        print('开动啦')
class Subway(Vehicle):
        def __init__(self,name,speed,load,power,line):
           Vehicle.__init__(self,name,speed,load,power)
           self.line=line

        def show_info(self):
            print(self.name,self.speed,self.load,self.power,self.line)

        def run(self):
            Vehicle.run(self)
            print('%s %s 线,开动啦' %(self.name,self.line))
line13=Subway('北京地铁','10km/s',1000000000,'电',13)

line13.show_info()

line13.run()

3.10.2 super调用不需指明父类名字

推荐该方法,可扩展性强。

class Vehicle1:
    Country='China'
    def __init__(self,name,speed,load,power):
        self.name=name
        self.speed=speed
        self.load=load
        self.power=power
    def run(self):
        print('开动啦')
        print('开动啦')
class Subway(Vehicle1):
        def __init__(self,name,speed,load,power,line):
           # Vehicle.__init__(self,name,speed,load,power)
           super().__init__(name,speed,load,power)  #super(__class__,self).__init__(name,speed,load,power)
           #super(Subway,self).__init__(name,speed,load,power)
           self.line=line
        def show_info(self):
            print(self.name,self.speed,self.load,self.power,self.line)
        def run(self):
            # Vehicle.run(self)
            super().run()
            print('%s %s 线,开动啦' %(self.name,self.line))
line13=Subway('北京地铁','10km/s',1000000000,'电',13)
line13.show_info()
line13.run()

print(line13.__class__)

3.11 多态的好处

1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
class H2O:
    def __init__(self,name,temperature):
        self.name=name
        self.temperature=temperature
    def turn_ice(self):
        if self.temperature < 0:
            print('[%s]温度太低结冰了' %self.name)
        elif self.temperature > 0 and self.temperature < 100:
            print('[%s]液化成水' %self.name)
        elif self.temperature > 100:
            print('[%s]温度太高变成了水蒸气' %self.name)
    def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(self):
        pass

class Water(H2O):
    pass
class Ice(H2O):
    pass
class Steam(H2O):
    pass

w1=Water('水',25)
i1=Ice('冰',-20)
s1=Steam('蒸汽',3000)

# w1.turn_ice()
# i1.turn_ice()
# s1.turn_ice()

def func(obj):
    obj.turn_ice()

func(w1)  #---->w1.turn_ice()
func(i1)  #---->i1.turn_ice()
# def func(obj):
#     obj.turn_ice()
#
# func(w1)
# func(i1)
# func(s1)

3.12 封装

3.12.1 引言

从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,一起装进麻袋,然后把麻袋封上口子。照这种逻辑看,封装=‘隐藏’,这种理解是相当片面的。

3.12.2 封装如何实现隐藏

#其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
#类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,
#这种,在外部是无法通过__x这个名字访问到。

3.12.3 一个封装案例

#_*_coding:utf-8_*_
__author__ = 'laoshi'

class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high

    def tell_area(self): #此时我们想求的是面积
        return self.__width * self.__length *self.__high

    def tell_width(self):
        return self.__width


r1=Room('卧室','xiaogou',100,100,10000)

print(r1.tell_area())  
# 实际是arear=r1.__width * r1.__length,

#总结封装的好处是(个人理解):
1)外部看不到内部参数,起到隐藏的作用;
2)内部调整不影响外部用户使用的方法,内部调整不影响外部;

3.13 反射

反射的好处:
1、相互依赖的模块在编程时可以互不影响进度。
2、可以动态导入模块。

反射在Python中的作用是对Python代码的自省,四个可以适用于Python自省的函数如下,下列方法适用于类和对象。

#以下方法同样适用于类
hasattr(object,name)   #判断object中有没有一个name字符串对应的方法或属性,结果是布尔值
getattr(object,name,'none')    #相当于object.name
setattr(x,y,v)    #相当于x.y=v
delattr(x,y)    #相当于del x
#四个自省方法的使用演示
class BlackMedium:
    feture='Ugly'
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_hourse(self):
        print('【%s】 正在卖房子,' %self.name)

    def rent_hourse(self):
        print('【%s】 正在租房子' % self.name)


print(hasattr(BlackMedium,'feture'))
getattr()
#
# b1=BlackMedium('盖世无双','天露园')
# b1.name--->b1.__dic__['name']
# print(b1.__dict__)
#
# # b1.name
# # b1.sell_hourse
# print(hasattr(b1,'name'))
# print(hasattr(b1,'sell_hourse'))
# print(hasattr(b1,'selasdfasdfsadfasdfasdfasdfasdl_hourse'))
#
#
#
# print(getattr(b1,'name'))
# print(getattr(b1,'rent_hourse'))
# func=getattr(b1,'rent_hourse')
# func()
# # print(getattr(b1,'rent_hourseasdfsa')) #没有则报错
# print(getattr(b1,'rent_hourseasdfsa','tag')) #有tag这个位置的字符则不会报错,显示tag
#
#
# # b1.sb=True
# setattr(b1,'sb',True)
# setattr(b1,'sb1',123)
# setattr(b1,'name','SB')
# setattr(b1,'func',lambda x:x+1)
# setattr(b1,'func1',lambda self:self.name+'sb')
# print(b1.__dict__)
# print(b1.func)
# print(b1.func(10))
# print(b1.func1(b1))
# del b1.sb
# del b1.sb1
# delattr(b1,'kd')
# print(b1.__dict__)
# -*- coding: utf-8 -*-
#!/bin/bash/env python
# 小张和小李共同完成一个FTP项目,小张做客户端,小李做服务端,小李请假了,还想不影响小张客户端的代码编写,就需要使用到反射。

# 小张的服务端代码
class Ftpserver:
    def __init__(self,addr):
        self.addr = addr
        print('正在连接FTP服务器%s' %self.addr)

# 小李的客户端代码
F1 = Ftpserver('192.168.31.1')
if hasattr(f1, 'get'):
    func_get = getattr(f1, get)
    func_get()
else:
    print('其他逻辑')
# 检测其他模块test的方法。
import test as obj

print(obj)

print(hasattr(obj,'say_hi'))
print(hasattr(obj,'say_hisssssssssssssssssssssssssssssssssssssssssss'))

if hasattr(obj,'say_hi'):
    func=getattr(obj,'say_hi')
    func()
else:
    print('其他的逻辑')

x=111
y=222

#检查自己模块fanshe的x方法是否存在。
# import fanshe as obj1
import sys
obj1=sys.modules[__name__]

print('===>',hasattr(obj1,'x'))

3.13.1 动态模块导入

#约定目录结构:
#模块所在目录1:/test/aaa/x.py
#模块所在目录2:/test/y.py
#使用模块的Python文件所在目录:/test/study.py
#要导入同级别文件件下的模块的方法:import y
#要导入同级别子文件件下的模块的方法:from aaa import x
#如果是通过字符串给的字符串模块名,要导入字符串的模块名的方法:__import__('y')
#如果是通过字符串给的字符串模块名,要导入字符串的模块名的方法:module = __import__('aaa.x')  
#注意此时导入的不是aaa目录下的x模块,而是aaa模块,如果要使用,需要如下操作:module.x.test()  #test是x模块中的一个函数功能。
#如上如果需要导入子目录下的字符串模块需要使用如下方法:m = importlib.import_module('aaa.x')    #拿到的是aaa下的x模块

# 注意如果x.py 中第一个函数是test1,第二个函数是 _test2
from aaa import *
test1()
_test2()   #这个执行会报错,因为*不能导入_开头的隐藏函数,如果想要使用隐藏函数,则需要导入的时候明确from aaa import test1,_test2

3.13.2 __开头的attr属性

#__开头的attr是实例取函数的时候会使用的到。
#__开头的attr原理介绍
# class Foo:
#     x=1
#     def __init__(self,y):
#         self.y=y
#
#     def __getattr__(self, item):
#         print('执行__getattr__')
#
# f1=Foo(10)
# print(f1.y)
# print(getattr(f1,'y'))   #len(str)--->str.__len__()
# f1.sssssssssssssssssssssssssssssssssssss


# class Foo:
#     x=1
#     def __init__(self,y):
#         self.y=y
#
#     def __delattr__(self, item):
#         print('删除操作__delattr__')
#
# f1=Foo(10)
# del f1.y
# del f1.x

#
# class Foo:
#     x=1
#     def __init__(self,y):
#         self.y=y
#
#     def __setattr__(self, key, value):
#         print('__setattr__执行')
#         # self.key=value
#         self.__dict__[key]=value
# f1=Foo(10)
# print(f1.__dict__)
# f1.z=2
# print(f1.__dict__)
# class Foo:
#     def __getattr__(self, item):
#         print('------------->')
#
# # print(Foo.__dict__)
# print(dir(Foo))
# f1=Foo()
#
# print(f1.x)  #只有在属性不存在时,会自动触发__getattr__
#
# del f1.x #删除属性时会触发_delattr__
#
# f1.y=10
# f1.x=3  # 设置属性的时候会触发——setattr———
### 3.13.3 __开头attr的应用场景
class Foo:
    def __init__(self,name):
        self.name=name
    def __getattr__(self, item):
        print('你找的属性【%s】不存在' %item)
    def __setattr__(self, k,v):
        print('执行setattr',k,v)
        if type(v) is str:
            print('开始设置')
            # self.k=v #触发__setattr__,导致不断递归下去,所以这步操作不能这么写,得如下方法写。
            self.__dict__[k]=v.upper()
        else:
            print('必须是字符串类型')
    def __delattr__(self, item):
        print('不允许删除属性【%s】' %item)
        # print('执行delattr',item)
        # del self.item  #触发__deltattr__,导致不断递归下去,所以这步操作不能这么写,得如下方法写。
        #self.__dict__.pop(item)

f1=Foo('alex')
# f1.age=18 #触发__setattr__
# print(f1.__dict__)
# print(f1.name)
# print(f1.age)
# print(f1.gender)
# print(f1.slary)
print(f1.__dict__)
del f1.name
print(f1.__dict__)

3.14 二次封包

#包装是对已经存在的类的功能定制和扩展
class List(list):
    def append(self, p_object):
        if type(p_object) is str:
            # self.append(p_object)
            super().append(p_object)
        else:
            print('只能添加字符串类型')

    def show_midlle(self):
        mid_index=int(len(self)/2)
        return self[mid_index]


# l2=list('hell oworld')
# print(l2,type(l2))

l1=List('helloworld')
# print(l1,type(l1))
# print(l1.show_midlle())
l1.append(1111111111111111111111)
l1.append('NB')
print(l1)
# 授权就是对所有新功能使用新的类来处理,所有已经存在功能授权给对象的默认属性
import time
class FileHandle:
    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):
        print('------------>',line)
        t=time.strftime('%Y-%m-%d %X')
        self.file.write('%s %s' %(t,line))

    def __getattr__(self, item):
        # print(item,type(item))
        # self.file.read
        return getattr(self.file,item)

f1=FileHandle('a.txt','w+')
# print(f1.file)
# print(f1.__dict__)
# print('==>',f1.read) #触发__getattr__
# print(f1.write)
f1.write('1111111111111111\n')
f1.write('cpu负载过高\n')
f1.write('内存剩余不足\n')
f1.write('硬盘剩余不足\n')
# f1.seek(0)
# print('--->',f1.read())

3.15 isinstance和issubclass

class Botany:
    pass

class Tree(Botany):
    pass

tree1 = Botany()
tree2 = Tree()

print(isinstance(tree1,Botany))  #判断实例tree1是否是类Botany实例化而来的。
print(isinstance(tree2,Botany)) #判断实例是否是某父类的子类。
print(issubclass(Tree,Botany))  #判断Tree是否是Botany的子类。
print(type(tree1))  #查看一个实例的类是谁。

3.16 iterm知识

#通过 f1.x方式调用是匹配的attr方法,通过f1['x']方式调用是匹配的iterm方法。
class Foo:
    def __getitem__(self, item):
        print('getitem',item)
        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()
print(f1.__dict__)
# f1.name='egon'  #---->setattr-------->f1.__dict__['name']='egon'
f1['name']='egon'#--->setitem--------->f1.__dict__['name']='egon'
f1['age']=18

print('===>',f1.__dict__)

# del f1.name
# print(f1.__dict__)
#
# print(f1.age)
del f1['name']
print(f1.__dict__)

print(f1['age'])
raise S

3.17 改变对象的字符串显示


#默认list类显示
l=list('hello')
print(l)
#默认句柄显示为对象。
file=open('test.txt','w')
print(file)

#自定义字符串显示str。
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return '名字是%s 年龄是%s' %(self.name,self.age)

f1=Foo('jet',18)
print(f1) #str(f1)--->f1.__str__()

x=str(f1)
print(x)

y=f1.__str__()
print(y)
#自定义字符串显示repo
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    # def __str__(self):
    #     return '折是str'
    def __repr__(self):
        return '名字是%s 年龄是%s' %(self.name,self.age)

f1=Foo('jet',19)
#在Python解释器中直接查看f1时使用的是repo,repr(f1)---->f1.__repr__()
#使用print查看f1时调用的是str,如果找不到才使用repo。
print(f1) #str(f1)---》f1.__str__()------>f1.__repr__()

3.18 自定义format格式

#笨办法
x='{0}{0}{0}'.format('dog')

print(x)

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day
d1=Date(2016,12,26)

x='{0.year}{0.mon}{0.day}'.format(d1)
y='{0.year}:{0.mon}:{0.day}'.format(d1)
z='{0.mon}-{0.day}-{0.year}'.format(d1)
print(x)
print(y)
print(z)
#进阶办法
format_dic={
    'ymd':'{0.year}{0.mon}{0.day}',
    'm-d-y':'{0.mon}-{0.day}-{0.year}',
    'y:m:d':'{0.year}:{0.mon}:{0.day}'
}
class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day
    def __format__(self, format_spec):
        print('自定义的format执行了')
        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(2016,12,26)
# format(d1) #d1.__format__()
# print(format(d1))
print(format(d1,'ymd'))
print(format(d1,'y:m:d'))
print(format(d1,'m-d-y'))
print(format(d1,'m-d:y'))
print('===========>',format(d1,'asd'))

3.19 slots属性

#慎用
#slots的优缺点:
#优点:节省内存,所有实例都使用同一块内存空间;
#缺点:每个实例只能使用类的slots规定的key,不够灵活;
class Foo:
    __slots__=['name','age']  #{'name':None,'age':None}
    # __slots__='name' #{'name':None,'age':None}

f1=Foo()
# f1.name='egon'
# print(f1.name)

# f1.age=18  #--->setattr----->f1.__dict__['age']=18

# print(f1.__dict__)
print(Foo.__slots__)
print(f1.__slots__)
f1.name='jet'
f1.age=17
print(f1.name)
print(f1.age)
# f1.gender='male'


f2=Foo()
print(f2.__slots__)
f2.name='tom'
f2.age=18
print(f2.name)
print(f2.age)

3.20 doc属性

#doc属性是类的描述信息,无法继承。
class Foo:
    '我是Foo描述信息'
    pass

class Bar(Foo):
    pass

print('Foo:%s' %Foo.__doc__)
print(Bar.__doc__) #该属性无法继承给子类

3.21 module和class属性

__module__ 表示当前操作的对象在那个模块
__class__     表示当前操作的对象的类是什么
#在同级的目录下的lib目录下的aa.py文件内容如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class C:
    def __init__(self):
        self.name = ‘NB'
#在同级目录下的py文件里引用aa模块
from lib.aa import C

obj = C()
print obj.__module__  # 输出 lib.aa,即:输出模块
print obj.__class__      # 输出 lib.aa.C,即:输出类

3.22

posted @ 2020-04-19 16:26  IamJet  阅读(253)  评论(0编辑  收藏  举报