面向对象进阶

在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。

@property装饰器

之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效。我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下所示。

  1. class Person(object):
  2.  
  3. def __init__(self, name, age):
  4. self._name = name
  5. self._age = age
  6.  
  7. # 访问器 - getter方法
  8. @property
  9. def name(self):
  10. return self._name
  11.  
  12. # 访问器 - getter方法
  13. @property
  14. def age(self):
  15. return self._age
  16.  
  17. # 修改器 - setter方法
  18. @age.setter
  19. def age(self, age):
  20. self._age = age
  21.  
  22. def play(self):
  23. if self._age <= 16:
  24. print('%s正在玩飞行棋.' % self._name)
  25. else:
  26. print('%s正在玩斗地主.' % self._name)
  27.  
  28. def main():
  29. person = Person('王大锤', 12)
  30. person.play()
  31. person.age = 22
  32. person.play()
  33. # person.name = '白元芳' # AttributeError: can't set attribute
  34.  
  35. if __name__ == '__main__':
  36. main()

__slots__魔法

我们讲到这里,不知道大家是否已经意识到,Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。

  1. class Person(object):
  2.  
  3. # 限定Person对象只能绑定_name, _age和_gender属性
  4. __slots__ = ('_name', '_age', '_gender')
  5.  
  6. def __init__(self, name, age):
  7. self._name = name
  8. self._age = age
  9.  
  10. @property
  11. def name(self):
  12. return self._name
  13.  
  14. @property
  15. def age(self):
  16. return self._age
  17.  
  18. @age.setter
  19. def age(self, age):
  20. self._age = age
  21.  
  22. def play(self):
  23. if self._age <= 16:
  24. print('%s正在玩飞行棋.' % self._name)
  25. else:
  26. print('%s正在玩斗地主.' % self._name)
  27.  
  28. def main():
  29. person = Person('王大锤', 22)
  30. person.play()
  31. person._gender = '男'
  32. # AttributeError: 'Person' object has no attribute '_is_gay'
  33. # person._is_gay = True

静态方法和类方法

之前,我们在类中定义的方法都是对象方法,也就是说这些方法都是发送给对象的消息。实际上,我们写在类中的方法并不需要都是对象方法,例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。我们可以使用静态方法来解决这类问题,代码如下所示。

  1. from math import sqrt
  2.  
  3. class Triangle(object):
  4.  
  5. def __init__(self, a, b, c):
  6. self._a = a
  7. self._b = b
  8. self._c = c
  9.  
  10. @staticmethod
  11. def is_valid(a, b, c):
  12. return a + b > c and b + c > a and a + c > b
  13.  
  14. def perimeter(self):
  15. return self._a + self._b + self._c
  16.  
  17. def area(self):
  18. half = self.perimeter() / 2
  19. return sqrt(half * (half - self._a) *
  20. (half - self._b) * (half - self._c))
  21.  
  22. def main():
  23. a, b, c = 3, 4, 5
  24. # 静态方法和类方法都是通过给类发消息来调用的
  25. if Triangle.is_valid(a, b, c):
  26. t = Triangle(a, b, c)
  27. print(t.perimeter())
  28. # 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数
  29. # print(Triangle.perimeter(t))
  30. print(t.area())
  31. # print(Triangle.area(t))
  32. else:
  33. print('无法构成三角形.')
  34.  
  35. if __name__ == '__main__':
  36. main()

和静态方法比较类似,Python还可以在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象,代码如下所示。

  1. from time import time, localtime, sleep
  2.  
  3. class Clock(object):
  4. """数字时钟"""
  5.  
  6. def __init__(self, hour=0, minute=0, second=0):
  7. self._hour = hour
  8. self._minute = minute
  9. self._second = second
  10.  
  11. @classmethod
  12. def now(cls):
  13. ctime = localtime(time())
  14. return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)
  15.  
  16. def run(self):
  17. """走字"""
  18. self._second += 1
  19. if self._second == 60:
  20. self._second = 0
  21. self._minute += 1
  22. if self._minute == 60:
  23. self._minute = 0
  24. self._hour += 1
  25. if self._hour == 24:
  26. self._hour = 0
  27.  
  28. def show(self):
  29. """显示时间"""
  30. return '%02d:%02d:%02d' % \
  31. (self._hour, self._minute, self._second)
  32.  
  33. def main():
  34. # 通过类方法创建对象并获取系统时间
  35. clock = Clock.now()
  36. while True:
  37. print(clock.show())
  38. sleep(1)
  39. clock.run()
  40.  
  41. if __name__ == '__main__':
  42. main()

