咸糖记录编程的地方

念念不忘,必有回响。

目录
cook book 类与对象 3
/  

cook book 类与对象 3

我又来了 昨天写了好多的例子 有些还是很模糊
所以今天对昨天的学习成果进行一个小小的总结

##使用super

class Base:
    def __init__(self):
        print("base.__init__")


class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')


class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')



class C(A,B):
    # pass
    def __init__(self):
        super().__init__()
        print("C.__init__")

# son will be check before father
c=C()
base.__init__
B.__init__
A.__init__
C.__init__

当你使用super时候 python 会从MRO表中搜索下一个类

你可以看到无法在类A中使用super 会调用和类A无关的spam方法


class Base:
    def __init__(self):
        print("base.__init__")


class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')


class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')



class C(A,B):
    # pass
    def __init__(self):
        super().__init__()
        print("C.__init__")
# son will be check before father
c=C()

主要也是由于C 的MRO表的结构为

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<class 'object'>)

在调用a的spam方法时候使用super会搜寻B的spam方法

##子类中扩展property

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

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,value):
        if not isinstance(value,str):
            raise TypeError("expected a sting")
        self._name=value

    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")

class SubPerson(Person):
    @property
    def name(self):
        print("Getting name")
        return  super().name

    @name.setter
    def name(self,value):
        print("setting name to",value)
        super(SubPerson,SubPerson).name.__set__(self,value)

    @name.deleter
    def name(self):
        super(SubPerson,SubPerson).name.__delete__(self)

没有理解 只了解到这个方法能通过子类修改父类属性

##创建描述器

描述器主要是以__get__ set __delete__为核心的类

class Integer:
    def __init__(self,name):
        self.name=name
        self.dd="jb"
    def __get__(self, instance, owner):

        if instance is None:
            return self

        else:
            print(instance.__dict__[self.name])
            return instance.__dict__[self.name]
#
#     #in case  to set x's value  will to come __set__ function
    def __set__(self, instance, value):
        # print(instance.__dict__)
        if  isinstance(value,int):
            instance.__dict__[self.name] = value

        elif isinstance(value,str):
            instance.__dict__[self.dd]=value
            # print(instance.__dict__)
        else:

            raise  TypeError("Expected an int")

    def __delete__(self, instance):
        del instance.__dict__[self.name]
        # input a instance
#
class Point:
    # put descriptor in class
    x = Integer('x')
    y = Integer('y')

    def __init__(self,x,y):
        self.x = x
        self.y = y

p=Point(2,3)
p.x="23234"
print(p.__dict__)
print(p.jb)


#C:\Users\战神皮皮迪\AppData\Local\Programs\Python\Python35\python.exe C:/Users/战神皮皮迪/PycharmProjects/cookbook/ClassAndInstance/create_new_class_and_instance.py
#{'y': 3, 'jb': '23234', 'x': 2}
23234

可以发现传入的实例是当前的实例,而不是类的成员,所以可以通过修改__set__方法去设置值

如果用类的变量去访问描述器 那么标准做法就是去返回自身即可

##使用延时计算属性 重要

我这里记录了一种比较常用的
使用的是描述类

class lazyproperty:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        if instance is None:
            return self
        else:
            values=self.func(instance)
            setattr(instance,self.func.__name__,values)
            return values
import math
class Circle:
    def __init__(self,radius):
        self.radius=radius

    @lazyproperty
    def area(self):
        print("computing area")
        return  math.pi*self.radius**2

    @lazyproperty
    def perimeter(self):
        print("computing perimeter")
        return 2*math.pi * self.radius



c = Circle(4.0)
print(c.area)

主要思想是在描述器类只有__get__方法时 对于属性的绑定会变弱 只有当目标属性不在底层字典的时候才会
触发

不信的话可以测试一下

class lazyproperty:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        if instance is None:
            return self
        else:
            values=self.func(instance)
            setattr(instance,self.func.__name__,values)
            return values


    def __set__(self, instance, value):
        # setattr(instance,self.func.__name__,value)
        super().__setattr__(self.func.__name__,value)

我们设置了__set__方法
会发现

#C:\Users\战神皮皮迪\AppData\Local\Programs\Python\Python35\python.exe C:/Users/战神皮皮迪/PycharmProjects/cookbook/ClassAndInstance/create_new_class_and_instance.py
#{'radius': 4.0}
#computing area
#50.26548245743669
#{'radius': 4.0}
#computing area
#50.26548245743669

触发了两次输出 表示描述器对属性的绑定增强

##简化数据结构的初始化
一般可以用来对于实体类进行编写
但是这个小节对我来说收获的不只是这个
而是明白了
加了星号(**)的变量名会存放所有未命名的变量参数
并且这写参数可以通过遍历进行设置值

import math
#可以用作对实体类的编写
class Structure1:

    _fields=[]

    def __init__(self,*args):
        if len(args) != len(self._fields):
            raise  TypeError('Expected {} arguments'.format(len(self._fields)))

        for name,value in zip(self._fields,args):
            setattr(self,name,value)

class Stracture2:
    _fields=[]

    def __init__(self,*args,**kwargs):
        print(kwargs)

        if len(args) > len(self._fields):
            raise  TypeError('Expected {} arguments'.format(len(self._fields)))

        for name,value in zip(self._fields,args):
            setattr(self,name,value)

        for name in  self._fields[len(args):]:
            #pop a value from dict
            setattr(self,name,kwargs.pop(name))
        if kwargs:
            raise TypeError('Invalid argument(s): {}'.format(','.join(kwargs)))

class Stock(Stracture2):
    _fields = ['name','shares','price']


class Points(Structure1):
    _fields = ['x','y']


class Circle(Structure1):
    _fields = ['radius']

    def area(self):
        return math.pi*self.radius**2
#
import sched
##指定参数传入
s3=Stock('ACME', shares=50, price=91.1)
print(s3.price)

————————————更新一下 舒服一哈———–6/16————–
##定义接口和基类

我们可以通过定义接口来判断类的类型
进行类型检查
抽象类无法被实例化

from abc import ABCMeta, abstractclassmethod

class IStream(metaclass=ABCMeta):
    @abstractclassmethod
    def read(self,maxbytes=-1):
        pass

    @abstractclassmethod
    def write(self,data):
        pass

class SocketStream(IStream):
    def read(self,maxbytes=-1):
        pass
    def write(self,data):
        pass

def serialize(stream):
    if not isinstance(stream,IStream):
        raise TypeError("Expected an IStream")
    pass
#
a=SocketStream()
serialize(a)

标题:cook book 类与对象 3
作者:xiantang
地址:http://xiantang.info/articles/2019/06/03/1559551066898.html

评论