python-study-23

学习总结

封装:外部不能直接使用,内部开接口
property:将方法伪装成数据,可以不加括号直接用
绑定:绑定(对象,类),非绑定

封装(方法,数据):
1 数据封装 提供接口,附加逻辑
2 方法封装 隔离复杂度

property(方法):注意方法名一样
property        查看
name.setter   修改
name.deleter  删除

方法(绑定 非绑定):

绑定:1 对象 默认  2 类 classmethod(配置文件读配置)
非绑定: staticmethod   (uuid.uuid1())
View Code

复习

上节课复习:
    1、组合
        什么是组合?
            一个类的对象具备某一个属性
            该属性的值是指向另外一个类的对象的
            class Foo:
                pass

            class Bar:
                pass

            obj_of_foo=Foo()
            obj_of_bar=Bar()
            obj_of_foo.attrib=obj_of_bar

            obj_of_foo.attrib.xxx

        为何用组合?
            是为了减少类与类直接的代码冗余


    2、菱形继承问题之新式类与经典的区别
        A(B,C,D)
        在属性查找方面
        新式类:广度优先查找
        经典类:深度优先查找

    3、继承的实现原理
        c3算法
        mro列表
    4、在子类派生的新方法中重用父类功能的两种方式
        指名道姓(与继承无关):类名.函数名(该传几个传几个)
        super(自己的类名,self).父类的属性:严格依赖继承,super()会得到一个特殊的对象
                                            该对象专门从当前的父类开始往后查找


    5、多态
        多态指的是同一种事物的多种形态,比如水有冰、水蒸气、雪
        多态性:
            指的是继承同一个父类的子类,具有相同的方法名
            在使用的时候,子类的对象可以在不用考虑其具体数据类型的前提下
            而直接调用的方法
        import abc
        class Foo(metaclass=abc.ABCMeta):
            @abc.abstractmethod
            def func1(self):
                pass

        class Bar(Foo):
            def func1(self):
                pass

        强调:父类不能实例化,子类要想实例化则必须实现与父类同名的方法

        python中崇尚“鸭子类型”


今日内容:
    1、封装
        1.1 如何隐藏属性
        1.2 封装的真实意图与用法
        1.3 property

    2、绑定方法与非绑定方法
View Code

封装

'''
1、什么是封装
    封:属性对外是隐藏的,但对内是开放的
    装:申请一个名称空间,往里装入一系列名字/属性

2、为什么要封装
    封装数据属性的目的
        首先定义属性的目的就是为了给类外部的使用使用的,
        隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
        然后让类外部的使用通过接口来间接地操作隐藏的属性。
        精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作

    封装函数属性
        首先定义属性的目的就是为了给类外部的使用使用的,
        隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口
        然后在接口内去调用隐藏的功能
        精髓在于:隔离了复杂度



3、如何封装

'''
# 如何隐藏:在属性前加上__开头


#1、 这种隐藏仅仅只是一种语法上的变形操作
#2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
#3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是
#    在类定义阶段,类体内代码统一发生了一次变形

#4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头


# class People:
#     __country='China' #_People__country='China'
#     __n=100 #_People__n=100
#     def __init__(self,name,age,sex):
#         self.__name=name #self._People__name=name
#         self.age=age
#         self.sex=sex
#
#     def eat(self):
#         print('eat.....')
#         print(People.__country) #People._People__country
        # print(self.__name) #self._People__name

# People.eat(123)
# print(People.__country)

# peo1=People('egon',18,'male')
# peo1.eat()
# print(peo1.__name)

# print(People.__dict__)
# print(People.__country)
# print(People._People__country)

# People.__x=11
# print(People.__dict__)


# peo1=People('egon',18,'male')
# print(peo1.__dict__)
# peo1.__x=111
# print(peo1.__dict__)

# class Foo:
#     def __f1(self): #_Foo__f1
#         print('Foo.f1')
#
#     def f2(self):
#         print('Foo.f2')
#         self.__f1() #self._Foo__f1
#
# class Bar(Foo):
#     def __f1(self): #_Bar__f1
#         print('Bar.f1')
#
# obj=Bar()
# obj.f2()