类之间的关系

简单的说,类和类之间的关系有三种:is-a、has-a和use-a关系。

  • is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
  • has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
  • use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。

我们可以使用一种叫做UML(统一建模语言)的东西来进行面向对象建模,其中一项重要的工作就是把类和类之间的关系用标准化的图形符号描述出来。关于UML我们在这里不做详细的介绍,有兴趣的读者可以自行阅读《UML面向对象设计基础》一书。

利用类之间的这些关系,我们可以在已有类的基础上来完成某些操作,也可以在已有类的基础上创建新的类,这些都是实现代码复用的重要手段。复用现有的代码不仅可以减少开发的工作量,也有利于代码的管理和维护,这是我们在日常工作中都会使用到的技术手段。

继承和多态

刚才我们提到了,可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。下面我们先看一个继承的例子。

  1. class Person(object):
  2. """人"""
  3.  
  4. def __init__(self, name, age):
  5. self._name = name
  6. self._age = age
  7.  
  8. @property
  9. def name(self):
  10. return self._name
  11.  
  12. @property
  13. def age(self):
  14. return self._age
  15.  
  16. @age.setter
  17. def age(self, age):
  18. self._age = age
  19.  
  20. def play(self):
  21. print('%s正在愉快的玩耍.' % self._name)
  22.  
  23. def watch_av(self):
  24. if self._age >= 18:
  25. print('%s正在观看爱情动作片.' % self._name)
  26. else:
  27. print('%s只能观看《熊出没》.' % self._name)
  28.  
  29. class Student(Person):
  30. """学生"""
  31.  
  32. def __init__(self, name, age, grade):
  33. super().__init__(name, age)
  34. self._grade = grade
  35.  
  36. @property
  37. def grade(self):
  38. return self._grade
  39.  
  40. @grade.setter
  41. def grade(self, grade):
  42. self._grade = grade
  43.  
  44. def study(self, course):
  45. print('%s的%s正在学习%s.' % (self._grade, self._name, course))
  46.  
  47. class Teacher(Person):
  48. """老师"""
  49.  
  50. def __init__(self, name, age, title):
  51. super().__init__(name, age)
  52. self._title = title
  53.  
  54. @property
  55. def title(self):
  56. return self._title
  57.  
  58. @title.setter
  59. def title(self, title):
  60. self._title = title
  61.  
  62. def teach(self, course):
  63. print('%s%s正在讲%s.' % (self._name, self._title, course))
  64.  
  65. def main():
  66. stu = Student('王大锤', 15, '初三')
  67. stu.study('数学')
  68. stu.watch_av()
  69. t = Teacher('骆昊', 38, '老叫兽')
  70. t.teach('Python程序设计')
  71. t.watch_av()
  72.  
  73. if __name__ == '__main__':
  74. main()

子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。

  1. from abc import ABCMeta, abstractmethod
  2.  
  3. class Pet(object, metaclass=ABCMeta):
  4. """宠物"""
  5.  
  6. def __init__(self, nickname):
  7. self._nickname = nickname
  8.  
  9. @abstractmethod
  10. def make_voice(self):
  11. """发出声音"""
  12. pass
  13.  
  14. class Dog(Pet):
  15. """狗"""
  16.  
  17. def make_voice(self):
  18. print('%s: 汪汪汪...' % self._nickname)
  19.  
  20. class Cat(Pet):
  21. """猫"""
  22.  
  23. def make_voice(self):
  24. print('%s: 喵...喵...' % self._nickname)
  25.  
  26. def main():
  27. pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
  28. for pet in pets:
  29. pet.make_voice()
  30.  
  31. if __name__ == '__main__':
  32. main()

