python进阶指南(编程轻松进阶):十六面向对象编程和继承(代码片段)

布客飞龙 布客飞龙     2023-04-11     372

关键词:

原文:http://inventwithpython.com/beyond/chapter16.html

定义一个函数,并从几个地方调用它,可以省去复制和粘贴源代码的麻烦。不复制代码是一个很好的实践,因为如果你需要修改它(无论是为了修复一个错误还是添加新特性),你只需要在一个地方修改它。没有重复的代码,程序也更短,更容易阅读。

类似于函数,继承是一种代码重用技术,您可以将其应用于类。这是将类置于父子关系中的行为,在这种关系中,子类继承父类方法的副本,使您不必在多个类中复制一个方法。

许多程序员认为继承被高估了,甚至是危险的,因为大量的继承类增加了程序的复杂性。以“继承是邪恶的”为标题的博客文章并非完全不着边际;继承当然容易被过度使用。但是在组织代码时,有限地使用这种技术可以节省大量时间。

继承是如何工作的

要创建一个新的子类,可以将现有父类的名称放在class语句的括号中。要练习创建子类,请打开一个新的文件编辑器窗口,并输入以下代码;保存为inheritanceExample.py :

class ParentClass: # 1
    def printHello(self): # 2
        print('Hello, world!')

class ChildClass(ParentClass): # 3
    def someNewMethod(self):
        print('ParentClass objects don't have this method.')

class GrandchildClass(ChildClass): # 4
    def anotherNewMethod(self):
        print('Only GrandchildClass objects have this method.')

print('Create a ParentClass object and call its methods:')
parent = ParentClass()
parent.printHello()

print('Create a ChildClass object and call its methods:')
child = ChildClass()
child.printHello()
child.someNewMethod()

print('Create a GrandchildClass object and call its methods:')
grandchild = GrandchildClass()
grandchild.printHello()
grandchild.someNewMethod()
grandchild.anotherNewMethod()

print('An error:')
parent.someNewMethod()

运行该程序时,输出应该如下所示:

Create a ParentClass object and call its methods:
Hello, world!
Create a ChildClass object and call its methods:
Hello, world!
ParentClass objects don't have this method.
Create a GrandchildClass object and call its methods:
Hello, world!
ParentClass objects don't have this method.
Only GrandchildClass objects have this method.
An error:
Traceback (most recent call last):
  File "inheritanceExample.py", line 35, in <module>
    parent.someNewMethod() # ParentClass objects don't have this method.
AttributeError: 'ParentClass' object has no attribute 'someNewMethod'

我们创建了三个名为ParentClass 1 、ChildClass 3 和GrandchildClass 4 的类。ChildClass 子类 ParentClass,意味着ChildClass将拥有与ParentClass相同的所有方法。我们说ChildClass 继承了ParentClass方法。另外,GrandchildClass继承了ChildClass的子类,因此它拥有与ChildClass及其父类ParentClass相同的所有方法。

使用这种技术,我们已经有效地将printHello()方法 2 的代码复制并粘贴到了ChildClassGrandchildClass类中。我们对printHello()中代码的任何更改不仅会更新ParentClass,还会更新ChildClassGrandchildClass。这与更改函数中的代码会更新其所有函数调用是一样的。你可以在图 16-1 中看到这个关系。注意,在类图中,箭头是从子类指向基类的。这反映了一个事实,即一个类总是知道它的基类,但不知道它的子类。

图 16-1:一个层次图(左)和文氏图(右)显示了三个类和它们拥有的方法之间的关系

人们常说父子类代表“是一种”关系。一个ChildClass对象是一个ParentClass对象,因为它拥有与一个ParentClass对象相同的所有方法,包括一些它定义的额外方法。这种关系是单向的:ParentClass对象不是ChildClass对象。如果一个ParentClass对象试图调用someNewMethod(),它只存在于ChildClass对象(以及ChildClass的子类),Python 会抛出一个AttributeError

程序员通常认为相关的类必须适应现实世界中的“是”层次结构。OOP 教程一般有Vehicle``FourWheelVehicle▶``Car``Animal``Bird``Sparrow,或者Shape``Rectangle``Square的父类、子类、孙类。但是请记住,继承的主要目的是代码重用。如果您的程序需要一个具有一组方法的类,这些方法是其他类的方法的完全超集,继承允许您避免复制和粘贴代码。

我们有时也称子类为子类派生类,称父类为超类基类

覆盖方法

子类继承其父类的所有方法。但是子类可以通过用自己的代码提供自己的方法来覆盖继承的方法。子类的覆盖方法将与父类的方法同名。

为了说明这个概念,让我们回到上一章创建的井字棋。这一次,我们将创建一个新类MiniBoard,它继承了TTTBoard并覆盖了getBoardStr(),以提供一个更小的井字棋棋盘。程序会询问玩家使用哪种风格的棋盘。我们不需要复制和粘贴其余的TTTBoard方法,因为MiniBoard将继承它们。

将以下内容添加到您的tictactoe_oop.py文件的末尾,以创建原始TTTBoard类的子类,然后覆盖getBoardStr()方法:

class MiniBoard(TTTBoard):
    def getBoardStr(self):
        """Return a tiny text-representation of the board."""
        # Change blank spaces to a '.'
        for space in ALL_SPACES:
            if self._spaces[space] == BLANK:
                self._spaces[space] = '.'

        boardStr = f'''
          self._spaces['1']self._spaces['2']self._spaces['3'] 123
          self._spaces['4']self._spaces['5']self._spaces['6'] 456
          self._spaces['7']self._spaces['8']self._spaces['9'] 789'''

        # Change '.' back to blank spaces.
        for space in ALL_SPACES:
            if self._spaces[space] == '.':
                self._spaces[space] = BLANK
        return boardStr

TTTBoard类的getBoardStr()方法一样,MiniBoardgetBoardStr()方法创建了一个井字棋棋盘的多行字符串,在传递给print()函数时显示。但是这个字符串要小得多,放弃了 X 和 O 标记之间的线,使用点号来表示空格。

更改main()中的行,使其实例化一个MiniBoard对象,而不是一个TTTBoard对象:

 if input('Use mini board? Y/N: ').lower().startswith('y'):
        gameBoard = MiniBoard() # Create a MiniBoard object.
    else:
        gameBoard = TTTBoard() # Create a TTTBoard object.

除了对main()的这一行修改,程序的其余部分和以前一样。当您现在运行该程序时,输出将如下所示:

Welcome to Tic-Tac-Toe!
Use mini board? Y/N: y

          ... 123
          ... 456
          ... 789
What is X's move? (1-9)
1

          X.. 123
          ... 456
          ... 789
What is O's move? (1-9)
`--snip--`
          XXX 123
          .OO 456
          O.X 789
X has won the game!
Thanks for playing!

您的程序现在可以轻松地拥有这两个井字棋棋盘类的实现。当然,如果你想要迷你版的板,你可以简单地替换TTTBoardgetBoardStr()方法中的代码。但是如果你需要,继承可以让你通过重用它们的公共代码轻松地创建两个类。

如果我们不使用继承,我们可以给TTTBoard添加一个名为useMiniBoard的新属性,并在getBoardStr()中放置一个if-else语句来决定何时显示常规面板或迷你面板。对于这样一个简单的改变,这将很好地工作。但是如果MiniBoard子类需要覆盖 2、3 甚至 100 个方法呢?如果我们想创建几个不同的TTTBoard子类会怎么样?不使用继承会导致我们的方法中的if-else语句爆炸,并大大增加代码的复杂性。通过使用子类和覆盖方法,我们可以更好地将代码组织成单独的类,以处理这些不同的用例。

super()函数

子类的覆盖方法通常类似于父类的方法。尽管继承是一种代码重用技术,但覆盖方法可能会导致您覆盖父类方法中的相同代码,作为子类方法的一部分。为了防止这种重复代码,内置的super()函数允许一个覆盖方法调用父类中的原始方法。

例如,让我们创建一个名为HintBoard的新类,它是TTTBoard的子类。新的类覆盖了getBoardStr(),所以在画了井字棋棋盘之后,它还添加了一个提示,如果 X 或 O 能在他们的下一步棋中获胜。这意味着HintBoard类的getBoardStr()方法必须做所有与TTTBoard类的getBoardStr()方法绘制井字棋棋盘相同的任务。我们可以使用super()HintBoard类的getBoardStr()方法中调用TTTBoard类的getBoardStr()方法,而不是重复代码来完成这项工作。将以下内容添加到您的tictactoe_oop.py文件的末尾:

class HintBoard(TTTBoard):
    def getBoardStr(self):
        """Return a text-representation of the board with hints."""
        boardStr = super().getBoardStr() # Call getBoardStr() in TTTBoard. # 1

        xCanWin = False
        oCanWin = False
        originalSpaces = self._spaces # Backup _spaces. # 2
        for space in ALL_SPACES: # Check each space:
            # Simulate X moving on this space:
            self._spaces = copy.copy(originalSpaces)
            if self._spaces[space] == BLANK:
                self._spaces[space] = X
            if self.isWinner(X):
                xCanWin = True
            # Simulate O moving on this space:
            self._spaces = copy.copy(originalSpaces) # 3
            if self._spaces[space] == BLANK:
                self._spaces[space] = O
            if self.isWinner(O):
                oCanWin = True
        if xCanWin:
            boardStr += '\\nX can win in one more move.'
        if oCanWin:
            boardStr += '\\nO can win in one more move.'
        self._spaces = originalSpaces
        return boardStr

首先,super().getBoardStr() 1 运行父TTTBoard类的getBoardStr()内部的代码,返回井字棋盘的字符串。我们暂时将这个字符串保存在一个名为boardStr的变量中。使用通过重用TTTBoard类的getBoardStr()创建的棋盘字符串,该方法中的其余代码处理提示的生成。然后,getBoardStr()方法将xCanWinoCanWin变量设置为False,并将self._spaces字典备份为originalSpaces变量 2 。然后一个for循环在从'1''9'的所有棋盘空间上循环。在循环内部,self._spaces属性被设置为一个originalSpaces字典的副本,如果正在循环的当前空格为空,则在那里放置一个 X。这模拟了 X 在这个空白空间上的下一步移动。对self.isWinner()的调用将确定这是否是一个赢棋,如果是,则将xCanWin设置为True。然后对 O 重复这些步骤,看看 O 是否能在这个空间上移动 3 获胜。这个方法使用copy模块来复制self._spaces中的字典,所以在tictactoe.py的顶部添加下面一行:

import copy

接下来,更改main()中的行,使其实例化一个HintBoard对象,而不是一个TTTBoard对象:

 gameBoard = HintBoard() # Create a TTT board object.

除了对main()的这一行修改之外,程序的其余部分和以前完全一样。当您现在运行该程序时,输出将如下所示:

Welcome to Tic-Tac-Toe!
`--snip--`
      X| |   1 2 3
      -+-+-
       | |O  4 5 6
      -+-+-
       | |X  7 8 9
X can win in one more move.
What is O's move? (1-9)
5

      X| |   1 2 3
      -+-+-
       |O|O  4 5 6
      -+-+-
       | |X  7 8 9
O can win in one more move.
`--snip--`
The game is a tie!
Thanks for playing!

在该方法结束时,如果xCanWinoCanWinTrue,一个附加的声明消息被添加到boardStr字符串中。最后,boardStr又回来了。

不是每个被覆盖的方法都需要使用super()!如果一个类的覆盖方法做的事情与父类中被覆盖的方法完全不同,就没有必要使用super()调用被覆盖的方法。当一个类有不止一个父方法时,super()函数特别有用,这将在本章后面的“多重继承”中解释。

首选组合而非继承

继承对于代码重用来说是一项伟大的技术,您可能希望在所有的类中立即开始使用它。但是您可能不总是希望基类和子类如此紧密地耦合。创建多层次的继承不会给你的代码增加组织性,反而会增加官僚主义。

虽然您可以对具有“是”关系的类使用继承(换句话说,当子类是一种父类时),但是对具有“有”关系的类使用一种称为组合的技术通常是有利的。组合是一种类设计技术,它将对象包含在类中,而不是继承那些对象的类。这就是我们在给类添加属性时所做的事情。当使用继承设计你的类时,支持组合而不是继承。这就是我们在本章和上一章的所有例子中所做的,如下表所述:

  • 一个对象“有”一定数量的大帆船、镰刀和克努特硬币。
  • 一个对象“有”一组九个空格。
  • 一个MiniBoard对象是一个TTTBoard对象,所以它也“有”一组九个空格。
  • 一个HintBoard对象是一个TTTBoard对象,所以它也“有”一组九个空格。

让我们回到上一章的WizCoin类。如果我们创建一个新的WizardCustomer类来代表巫师世界中的顾客,这些顾客将携带一定数量的钱,我们可以通过WizCoin类来表示这些钱。但是这两个阶级之间没有“是一”的关系;一个WizardCustomer对象不是一种WizCoin对象。如果我们使用继承,可能会产生一些笨拙的代码:

import wizcoin

class WizardCustomer(wizcoin.WizCoin): # 1
    def __init__(self, name):
        self.name = name
        super().__init__(0, 0, 0)

wizard = WizardCustomer('Alice')
print(f'wizard.name has wizard.value() knuts worth of money.')
print(f'wizard.name\\'s coins weigh wizard.weightInGrams() grams.')

在这个例子中,WizardCustomer继承了一个WizCoin 1 对象的方法,比如value()weightInGrams()。从技术上来说,继承自WizCoinWizardCustomer可以完成与包含WizCoin对象作为属性的WizardCustomer相同的任务。但是wizard.value()wizard.weightInGrams()方法的名字有误导性:它们似乎会返回巫师的价值和重量,而不是巫师硬币的价值和重量。此外,如果我们后来想为向导的权重添加一个weightInGrams()方法,那么这个方法名已经被占用了。

最好有一个WizCoin对象作为属性,因为一个巫师顾客“有”一定数量的巫师硬币:

import wizcoin

class WizardCustomer:
    def __init__(self, name):
        self.name = name
        self.purse = wizcoin.WizCoin(0, 0, 0) # 1

wizard = WizardCustomer('Alice')
print(f'wizard.name has wizard.purse.value() knuts worth of money.')
print(f'wizard.name\\'s coins weigh wizard.purse.weightInGrams() grams.')

我们没有让WizardCustomer类从WizCoin继承方法,而是给了WizardCustomer类一个purse属性 1 ,其中包含一个WizCoin对象。当使用组合时,对WizCoin类方法的任何改变都不会改变WizardCustomer类的方法。这种技术为两个类的未来设计变更提供了更大的灵活性,并使代码更易于维护。

继承的缺点

继承的主要缺点是,将来您对父类所做的任何更改必然会被它的所有子类继承。在大多数情况下,这种紧密耦合正是您想要的。但是在某些情况下,您的代码需求不太适合您的继承模型。

例如,假设我们在一个车辆模拟程序中有CarMotorcycleLunarRover类。他们都需要类似的方法,比如startIgnition()changeTire()。我们可以创建一个父类Vehicle,并让CarMotorcycleLunarRover继承它,而不是将这些代码复制并粘贴到每个类中。现在,如果我们需要修复一个 bug,比如说,changeTire()方法,我们只需要在一个地方进行修改。如果我们有几十个继承自Vehicle的不同的车辆相关类,这尤其有用。这些类的代码如下所示:

class Vehicle:
    def __init__(self):
        print('Vehicle created.')
    def startIgnition(self):
        pass  # Ignition starting code goes here.
    def changeTire(self):
        pass  # Tire changing code goes here.

class Car(Vehicle):
    def __init__(self):
        print('Car created.')

class Motorcycle(Vehicle):
    def __init__(self):
        print('Motorcycle created.')

class LunarRover(Vehicle):
    def __init__(self):
        print('LunarRover created.')

但是将来对Vehicle的所有更改也会影响这些子类。如果我们需要一个changeSparkPlug()方法会怎么样?汽车和摩托车有带火花塞的内燃机,但月球车没有。通过支持组合胜过继承,我们可以创建单独的CombustionEngineElectricEngine类。然后我们设计了Vehicle类,这样它就“有一个”engine attribute, either a CombustionEngineElectricEngine对象,使用适当的方法:

class CombustionEngine:
   def __init__(self):
       print('Combustion engine created.')
   def changeSparkPlug(self):
       pass  # Spark plug changing code goes here.

class ElectricEngine:
   def __init__(self):
       print('Electric engine created.')

class Vehicle:
   def __init__(self):
       print('Vehicle created.')
       self.engine = CombustionEngine()  # Use this engine by default.
`--snip--`

class LunarRover(Vehicle):
   def __init__(self):
       print('LunarRover created.')
       self.engine = ElectricEngine()

这可能需要重写大量的代码,特别是如果你有几个继承自先前存在的Vehicle类的类:对于Vehicle类或其子类的每个对象,所有的vehicleObj.changeSparkPlug()调用都需要变成vehicleObj.engine.changeSparkPlug()。因为如此大的变化可能会引入错误,所以您可能希望简单地让LunarVehiclechangeSparkPlug()方法什么都不做。在这种情况下,Python 风格的方法是在LunarVehicle类内将changeSparkPlug设置为None

class LunarRover(Vehicle):
    changeSparkPlug = None
    def __init__(self):
        print('LunarRover created.')

changeSparkPlug = None行遵循本章后面的“类属性”中描述的语法。这覆盖了从Vehicle继承的changeSparkPlug()方法,所以用LunarRover对象调用它会导致错误:

>>> myVehicle = LunarRover()
LunarRover created.
>>> myVehicle.changeSparkPlug()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

如果我们试图用一个LunarRover对象调用这个不合适的方法,这个错误允许我们快速失败并立即发现问题。任何LunarRover的子类也为changeSparkPlug()继承这个None值。TypeError: 'NoneType' object is not callable错误信息告诉我们LunarRover类的程序员有意将changeSparkPlug()方法设置为None。如果一开始就没有这样的方法,我们就会收到一条NameError: name 'changeSparkPlug' is not defined错误消息。

继承可以创造出复杂矛盾的阶级。用作文来代替通常是有利的。

isinstance()issubclass()函数

当我们需要知道一个对象的类型时,我们可以将该对象传递给内置的type()函数,如前一章所述。但是如果我们正在做一个对象的类型检查,使用更灵活的内置函数isinstance()是一个更好的主意。如果对象属于给定类或给定类的子类,则isinstance()函数将返回True。在交互式 Shell 中输入以下内容:

>>> class ParentClass:
...    pass
...
>>> class ChildClass(ParentClass):
...    pass
...
>>> parent = ParentClass() # Create a ParentClass object.
>>> child = ChildClass() # Create a ChildClass object.
>>> isinstance(parent, ParentClass)
True
>>> isinstance(parent, ChildClass)
False
>>> isinstance(child, ChildClass) # 1
True
>>> isinstance(child, ParentClass) # 2
True

注意,isinstance()表示child中的ChildClass对象是ChildClass 1 的实例,也是ParentClass 2 的实例。这是有意义的,因为一个ChildClass对象是一种ParentClass对象。

您还可以传递一个类对象元组作为第二个参数,以查看第一个参数是否是元组中的任何一个类:

>>> isinstance(42, (int, str, bool)) # True if 42 is an int, str, or bool.
True

不太常用的issubclass()内置函数可以识别为第一个参数传递的类对象是否是为第二个参数传递的类对象的子类(或同一个类):

>>> issubclass(ChildClass, ParentClass) # ChildClass subclasses ParentClass.
True
>>> issubclass(ChildClass, str) # ChildClass doesn't subclass str.
False
>>> issubclass(ChildClass, ChildClass) # ChildClass is ChildClass.
True

就像使用isinstance()一样,您可以将一个类对象元组作为第二个参数传递给issubclass(),以查看第一个参数是否是元组中任何类的子类。isinstance()issubclass()的关键区别在于issubclass()被传递了两个类对象,而isinstance()被传递了一个对象和一个类对象。

类方法

类方法与类相关联,而不是像常规方法那样与单个对象相关联。当您看到两个标记时,您可以在代码中识别出一个类方法:方法的def语句前的@classmethod装饰器和使用cls作为第一个参数,如下例所示。

class ExampleClass:
    def exampleRegularMethod(self):
        print('This is a regular method.')

    @classmethod
    def exampleClassMethod(cls):
        print('This is a class method.')

# Call the class method without instantiating an object:
ExampleClass.exampleClassMethod()

obj = ExampleClass()
# Given the above line, these two lines are equivalent:
obj.exampleClassMethod()
obj.__class__.exampleClassMethod()

除了self引用一个对象,而cls引用一个对象的类之外,cls参数的行为类似于self。这意味着类方法中的代码不能访问单个对象的属性或调用对象的常规方法。类方法只能调用其他类方法或访问类属性。我们使用名称cls是因为class是一个 Python 关键字,就像其他关键字一样,比如ifwhileimport,我们不能将其用于参数名称。我们经常通过类对象调用类属性,如在ExampleClass.exampleClassMethod()中。但是我们也可以通过类的任何对象调用它们,就像在obj.exampleClassMethod()中一样。

类方法并不常用。最常见的用例是提供除了__init__()之外的可选构造方法。例如,如果构造器既可以接受新对象需要的数据字符串,也可以接受包含新对象需要的数据的文件名字符串,会怎么样呢?我们不希望__init__()方法的参数列表冗长而混乱。相反,让我们使用类方法来返回一个新的对象。

例如,让我们创建一个AsciiArt类。正如你在第 14 章看到的,ASCII 艺术画使用文本字符来形成图像。

class AsciiArt:
   def __init__(self, characters):
       self._characters = characters

   @classmethod
   def fromFile(cls, filename):
       with open(filename查看详情  

python面向对象编程进阶(代码片段)

前言上上篇我们讲解了Python面向对象编程的基础知识,《Python基础篇:面向对象怎样炼成的》这篇我们继续来讨论面向对象编程相关的内容。目录前言可见性和属性装饰器动态属性静态方法和类方法继承和多态总结可见... 查看详情

python进阶指南(编程轻松进阶):八常见的python陷阱(代码片段)

原文:http://inventwithpython.com/beyond/chapter8.html虽然Python是我最喜欢的编程语言,但它也不是没有缺陷。每种语言都有缺点(有些比其他的多),Python也不例外。新的Python程序员必须学会避免一些常见的“陷阱”... 查看详情

进阶学python:python面向对象基础!(代码片段)

什么是编程范式?在了解面向对象编程之前,我们需要了解三大编程范式以及其之间的区别和利弊即:面向过程编程、函数式编程、面向对象编程。编程:是程序员用特定的语法+数据结构+算法组成的代码来... 查看详情

python面向对象进阶(代码片段)

...好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。@property装饰器之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性... 查看详情

面向对象编程进阶(代码片段)

python内置函数isinstance(obj,class)  判断一个对象是否是已知的类型,类似type()isinstance语法:isinstance(object,classinfo)object是实例/对象classinfo可以是直接或间接类名,基本类型或者由他们组成的元组返回值如果对象的类型与classinfo相... 查看详情

python入门自学进阶——5--类与对象

面向对象编程是函数式编程的一种变化。python既可以函数式编程,也可以面向对象编程。函数式编程可以做所有事,只是看适不适合,如果使用面向对象更简洁,就使用面向对象。对比:函数式编程,定义... 查看详情

面向对象编程——super进阶

一、入门使用在python中,使用super最常见的让子类继承父类。在这种情况下,当前类和对象可以作为super函数的参数使用,调用函数返回的任何方法都是调用超类的方法,而不是当前类的方法。classInformation(object):def__init__(self,name,... 查看详情

进阶学python:python面向对象系列之魔法方法!(代码片段)

本篇主要介绍面向对象编程中类的魔法属性,这些魔法属性均有其特殊的功能,即执行某些操作时,会自动触发这些魔法方法的执行,了解这些魔法方法可以更好的了解面向对象编程的实现原理;在学习魔法... 查看详情

面向对象进阶(代码片段)

...中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成立:>>>classObjectCreator(object):…pass…>>>my_object=ObjectCreator()>>>printmy_object<__main__.ObjectCreatorobjectat0 查看详情

go语言的进阶之路-面向对象编程

                                   GO语言的进阶之路- 查看详情

面向对象编程进阶版(代码片段)

isinstance(obj,cls)和issubclass(sub,super)isinstance(obj,cls)检查obj是否是类cls的实例化对象issubclass(sub,super)检查sub类是否是super类的派生类#isinstance(obj,cls)检查obj是否是类cls的实例化对象classFoo(object):passclassFoo1(Foo):passobj= 查看详情

python面向对象编程进阶(代码片段)

前言上上篇我们讲解了Python面向对象编程的基础知识,《Python基础篇:面向对象怎样炼成的》这篇我们继续来讨论面向对象编程相关的内容。目录前言可见性和属性装饰器动态属性静态方法和类方法继承和多态总结可见... 查看详情

python面向对象编程进阶(代码片段)

前言上上篇我们讲解了Python面向对象编程的基础知识,《Python基础篇:面向对象怎样炼成的》这篇我们继续来讨论面向对象编程相关的内容。目录前言可见性和属性装饰器动态属性静态方法和类方法继承和多态总结可见... 查看详情

面向对象(进阶)

面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用类是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)对象,根据模板创建的实例(即:对象),实例用于调用被包... 查看详情

面向对象(进阶)(代码片段)

一.关于上篇面向对象(初识)总结:1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用2.类:是一个模板,模板中包装了多个"函数"供使用(可以讲多个函数中公用的变量封装到对象中)3.对象,根据模板创建的实例(即:... 查看详情

javascript精粹基础进阶oop面向对象编程(上)

转载请注明出处原文连接http://blog.huanghanlian.com/article/5b698f14b8ea642ea9213f50面向对象编程,oop并不是针对与javascript,很多语言都实现了oop这样一个编程发法论,比如说java,c++,都是实现了oop的语言。概念与继承概念面向对象程序设... 查看详情

面向对象进阶

...设计领域所采用,并在Lisp和面向对象方面取得了成绩。2、python中的反射通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)3、可以 查看详情