# class People:
#     def __init__(self,name,age):
#         self.__name=name
#         self.__age=age
#
#     def tell_info(self):
#         print('%s:%s' %(self.__name,self.__age))
#
#     def set_info(self,name,age):
#         if type(name) is not str:
#             # print('用户名必须为str类型')
#             # return
#             raise TypeError('用户名必须为str类型')
#
#         if type(age) is not int:
#             # print('年龄必须为int类型')
#             # return
#             raise TypeError('年龄必须为int类型')
#         self.__name=name
#         self.__age=age
#
# peo1=People('egon',18)
# peo1.name=123
# peo1.age
# peo1.tell_info()
#
# peo1.set_info('egon',19)
# peo1.tell_info()
View Code

特性

#property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接引用
# class People:
#     def __init__(self,name,weight,height):
#         self.name=name
#         self.weight=weight
#         self.height=height
#
#     @property
#     def bmi(self):
#         return self.weight / (self.height ** 2)
#
# peo1=People('egon',75,1.8)
#
# peo1.height=1.85
# print(peo1.bmi)


'''
class People:
    def __init__(self,name):
        self.__name=name

    @property # 查看obj.name
    def name(self):
        return '<名字是:%s>' %self.__name

    @name.setter #修改obj.name=值
    def name(self,name):
        if type(name) is not str:
            raise TypeError('名字必须是str类型傻叉')
        self.__name=name

    @name.deleter #删除del obj.name
    def name(self):
        # raise PermissionError('不让删')
        print('不让删除傻叉')
        # del self.__name

peo1=People('egon')
# print(peo1.name)

# print(peo1.name)

# peo1.name='EGON'
# print(peo1.name)

del peo1.name

'''


class People:
    def __init__(self,name):
        self.__name=name


    def tell_name(self):
        return '<名字是:%s>' %self.__name

    def set_name(self,name):
        if type(name) is not str:
            raise TypeError('名字必须是str类型傻叉')
        self.__name=name

    def del_name(self):
        print('不让删除傻叉')

    name=property(tell_name,set_name,del_name)


peo1=People('egon')

print(peo1.name)
peo1.name='EGON'
print(peo1.name)
del peo1.name
View Code

绑定方法与非绑定方法

'''
1、绑定方法
    特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
         《《《精髓在于自动传值》》》

    绑定方法分为两类:
        1.1 绑定给对象方法
            在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的
        1.2 绑定给类的方法:
            在类内部定义的函数如果被装饰器@classmethod装饰,
            那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入

2、非绑定方法
    类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法
    既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
    但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数

3 应用
    如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法
    如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法
    如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数


'''

# class Foo:
#     @classmethod
#     def f1(cls):
#         print(cls)
#
#     def f2(self):
#         print(self)


# obj=Foo()
# print(obj.f2) #obj
# print(Foo.f1) #Foo
#
# Foo.f1()
# print(Foo)


#1、f1绑定给类的
# 了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类
# print(Foo.f1)
# print(obj.f1)
# Foo.f1()
# obj.f1()

#2、f2是绑定给对象的
# obj.f2()
# Foo.f2(obj)

import settings
import uuid

class Mysql:
    def __init__(self,ip,port):
        self.uid=self.create_uid()
        self.ip=ip
        self.port=port

    def tell_info(self):
        print('%s:%s' %(self.ip,self.port))

    @classmethod
    def from_conf(cls):
        return cls(settings.IP, settings.PORT)

    @staticmethod
    def func(x,y):
        print('不与任何人绑定')

    @staticmethod
    def create_uid():
        return uuid.uuid1()

# 默认的实例化方式:类名(..)
obj=Mysql('10.10.0.9',3307)

# 一种新的实例化方式:从配置文件中读取配置完成实例化
obj1=Mysql.from_conf()
obj1.tell_info()