在上面的代码中,我们将Pet类处理成了一个抽象类,所谓抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,DogCat两个子类分别对Pet类中的make_voice抽象方法进行了重写并给出了不同的实现版本,当我们在main函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。

综合案例

案例1:奥特曼打小怪兽

  1. from abc import ABCMeta, abstractmethod
  2. from random import randint, randrange
  3.  
  4. class Fighter(object, metaclass=ABCMeta):
  5. """战斗者"""
  6.  
  7. # 通过__slots__魔法限定对象可以绑定的成员变量
  8. __slots__ = ('_name', '_hp')
  9.  
  10. def __init__(self, name, hp):
  11. """初始化方法
  12.  
  13. :param name: 名字
  14. :param hp: 生命值
  15. """
  16. self._name = name
  17. self._hp = hp
  18.  
  19. @property
  20. def name(self):
  21. return self._name
  22.  
  23. @property
  24. def hp(self):
  25. return self._hp
  26.  
  27. @hp.setter
  28. def hp(self, hp):
  29. self._hp = hp if hp >= 0 else 0
  30.  
  31. @property
  32. def alive(self):
  33. return self._hp > 0
  34.  
  35. @abstractmethod
  36. def attack(self, other):
  37. """攻击
  38.  
  39. :param other: 被攻击的对象
  40. """
  41. pass
  42.  
  43. class Ultraman(Fighter):
  44. """奥特曼"""
  45.  
  46. __slots__ = ('_name', '_hp', '_mp')
  47.  
  48. def __init__(self, name, hp, mp):
  49. """初始化方法
  50.  
  51. :param name: 名字
  52. :param hp: 生命值
  53. :param mp: 魔法值
  54. """
  55. super().__init__(name, hp)
  56. self._mp = mp
  57.  
  58. def attack(self, other):
  59. other.hp -= randint(15, 25)
  60.  
  61. def huge_attack(self, other):
  62. """究极必杀技(打掉对方至少50点或四分之三的血)
  63.  
  64. :param other: 被攻击的对象
  65.  
  66. :return: 使用成功返回True否则返回False
  67. """
  68. if self._mp >= 50:
  69. self._mp -= 50
  70. injury = other.hp * 3 // 4
  71. injury = injury if injury >= 50 else 50
  72. other.hp -= injury
  73. return True
  74. else:
  75. self.attack(other)
  76. return False
  77.  
  78. def magic_attack(self, others):
  79. """魔法攻击
  80.  
  81. :param others: 被攻击的群体
  82.  
  83. :return: 使用魔法成功返回True否则返回False
  84. """
  85. if self._mp >= 20:
  86. self._mp -= 20
  87. for temp in others:
  88. if temp.alive:
  89. temp.hp -= randint(10, 15)
  90. return True
  91. else:
  92. return False
  93.  
  94. def resume(self):
  95. """恢复魔法值"""
  96. incr_point = randint(1, 10)
  97. self._mp += incr_point
  98. return incr_point
  99.  
  100. def __str__(self):
  101. return '~~~%s奥特曼~~~\n' % self._name + \
  102. '生命值: %d\n' % self._hp + \
  103. '魔法值: %d\n' % self._mp
  104.  
  105. class Monster(Fighter):
  106. """小怪兽"""
  107.  
  108. __slots__ = ('_name', '_hp')
  109.  
  110. def attack(self, other):
  111. other.hp -= randint(10, 20)
  112.  
  113. def __str__(self):
  114. return '~~~%s小怪兽~~~\n' % self._name + \
  115. '生命值: %d\n' % self._hp
  116.  
  117. def is_any_alive(monsters):
  118. """判断有没有小怪兽是活着的"""
  119. for monster in monsters:
  120. if monster.alive > 0:
  121. return True
  122. return False
  123.  
  124. def select_alive_one(monsters):
  125. """选中一只活着的小怪兽"""
  126. monsters_len = len(monsters)
  127. while True:
  128. index = randrange(monsters_len)
  129. monster = monsters[index]
  130. if monster.alive > 0:
  131. return monster
  132.  
  133. def display_info(ultraman, monsters):
  134. """显示奥特曼和小怪兽的信息"""
  135. print(ultraman)
  136. for monster in monsters:
  137. print(monster, end='')
  138.  
  139. def main():
  140. u = Ultraman('骆昊', 1000, 120)
  141. m1 = Monster('狄仁杰', 250)
  142. m2 = Monster('白元芳', 500)
  143. m3 = Monster('王大锤', 750)
  144. ms = [m1, m2, m3]
  145. fight_round = 1
  146. while u.alive and is_any_alive(ms):
  147. print('========第%02d回合========' % fight_round)
  148. m = select_alive_one(ms) # 选中一只小怪兽
  149. skill = randint(1, 10) # 通过随机数选择使用哪种技能
  150. if skill <= 6: # 60%的概率使用普通攻击
  151. print('%s使用普通攻击打了%s.' % (u.name, m.name))
  152. u.attack(m)
  153. print('%s的魔法值恢复了%d点.' % (u.name, u.resume()))
  154. elif skill <= 9: # 30%的概率使用魔法攻击(可能因魔法值不足而失败)
  155. if u.magic_attack(ms):
  156. print('%s使用了魔法攻击.' % u.name)
  157. else:
  158. print('%s使用魔法失败.' % u.name)
  159. else: # 10%的概率使用究极必杀技(如果魔法值不足则使用普通攻击)
  160. if u.huge_attack(m):
  161. print('%s使用究极必杀技虐了%s.' % (u.name, m.name))
  162. else:
  163. print('%s使用普通攻击打了%s.' % (u.name, m.name))
  164. print('%s的魔法值恢复了%d点.' % (u.name, u.resume()))
  165. if m.alive > 0: # 如果选中的小怪兽没有死就回击奥特曼
  166. print('%s回击了%s.' % (m.name, u.name))
  167. m.attack(u)
  168. display_info(u, ms) # 每个回合结束后显示奥特曼和小怪兽的信息
  169. fight_round += 1
  170. print('\n========战斗结束!========\n')
  171. if u.alive > 0:
  172. print('%s奥特曼胜利!' % u.name)
  173. else:
  174. print('小怪兽胜利!')
  175.  
  176. if __name__ == '__main__':
  177. main()

