方法)
先来看init()方法存在重大意义的缘由, 这缘由有着两方面。一方面的缘由在于, 于对象的生命周期当中, 初始化属于最为关键的一步, 每个对象唯有完成正确初始化之后才能够顺利展开工作。另一方面的缘由在于, init()的参数值其形式可能存在多种多样, 会有多种不同的呈现方式。因存在诸多为 init()给予参数值的方式, 于对象创建而言有着大量用例, 对此数种用例之中的部分予以查看, 将竭尽全力来弄明白, 所以需定义一个初始化去恰当精准地描述问题区域。就我们而言, 于接触init()方法之前, 不管怎样, 我们都得大致、简略地瞧一瞧在其中所隐含的类的层次结构呀。在这一章节之中, 我们来瞧一瞧不同样式的简单对象的初始化情况, 举例来说的话, 就像是打牌这种情形。在做完这一步之后, 我们能够进而看看更为复杂一些的对象, 就如同包含集合的hands对象以及涉及包含策略还有状态的那种。隐含的超类——每个类之中都暗藏着一个超类, 它是种极为简易的类定义方式, 几乎没干什么事, 我们得以创建出实例, 然而我们没办法借之做过多事情, 缘由在于诸多特别的方法极易引发异常。当我们去自定义一个类的时候, 这个类就成为了超类, 下面呈现的是一个类定义的示例, 它借助新的名称以简单的方式实施了继承:classX:pass下面是和自定义类的一些交互 X.__class__classtype X.__class__.__base__classobject我们可以看到该类是type类的一个对象且它的基类为。如同于每个方法之中能看到的那般, 我们同样去瞧瞧源自继承的默认行为, 于某些情形之下, 超类特殊方法的行为恰是我们所期望的, 然而在别的情形之下我们得去覆盖此特殊方法。基类对象的init()方法基础是对象生命周期中的创建、初始化以及销毁, 我们把那些创建和销毁的高级特殊方法, 推迟到后面的章节里, 目前仅关注初始化。任意类的超类, 存有一个默认涵盖pass的init()实现, 我们不必去实现init()。要是不实现它, 那么在对象创建后就不会生成实例变量。于某些情形下, 此种默认行为是能够被接受的。我们老是给对象增添属性, 此对象是基类的子类。思索下面这个类, 它要有两个实例变量, 然而却不初始化它们:classRectangle:defarea(self):returnself.length * self.width一个类存在用以返回一个值且使用两个属性的方法, 而这些属性并未进行初始化, 即此代码是合法的, 它能够有效地避免专门设定属性, 虽说感觉稍显有些奇怪, 然而却是有效的。下面是于类的交互 r Rectangle() r.length, r.width 13, 8 r.area()显而易见, 这是具备合法性的, 然而这同时也是致使容易产生混淆的源头所在, 故而这同样是我们必须要予以规避的缘由。不管怎样, 这个设计赋予了极大的灵活性, 如此一来, 有时我们无需在init()方法里设置全部属性。到这一步, 我们进展得颇为顺畅。一个可选属性实际上就是一个子类, 只不过没有真正正式声明为子类。我们创建多态在一定程度上或许会引发混乱以及因if语句使用不当而造成的盘绕。虽说未初始化的属性可能有其用处, 然而极有可能是糟糕设计的先兆。《之禅》中的建议显式比隐式更好。一个init()方法应该让实例变量显式。可怜的多态灵活和愚蠢就在一念之间。当出现我们认为要依照如下这般去撰写的状况时, 我们正朝着愚笨前行, 这一前行是从灵活的边缘起始的。ifxinself.__dict__:或者try: self.xexceptAttributeError:就是使用隐示变量还要对变量的值进行判断现在应当再度思索API, 并且增添一个通用的方法或者属性, 进行重构要比增添if语句更为明智。在超类中实现init()我们借助实现init()方法达成对象的初始化。在一个对象被创建的时候, 先是创建出一个空对象, 接着针对那个新对象调用init()方法。该方法功能常常用于创建对象的实例变量以及执行相关任何其他一次性处理事务得以完成。以下展现的是Card类示例所定义的层次架构, 我们会去定义Card超类以及有三个子类, 这三个子类都是Card的变体, 当中呀存在两个实例变量是直接根据参数值来予以设置的, 另外还有两个变量则借着初始化方法来进行计算。classCard:def__init__(self, rank, suit): self.suitsuit self.rankrank self.hard, self.softself._points()classNumberCard(Card):def_points(self):returnint(self.rank), int(self.rank)classAceCard(Card):def_points(self):return1, 11classFaceCard(Card):def_points(self):return10, 10在此示例里, 我们将init()方法提取至超类, 借此, Card超类中的通用初始化能够应用于三个子类 , 和。存在着这样一种设计, 它是常见的多态设计, 每一个子类都会提供一个实现, 这个实现是唯一的()方法实现, 所有子类具备相同的签名, 也就是其有着相同的方法以及属性, 在一个应用程序当中, 这三个子类的对象能够交替使用。倘若我们针对花色采用简易的字符, 那我们能够创建Card实例, 情形如下:cards [AceCard(A,?), NumberCard(2,?), NumberCard(3,?),]把一些牌的类、牌值以及花色在列表里进行逐个列举。长远来看, 创建Card实例得依靠更具智能的工厂函数才行这般去逐个列举52张牌, 既无趣还容易出现差错。在接触工厂函数以前, 先来瞧瞧一些别的问题。使用init()创建显式常量给牌定义花色类是可行的。二十一点里, 花色没什么要紧, 简单字符串就行。我们将花色构造函数用作创建常量对象的例子, 在好多情形下, 我们应用里一小部分对象能够借由常量集合去定义 , 一小部分的静态对象兴许是达成策略模式或者状态模式的一份子。在一些情形下, 我们存在一个于初始化时或者配置文件里创建的常量对象池, 或者我们能够依据命令行参数来创建常量对象。我们将会在第十六章名为《通过命令进行复制》这一章节中获取初始化设计以及启动设计的详尽信息。对于定义一个不可变对象而言, 不存在简单正式的机制, 我们会在第三章《属性访问、方法属性和描述符》去瞧瞧保证不可变性的相关技术有哪些。在本示例当中, 花色具备不可变的特性是具备一定道理的。下面这个类我们将用于创建两个个显式常量classSuit:def__init__(self, name, symbol): self.namename self.symbol symbol下面是通过这个类创建的常量Club, Diamond, Heart, Spade Suit(Club,?), Suit(Diamond,?), Suit(Heart,?), Suit(Spade,?)现在我们可以通过下面展示的代码片段创建cardscards [AceCard(A, Spade), NumberCard(2, Spade), NumberCard(3, Spade),]这个小小的示例, 这般做法对于单个特性涵盖的花色代码而言不是多么巨大的进步, 在更为复杂的情形下, 会有一些策略或者一些状态对象经由这个途径去创立, 依靠来自小的且静态的常量对象进行复用能够让策略或状态设计模式更具效率。必须得承认, 在其中这些对象并非技术层面一直不变的, 乃是可变的。若进行额外编码以使这些对象真的不变, 倒是可能存在一些好处的。无关紧要的不变性它很有吸引力, 然而却容易引发麻烦, 这种麻烦就是不变性带来的。那是怎样的麻烦呢? 有时候, 在他们的应用程序里, 会被神话般的“恶意程序员”通过修改常量值来进行调整。从设计角度去考量, 这是极为愚蠢的做法。那些神话般的、怀有恶意的程序员不会停下这样做的行为, 原因在于已经不存在更好的办法, 能以更简洁简单的方式在其中进行编码。恶意程序员访问源码并对其修改, 仅仅是期望尽可能轻松地编写代码, 以此来修改一个常数。当对定义不可变对象的类设定之时, 理应尽量别作过长时间的纠结。在第三章名为《属性访问、方法属性和描述符》的章节里面, 我们会借助于在存在问题的程序之中提供适宜的诊断信息, 以此来呈现怎样去达成不变性这一目的。方法使用1.使用demo初始化 。注意这个名称的开始和结尾都是双下划线。使用方法代码例子#!/usr/bin/python#Filename: class_init.pyclassPerson:def__init__(self, name): self.namenamedefsayHi(self):printHello, my nameis, self.name pPerson(Swaroop) p.sayHi()#This short example can also be written as Person(Swaroop).sayHi()输出$ python class_init.py Hello, my nameisSwaroop它如何工作在这里, 我们将方法定义为, 取一个名为name的参数, 以及普通的参数self。在这当中, 我们仅仅是去创建一个新的域, 它亦称为name。需要留意的是, 它们是两个彼此不同的变量, 虽说它们有着相同的名字。而点号让我们得以区分它们。最关键的是, 我们并未特意去调用方法, 仅仅是在创建一个类的全新实例之际, 将参数包含于圆括号里边而后跟在类名的后面, 借此传递给方法。这便是这种方法的关键所在。现时, 于我们的办法里, 我们能够运用self.name域, 此在讲Hi方法中获得了证实, 且有验证。方法类似于C 、C#和Java中的2.注意点注意, 其一, 它并不等同于C#里的构造函数, 其二, 在执行它之际, 实例已然被构造出来了。classA(object):def__init__(self,name): self.namenamedefgetName(self):returnAself.name当我们执行aA(hello)时可以理解为aobject.__new__(A) A.__init__(a,hello)即作用是初始化已实例化后的对象。要留意 2 , 当针对子类进行实例化操作的时候 , 子类能够选择不进行重写 , 此时会自动去调用超类内已经被定义好的。classB(A):defgetName(self):returnBself.nameif__name____main__: bB(hello)printb.getName()但要是进行了重写, 那么在实例化子类之际, 就不会以隐式这种方式再去调用超类当中已作定义的。classC(A):def__init__(self):passdefgetName(self):returnCself.nameif__name____main__: cC()printc.getName()便会报出: C 不存在 name这样的错误, 因而要是进行了重写, 为了能够去使用或者扩展超类里的行为, 最好是明确地调用超类的方法。classC(A):def__init__(self,name): super(C,self).__init__(name)defgetName(self):returnCself.nameif__name____main__: cC(hello)printc.getName()1.使用demo初始化 。注意这个名称的开始和结尾都是双下划线。使用方法代码例子#!/usr/bin/# : .pyclass :def (self, name):self.name namedef sayHi(self):把print, 放在Hello, 之前, 然后, my name is, 之后, 再放上self.name。p ()p.sayHi()# 这个简短的内容也能够被用作。调用打招呼的方法输出$ .pyHello, my name is它如何工作这里我们把方法定义为取一个参数name以及普通的参数self。在这个里我们只是创建一个新的域也称为name。注意它们是两个不同的变量尽管它们有相同的名字。点号使我们能够区分它们。最重要的是我们没有专门调用方法只是在创建一个类的新实例的时候把参数包括在圆括号内跟在类名后面从而传递给方法。这是这种方法的重要之处。现在我们能够在我们的方法中使用self.name域。这在sayHi方法中得到了验证。方法类似于C 、C#和Java中的2.注意点注意1、并不相当于C#中的构造函数执行它的时候实例已构造出来了。当我们执行时可以理解为即作用是初始化已实例化后的对象。注意2、子类可以不重写实例化子类时会自动调用超类中已定义的但如果重写了实例化子类时则不会隐式的再去调用超类中已定义的则会报: C has no name”错误所以如果重写了为了能使用或扩展超类中的行为最好显式的调用超类的方法----------这篇文章源自一位名为 jiesa 的人在 CSDN 所开设的博客 , 其完整的文章地址获取方式应当是通过点击操作:每天一点点感受自己存在的意义。