封装、特性property、绑定方法(classmethod)与非绑定方法(staticmethod)

    1、组合
        什么是组合?
            一个类的对象具备某一个属性

            该属性的值是指向另外一个类的对象的 

class Foo:
    pass
class Bar:
    pass
obj_of_foo=Foo()
obj_of_bar=Bar()

obj_of_foo.attrib=obj_of_bar # .attrib是将obj_of_bar属性赋予给obj_of_foo

 

obj_of_foo.attrib.xxx  # 此时的obj_of_foo属性为obj_of_bar,又可以将该属性赋予给其它值

为何用组合?

    是为了减少类与类直接的代码冗余

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

    经典类:深度优先查找(python2)

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.什么是封装

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

2.为什么要封装

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

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

1.这种隐藏仅仅只是语法上的变形操作
2.这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只有类定义阶段检测一次
3.这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是在类定义阶段,类体代码统一发生了一次变形
4.如果不想让子类的方法覆盖父类的,可以将该方法前加一个__开头

class People:
    __country='country'
    def __init__(self,name,age,sex):
        self.__name=name
        self.__age=age
        self.__sex=sex
    def eat(self):
        print(self.__name)
        print(self.__age)
        print(self.__sex)
        print(People.__country)
peo1=People('egon',18,'male')
peo1.eat
class People:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
    def tall_info(self):
        print('%s:%s'%(self.__name,self.__age))
    def set_info(self,name,age):
        if type(name) is not str:
            raise TyperError('用户名必需为str类型')
        if type(age) is not int:
            raist TyperError('密码必需为int类型')
peo1=People('egon',18)
peo1.set_info('egon',18)#如果更改的值没有对应set_info所规定的 就会报错相应的提示

特性property

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.78)
print(peo1.bmi) # 有装饰器
print(peo1.bim()) # 无装饰器

property的常用两种方式:以下两种方式均为同一种效果↑↓

# 方式一
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
    def name(self):
        raise PermissionError('名字无法删除')

peo1=People('egon')
peo1.name=333#报错提示:名字必需为str类型
del peo1.name#报错提示:名字无法删除 
# 方式二
class People:
    def __init__(self,name):
        self.__name=name
    
    def tell_name(self):
        return '>>>%s报道了<<<'%sself.name

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

    def del_name(self):
        raise PermissionError('名字无法删除的,大兄弟')
        #print('名字无法删除的,大兄弟')

    name=property(tell_name,set_name,del_name)

peo1=People('egon')
peo1.name=333#报错提示:名字需为str类型
del peo1.name#报错提示:名字无法删除

 

绑定方法与非绑定方法

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)
print(Foo.f1)

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

class Mysql:

    def __init__(self,ip,port):
        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)

obj=Mysql.from_conf()
obj.tell_info()
import settings
import uuid

class Mysql:
    def __init__(self,ip,port):
        self.ip=ip
        self.port=port
        self.uid=self.create_uid()
    
    def tell_info(self):
        print('%s:%s'%(self.ip,self.port))

    @classmethod
    def from_conf(cls):
        return cls(settings.IP,settings.PORT)
    
    @staticmethod
    def cread_udi():
        return uuid.uuid1()

obj=Mysql.from_conf()
obj.from_conf() # 将settings文件中的IP,PORT显示出来,且如果settings模块文件中数据变动与显示是同步的
obj.cread_udi # 通过uuid模块来算出不同的Id

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值