案例2:扑克游戏

  1. import random
  2.  
  3. class Card(object):
  4. """一张牌"""
  5.  
  6. def __init__(self, suite, face):
  7. self._suite = suite
  8. self._face = face
  9.  
  10. @property
  11. def face(self):
  12. return self._face
  13.  
  14. @property
  15. def suite(self):
  16. return self._suite
  17.  
  18. def __str__(self):
  19. if self._face == 1:
  20. face_str = 'A'
  21. elif self._face == 11:
  22. face_str = 'J'
  23. elif self._face == 12:
  24. face_str = 'Q'
  25. elif self._face == 13:
  26. face_str = 'K'
  27. else:
  28. face_str = str(self._face)
  29. return '%s%s' % (self._suite, face_str)
  30.  
  31. def __repr__(self):
  32. return self.__str__()
  33.  
  34. class Poker(object):
  35. """一副牌"""
  36.  
  37. def __init__(self):
  38. self._cards = [Card(suite, face)
  39. for suite in '♠♥♣♦'
  40. for face in range(1, 14)]
  41. self._current = 0
  42.  
  43. @property
  44. def cards(self):
  45. return self._cards
  46.  
  47. def shuffle(self):
  48. """洗牌(随机乱序)"""
  49. self._current = 0
  50. random.shuffle(self._cards)
  51.  
  52. @property
  53. def next(self):
  54. """发牌"""
  55. card = self._cards[self._current]
  56. self._current += 1
  57. return card
  58.  
  59. @property
  60. def has_next(self):
  61. """还有没有牌"""
  62. return self._current < len(self._cards)
  63.  
  64. class Player(object):
  65. """玩家"""
  66.  
  67. def __init__(self, name):
  68. self._name = name
  69. self._cards_on_hand = []
  70.  
  71. @property
  72. def name(self):
  73. return self._name
  74.  
  75. @property
  76. def cards_on_hand(self):
  77. return self._cards_on_hand
  78.  
  79. def get(self, card):
  80. """摸牌"""
  81. self._cards_on_hand.append(card)
  82.  
  83. def arrange(self, card_key):
  84. """玩家整理手上的牌"""
  85. self._cards_on_hand.sort(key=card_key)
  86.  
  87. # 排序规则-先根据花色再根据点数排序
  88. def get_key(card):
  89. return (card.suite, card.face)
  90.  
  91. def main():
  92. p = Poker()
  93. p.shuffle()
  94. players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
  95. for _ in range(13):
  96. for player in players:
  97. player.get(p.next)
  98. for player in players:
  99. print(player.name + ':', end=' ')
  100. player.arrange(get_key)
  101. print(player.cards_on_hand)
  102.  
  103. if __name__ == '__main__':
  104. main()

