美文网首页
python面向对象编程进阶(7)

python面向对象编程进阶(7)

作者: 纳米君 | 来源:发表于2018-04-24 00:37 被阅读10次
    1. 对类的属性可以做出一些限制,需声明__slots__属性。
      一般情况下,只限制类自身属性。当存在继承关系时,分情况如下:
      子父类都有该属性,那么父类受自身影响,子类继承父类的限制,双重影响;
      父类有该属性,子类没有,那么父类受自身影响,子类不受影响;
      子类有该属性,父类没有,那么父类和子类都不受影响。

    2. 针对私有变量,简化getter、setter方法。

    3. 对一些方法(比如__str____repr__ 等等)的用途作出简单介绍。

    直接看例子和注释:

    class Person:
        # 限制Person类只能有name、age属性,注意是tuple类型
        __slots__ = ('name', 'age')
    
        # print(p)调用该方法,如果不自定义__str__方法,会输出<__main__.Person object at 0x00000000028DBB38>
        # 自定义之后,就可以输出指定格式了。
        def __str__(self):
            return 'Person object (name: %s)' % self.name
    
        # 命令行执行p后,会调用该方法
        __repr__ = __str__
    
        def do(self):
            print('person...')
    
    
    class Student(Person):  
        __slots__ = ('sex',)
    
    
    p = Person()
    p.name = 'tom'
    print(p.name)
    print(p)
    
    s = Student()
    s.age = 23
    print(s.age)
    
    
    class Teacher:
    
        def __init__(self, name):
            self._name = name
    
        # 简化getter方法,针对私有变量
        @property
        def name(self):
            # _name不能和函数名同名,即不能写成self.name
            return self._name
    
        # 简化setter方法,声明@property之后,就会有@函数名.setter装饰器
        @name.setter
        def name(self, name):
            if isinstance(name, str):
                self._name = name
            else:
                raise ValueError('str is required')
    
    
    t = Teacher('fuck')
    print(t.name)
    t.name = 'tom'
    print(t.name)
    

    继承时,主线一般都是单一继承下来。当需要扩展功能时,只需设计额外的功能类,多重继承即可。这种设计一般称为MixIn。比如:

    #会跑
    class RunnableMixIn:
        def do(self):
            print('run...')
    
    #会飞
    class FlyMixIn:
        def do(self):
            print('fly...')
    
    #多重继承,当父类中至少有两个父类拥有同样的方法时,子类调用该方法时遵循拓扑排序。关于拓扑排序会在下一篇当中专门介绍。
    class My(Person, FlyMixIn, RunnableMixIn):
        pass
    
    
    m = My()
    m.do()
    

    如果想把对象定义成像list一样操作数据,需定义下面几个方法:

    # 斐波那契数列
    class Fib:
    
      def __init__(self):
         self.a = 0
         self.b = 1
    
      # 当需要迭代对象时,需要定义__iter__和__next__方法
      def __iter__(self):
          return self
    
      def __next__(self):
          self.a, self.b = self.b, self.a + self.b
          return self.a
    
      # 当需要和list一样用下标取值时,需要定义__getitem__方法
      # item可能是下标,也可能是slice对象,当需要和list一样使用切片时,需做一下判断
      # 如果把对象看成dict,item就看成是key
      def __getitem__(self, item):
         if isinstance(item, int):
             a, b = 1, 1
             for i in range(item):
                 a, b = b, a + b
             return a
         elif isinstance(item, slice):
             # start stop可能为负数,这里暂时只考虑正数
            start = item.start
            if start is None:
              start = 0
            stop = item.stop
            value = []
            a, b = 1, 1
            for i in range(stop):
                if i >= start:
                  value.append(a)
                a, b = b, a + b
            # 每几个取一个
            step = item.step
            new_value = []
            if step is not None and step != 1:
                for i in range(len(value)):
                    if i * step < len(value) - 1:
                        new_value.append(value[i * step])
                return new_value
            else:
                return value
    
      # 给对象进行赋值的方法
      def __setitem__(self, key, value):
          pass
    
      # 删除对象某个元素的方法
      def __delitem__(self, key):
          pass
    
      # 当我们get对象中不存在的属性时,会报错,自定义__getattr__方法可以对没定义的属性进行赋值
      # 如果该属性已经定义了,该方法针对该属性的赋值就无效
      def __getattr__(self, item):
          if item == 'c':
              return 100
    
    for v in Fib():
      if v < 100:
          print(v)
      else:
          break
    
    print(Fib()[2])
    print(Fib()[:10])
    print(Fib()[:10:2])
    print(Fib().c)
    

    链式调用,定义__getattr__()和__call__()方法,利于组装url

    class Chain:
    
          def __init__(self, path=''):
              self._path = path
    
          # 当实例.属性不存在时,调用该方法
          def __getattr__(self, path):
              return Chain('%s/%s' % (self._path, path))
    
          def __str__(self):
              return self._path
    
          __repr__ = __str__
    
          # 对象实例()会调用该方法
          def __call__(self, args):
              return Chain('%s/%s' % (self._path, args))
    
    
    print(Chain().status.user.timeline.list) --> 结果:/status/user/timeline/list
    print(Chain().users('michael').repos) --> 结果:/users/michael/repos
    # callable(obj) 判断obj是否是callable,class中必须要有__call__方法,部分函数例外
    print(callable(Chain())) --> 结果:True
    print(callable([1, 2])) --> 结果:False
    print(callable(max)) --> 结果:True
    

    type()函数可以查看变量或者函数的类型。

    # 类型是class type
    print(type(Chain))
    # 类型是class Chain
    print(type(Chain()))
    

    type(args1, args2, args3)函数还可以可以创建类。

    args1: 类名
    args2: 父类tuple
    args3: 类中方法名绑定方法
    一般采用class Xxx声明类,Python解释器遇到class定义时,只是扫描一下class定义的语法,然后调用type()方法创建class,所以动态语言Python本身支持运行期动态创建class。

    def fn(self, name='233'):
        print('name: %s' % name)
    
    # 创建类
    Test = type('Test', (object,), dict(test=fn))
    # name: HelloTest
    Test().test('HelloTest')

    相关文章

      网友评论

          本文标题:python面向对象编程进阶(7)

          本文链接:https://www.haomeiwen.com/subject/dxawkftx.html