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

  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')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容