说明:大家可以自己尝试在上面代码的基础上写一个简单的扑克游戏,例如21点(Black Jack),游戏的规则可以自己在网上找一找。

案例3:工资结算系统

  1. """
  2. 某公司有三种类型的员工 分别是部门经理、程序员和销售员
  3. 需要设计一个工资结算系统 根据提供的员工信息来计算月薪
  4. 部门经理的月薪是每月固定15000元
  5. 程序员的月薪按本月工作时间计算 每小时150元
  6. 销售员的月薪是1200元的底薪加上销售额5%的提成
  7. """
  8. from abc import ABCMeta, abstractmethod
  9.  
  10. class Employee(object, metaclass=ABCMeta):
  11. """员工"""
  12.  
  13. def __init__(self, name):
  14. """
  15. 初始化方法
  16.  
  17. :param name: 姓名
  18. """
  19. self._name = name
  20.  
  21. @property
  22. def name(self):
  23. return self._name
  24.  
  25. @abstractmethod
  26. def get_salary(self):
  27. """
  28. 获得月薪
  29.  
  30. :return: 月薪
  31. """
  32. pass
  33.  
  34. class Manager(Employee):
  35. """部门经理"""
  36.  
  37. def get_salary(self):
  38. return 15000.0
  39.  
  40. class Programmer(Employee):
  41. """程序员"""
  42.  
  43. def __init__(self, name, working_hour=0):
  44. super().__init__(name)
  45. self._working_hour = working_hour
  46.  
  47. @property
  48. def working_hour(self):
  49. return self._working_hour
  50.  
  51. @working_hour.setter
  52. def working_hour(self, working_hour):
  53. self._working_hour = working_hour if working_hour > 0 else 0
  54.  
  55. def get_salary(self):
  56. return 150.0 * self._working_hour
  57.  
  58. class Salesman(Employee):
  59. """销售员"""
  60.  
  61. def __init__(self, name, sales=0):
  62. super().__init__(name)
  63. self._sales = sales
  64.  
  65. @property
  66. def sales(self):
  67. return self._sales
  68.  
  69. @sales.setter
  70. def sales(self, sales):
  71. self._sales = sales if sales > 0 else 0
  72.  
  73. def get_salary(self):
  74. return 1200.0 + self._sales * 0.05
  75.  
  76. def main():
  77. emps = [
  78. Manager('刘备'), Programmer('诸葛亮'),
  79. Manager('曹操'), Salesman('荀彧'),
  80. Salesman('吕布'), Programmer('张辽'),
  81. Programmer('赵云')
  82. ]
  83. for emp in emps:
  84. if isinstance(emp, Programmer):
  85. emp.working_hour = int(input('请输入%s本月工作时间: ' % emp.name))
  86. elif isinstance(emp, Salesman):
  87. emp.sales = float(input('请输入%s本月销售额: ' % emp.name))
  88. # 同样是接收get_salary这个消息但是不同的员工表现出了不同的行为(多态)
  89. print('%s本月工资为: ¥%s元' %
  90. (emp.name, emp.get_salary()))
  91.  
  92. if __name__ == '__main__':
  93. main()