obj.func(1,2)
Mysql.func(3,4)
print(obj.func)
print(Mysql.func)

print(obj.uid)
View Code
1、定义MySQL类(参考答案:http://www.cnblogs.com/linhaifeng/articles/7341177.html#_label5)

  1.1.对象有id、host、port三个属性

  1.2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一

  1.3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化

  1.4.为对象定制方法,save和get_obj_by_id,save能自动将对象序列化到文件中,文件路径为配置文件中DB_PATH,文件名为id号,保存之前验证对象是否已经存在,若存在则抛出异常,;get_obj_by_id方法用来从文件中反序列化出对象

2、定义一个类:圆形,该类有半径,周长,面积等属性,将半径隐藏起来,将周长与面积开放
    参考答案(http://www.cnblogs.com/linhaifeng/articles/7340801.html#_label4)


3、明日默写
    1、简述面向对象三大特性:继承、封装、多态
    2、定义一个人的类,人有名字,身高,体重,用property讲体质参数封装成人的数据属性
    3、简述什么是绑定方法与非绑定方法,他们各自的特点是什么?
作业
###1 author--oneself
import settings
import uuid
import json
import os

class Mysql:
    def __init__(self,host,port):
        self.uid=self.create_uid()
        self.host=host
        self.port=port

    @staticmethod  #为每个对象随机生成id
    def create_uid():
        return uuid.uuid1()

    @classmethod
    def from_conf(cls): #从配置文件中读取host和port进行实例化
        return cls(settings.HOST, settings.PORT)

    def save(self):
        user_dic = {'host':self.host,'port':self.port}
        user_path = os.path.join(settings.DB_PATH,'%s.json' %self.uid)
        if os.path.exists(user_path):
            raise FileExistsError('文件已存在')
        with open(user_path,'w',encoding='utf-8') as f:
            json.dump(user_dic,f)
            f.flush()
            print('save successful')

    # def get_obj_by_id(self):
    #     user_path = os.path.join(settings.DB_PATH, '%s.json' % self.uid)
    #     with open(user_path,encoding='utf-8') as f:
    #         return json.load(f)

    @staticmethod
    def get_obj_by_id(id):
        user_path = os.path.join(settings.DB_PATH,id)
        with open(user_path,encoding='utf-8') as f:
            return json.load(f)

# mysql1 = Mysql.from_conf()
# mysql2 = Mysql('3.3.3.3','88')
#
# mysql1.save()
# mysql2.save()

# print(mysql1.get_obj_by_id())
# print(mysql2.get_obj_by_id())

obj1 = Mysql.get_obj_by_id('2d197874-7ac6-11e8-915c-68f728b8340c.json')
print(obj1)






###2
# import math
#
#
# class circle:  # radius   #perimeter   #area
#     def __init__(self, radius):
#         self.__radius = radius
#
#     @property
#     def perimeter(self):
#         return 2 * math.pi * self.__radius
#     @property
#     def area(self):
#         return math.pi * self.__radius ** 2
#
# c1 = circle(3)
# print(c1.perimeter)
# print(c1.area)

##1
# 继承:新建类,遗传属性,减少代码冗余,新式类,经典类
# 封装:对内开放,对外隐藏,外部不能直接使用,调用接口,附加逻辑,隔离复杂度
# 多态:同一事物,不通形态,同一父类的子类,相同的方法名, 使用时子类的对象可以在不用考虑其具体数据类型的前提下,直接调用方法

##2
# class People:
#     def __init__(self,name,height,weight):
#         self.name=name
#         self.height=height
#         self.weight=weight
#
#     @property
#     def bmi(self):
#         return self.weight / (self.height ** 2)
#
# p1 = People('xjj',1.78,68)
# print(p1.bmi)

##3
# 绑定方法:自动传值   1 对象绑定(默认) 2 类绑定(@classmethod)
# 非绑定方法: 没有自动传值 @staticmethod 普通函数,都可以调用
View Code
原文地址:https://www.cnblogs.com/xujinjin18/p/9240222.html