zoukankan      html  css  js  c++  java
  • Python基础学习(六)

    前几天一直在练手廖雪峰老师的python课程,接下来继续学习,由于面向对象编程这一课相对理论便不在此练手,直接上手面向对象高级编程。

    一、使用 __slots__

      一般情况下一个class是可以绑定一个属性和方法的,例如:

    #给实例绑定属性 和 方法
    #绑定属性
    class Student(object):
        pass
    
    s = Student()
    s.name = 'nihao'
    print(s.name)
    

      绑定方法:

    #绑定方法
    def setAge(self, a):
        self.age = a
    
    from types import MethodType
    s.setAge = MethodType(setAge, s)
    s.setAge(22)
    print( s.age )
    

      给一个实例绑定一个方法,对于另外一个实例是不起作用的

      例如:

    #给一个实例绑定一个方法,对于另外一个实例是不起作用的
    s2 = Student()
    #s2.setAge(11)
    

      说明:这里的s2.setAge(11)是会报错的。

      但是给class绑定方法后,所有实例均可调用

    #但是给class绑定方法后,所有实例均可调用
    def setScore(self, score):
        self.score = score
    
    Student.setScore = setScore
    
    s.setScore(11)
    print( s.score )
    
    s2.setScore(33)
    print( s2.score )
    

      其他的案例将函数写在class里面,任何实例都可以调用:

    class Test(object):
        def myFun(self, num):
            self.num = num
    
    t = Test()
    t.myFun(22)
    print(t.num)
    

      总结:可以给一个实例绑定方法和属性,但是另外一个实例调用是不起作用的,除非给class绑定一个方法,或者在class里面自定义一个方法,这样才会在所有的实例中都可以调用。

      使用__slots__

      说明:__slots__ 的英文单词是槽的意思,也就是一个位置的意思。占用一个坑。__slots__的好处是可以限定一个class的实例绑定属性的个数和指定属性的标准。

           比方说我限定了一个类只能在外部绑定哪些属性名称,通过__slots__定义的就可以使用 否则定义其他属性的 class 都不认识。

      案例:

    class Student(object):
        __slots__ = ('name', 'age') #用tuple定义允许绑定的属性名称
    
    s = Student()
    s.name = 'cici'
    print( s.name )
    s.age = '18'
    print( s.age )
    s.score = 100
    print( s.score )
    

      输出:

    cici
    18
    Traceback (most recent call last):
      File "/mnt/hgfs/webspace/pythonStudy/one.py", line 678, in <module>
        s.score = 100
    AttributeError: 'Student' object has no attribute 'score'
    

      由此可见,只有定义了属性名称,是可以做外部绑定的,没有定义的属性名称,是绑定不成功的。

      另外需要注意的是:__slots__只对当前类起作用,对于继承的子类是不起作用的。

    二、使用@property

      通常我们通过实例去给一个实例绑定一个属性,或者修改属性的值,显然很不安全,可以通过如下案例实现:

    class Student(object):
    
        def getScore(self):
            return self._score
    
        def setScore(self, val):
            if not isinstance(val, int):
                raise ValueError('请输入整型')
            if val <0 or val> 100:
                raise ValueError('范围要在0-100直间')
            self._score = val
    
    
    s = Student()
    
    s.setScore(44)
    print( s.getScore() )
    

      说明:由此可见,通过设置方法,去设置参数,再通过另外一个方法去获取参数。明显比较安全些,但是这种写法稍微复杂了一点,要调用两个方法才行

      python恰好有一个即可以验证参数,有可以像普通绑定属性这样简单的方式,那就是python内置的@property装饰器 装饰器就是负责把一个方法变成属性调用的形式:
      案例:

    class Student(object):
    
        @property
        def score(self):
            return self._score
    
        @score.setter
        def score(self, val):
            if not isinstance(val, int):
                raise ValueError('score is integer')
            elif val <0 or val >100:
                raise ValueError('0-100')
            self._score = val
    
    
    s = Student()
    s.score = 90
    
    print(s.score)
    

      输出:90

      说明:要将一个getter方法变成属性一样的调用,只需要加上@property就可以了,另外 @property 本身又创建了一个装饰器@score.setter 负责把一个setter方法变成属性赋值,这样就可以得到一个可控的属性操作了。

    三、定制类

      在python中类似__xxx__的变量或则函数名说明它们是拥有特殊用途的函数。

      例如:

      __str__

      案例:

    class Student(object):
        def __init__(self, name):
            self.name = name
    
    print( Student('cici') )
    

      输出:<__main__.Student object at 0x7fd703484940>

      说明:由此可见,这种输出是非常不好看的,改一下

    class Student(object):
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return 'Student object (name: %s)' % self.name
    
    print( Student('cici') )
    

      输出:Student object (name: cici)

      由此可见,__str__()方法是可以返回一个好看的字符串的,而且还可以看出实例内部的数据。

      __iter__ 

    class Fib(object):
        def __init__(self):
            self.a, self.b = 0, 1 #初始化两个计数器
    
        def __iter__(self):
            return  self #实例本身就是迭代对象
    
        def __next__(self):
            self.a, self.b = self.b,  self.a+self.b #计算下一个值
            if self.a > 20: #退出循环的条件
                raise StopIteration()
            return self.a #返回下一个值
    
    for item in Fib():
        print(item)
    

      输出:

    1
    1
    2
    3
    5
    8
    13
    

      说明:如果一个类想要被for ... in ... 循环,类似list 或 tuple ,就必须实现一个__iter__() 方法 返回它自己,改方法返回一个迭代对象,然后,python 的 for 循环将会不间断的调用该迭代对象的 __next__() 方法,拿到循环的下一个值,直到遇到 StopIteration 错误时退出。

         __getitem__

      上面定义的Fib实例虽然可以作用于for循环,看起来类似list,但是它并不能类似list一样去使用,比如取值的时候:  

    class Fib(object):
        def __getitem__(self, item):
            a,b = 1,1
            for x in range(item):
                a, b = b, a+b
            return a
    
    print(Fib()[0])
    print(Fib()[1])
    print(Fib()[2])
    print(Fib()[3])
    print(Fib()[4])
    print(Fib()[5])
    

      输出:

    1
    1
    2
    3
    5
    8
    

      说明:由此可见,若要将一个实例像list那样调用按照下标取元素,需要在定义一个__getitem__()方法。

      注意: list 有一个切片方法,但是用在类里面会报错,这是由于__getitem__()传入的参数有可能是一个int 也有可能是一个切片的对象slice,所以需要做判断:

      __getattr__

      一般情况下,如果我们调用一个类的方法或者属性,如果不存在,就会报错,例如:

    class Student(object):
    
        def __init__(self):
            self.name = 'cici'
    
    s = Student()
    print( s.name )
    print( s.score )
    

      输出:

    cici
    Traceback (most recent call last):
      File "/mnt/hgfs/webspace/pythonStudy/one.py", line 771, in <module>
        print( s.score )
    AttributeError: 'Student' object has no attribute 'score'
    

      说明:由此可见,调用 name 的时候没有问题,而调用 score的时候说Student没有找score的元素

      通过__getattr__控制

    class Student(object):
    
        def __init__(self):
            self.name = 'cici'
    
        def __getattr__(self, item):
            if item == 'score':
                return 100
    
    s = Student()
    print( s.name )
    print( s.score )
    print( s.aaaaa )
    

      输出:

    cici
    100
    None
    

      说明:由此可见,在类中增加了一个__getattr__ 可以自定义输出的属性,另外在次访问不存在的属性或时会友好的返回None

      __call__

      一个对象实例可以有自己的属性和方法,当我们调用实例方法时使用 instance.method() 来调用,能不能直接在实例本身上调用呢?案例

      例如:

    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            return self.name
    
    s = Student('cici')
    print( s() )
    

      输出:‘cici'

      说明:由此可见,如果像调用实例本身 s() 其实是可以调用成功的,因为这类中我们已经定义了一个__call__()方法,这样就实现了调用实例就好像调用函数一样的效果。

         那么问题就来了,如果区分它是一个对象,还是一个函数呢?更多时候,我们需要判断一个对象是否能够被调用,能够被调用的对象就是一个Callable对象

      例如:  

    print( callable(Student) )
    

      返回:True

      所以、通过callable()函数,就可以判断这个对象是否是 可调用的 对象。

    四、使用枚举类

      定义一个枚举

    from enum import Enum, unique
    Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
    
    for name, member in Month.__members__.items():
        print(name, '=>', member, ',', member.value)
    

      输出:

    Jan => Month.Jan , 1
    Feb => Month.Feb , 2
    Mar => Month.Mar , 3
    Apr => Month.Apr , 4
    May => Month.May , 5
    Jun => Month.Jun , 6
    Jul => Month.Jul , 7
    Aug => Month.Aug , 8
    Sep => Month.Sep , 9
    Oct => Month.Oct , 10
    Nov => Month.Nov , 11
    Dec => Month.Dec , 12
    

      访问枚举的方法

    @unique
    class Weekday(Enum):
        Sun = 0  # Sun的value被设定为0
        Mon = 1
        Tue = 2
        Wed = 3
        Thu = 4
        Fri = 5
        Sat = 6
    
    #访问这些枚举类型的方法
    day1 = Weekday.Mon
    print( day1 )
    print( day1.value )
    print( Weekday['Thu'])
    print( Weekday['Thu'].value)
    print( Weekday(2) )
    

      输出:

    Weekday.Mon
    1
    Weekday.Thu
    4
    Weekday.Tue
    

      可见,既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。

    五、使用元类

      。。。

       

      

  • 相关阅读:
    linux内存不足时,为了防止报错,可以使用swap
    Linux SWAP 深度解读
    tomcat启用apr需要的三个组件(缺少可能会报错)
    阿里云无法ping通解决
    linux安装jdk环境
    linux下如何彻底删除mysql
    如何让百度收录自己的网站
    [SWF]在线预览文档下载
    [C#]线程处理
    [C#]关键字
  • 原文地址:https://www.cnblogs.com/dump/p/9592989.html
Copyright © 2011-2022 走看看