Python:Day05-2的更多相关文章

  1. My way to Python - Day05 - 面向对象-思维导图

    My way to Python - Day05 - 面向对象   思维导图

  2. python day05笔记总结

    2019.4.2 S21 day05笔记总结 一.昨日内容回顾与补充 1.extend(列表独有功能) 循环添加到一个列表中 a.有列表users = ['张三',‘李四]   people = [' ...

  3. My way to Python - Day05 - 面向对象

    思维导图

  4. python day05

    数字类型 1.整型:整数 num = 1000000000000 type(num) --->int 2.浮点型:小数 num = 123.2341 type(num) --->float ...

  5. python day05 作业答案

    1. b.不可以 c.tu=("alex",[11,22,{"k1":"v1","k2":["age" ...

  6. python day05字典

    一.字典 1.字典的结构: a={key:value,key2:value},key是不可变的,value是可变的. 例子:dic = {123: 456, True: 999, "id&q ...

  7. python day05作业

  8. 铁乐学Python_day05-字典dict

    1.[字典dict] Python内置了字典:dict的支持,dict全称dictionary, 在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 字典和列表直观上 ...

  9. Python基础(协程函数、内置函数、递归、模块和包)-day05

    写在前面 上课第五天,打卡: 凭着爱,再回首: 一.协程函数(生成器:yield的表达式形式) 1.yield 的语句形式: yield 1 - 这种方式在 Python基础(函数部分)-day04  ...

  10. python开发学习-day05(正则深入、冒泡排序算法、自定义模块、常用标准模块)

    s12-20160130-day05 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

随机推荐

  1. 通过实现简单聊天室了解websocket的基础使用

    websocket基础使用 用到的依赖包 websocket的依赖 <dependency> <groupId>javax.websocket</groupId> ...

  2. Java反射之数组的反射应用

    上一篇我们说了Java反射之成员方法的反射 这一篇我们说一说数组的反射应用,数组的有长度等属性,所以也会有相应的方法获得这些属性,这里我们不一一列举哪些方法.我们来了解反射包中的一个类----Arra ...

  3. vue基础----自定义组件directive ,bind,update,insert

    <div id="app"> <input type="text" v-limit.3="msg" v-focus> ...

  4. LeetCode-矩形重叠

    题目描述: 矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标. 如果相交的面积为正,则称两矩形重叠.需要明确的是,只在 ...

  5. 可运行jar包的几种打包/部署方式(转)

    转自:https://www.cnblogs.com/yjmyzz/p/executable-jar.html java项目开发中,最终生成的jar,大概可分为二类,一类是一些通用的工具类(不包含ma ...

  6. 【Weiss】【第03章】练习3.13:桶排序

    [练习3.13] 利用社会安全号码对学生记录构成的数组排序.编写一个程序进行这件工作,使用具有1000个桶的基数排序并且分三趟进行. Answer: 首先,对社会安全号码不了解的就把它当成一个不超过9 ...

  7. angular http 节流

    有时候点列表但是由于查询问题,后端返回数据的速度很慢,导致回来的顺序错乱,后端解决不了,前端来 在jq年代 像标志位 防抖 节流等 在angular里使用了rxjs //错误示范 getIntelli ...

  8. vnpy源码阅读学习(8):关于app

    关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...

  9. 1、Spark Core所处位置和主要职责

    Spark组件是基于分布式资源引擎层(Yarn等)和分布式存储层(HDFS等)之上的一个组件,Spark本质上是一个计算引擎,负责计算的,根据不同计算场景划分出了SQL.Streaming.MLib. ...

  10. MySql最左匹配原则解析

    看前提问:table中有多个字段组成的联合索引(a,b,c),查询时哪些情况能够命中索引呢? 话不多说,直接开搞: 数据库表结构如下: CREATE TABLE `test` ( `id` ) uns ...