>

尤为空虚,python中类和项目介绍

- 编辑:正版管家婆马报彩图 -

尤为空虚,python中类和项目介绍

python中类和类型介绍,python类型介绍

类是什么

可以视为种类或者类型的同义词。所有的对象都属于某一个类,称为类的实例。

例如:鸟就是"鸟类"的实例。这就是一个有很多子类的一般(抽象)类:看到的鸟可能属于子类"百灵鸟"。可以将"鸟类"想象成所有鸟的集合,而"百灵鸟类"是其中的一个子集。当一个对象所属的类是另外一个对象所属类的子集时,前者就被称为后者的子类,所以"百灵鸟类"是"鸟类"的子类,"鸟类"是"百灵鸟类"的超类

定义子类只是个定义更多方法的过程

创建类

>>> class Person:
    def setName(self,name):
        self.name=name
    def getName(self):
        return self.name
    def greet(self):
        print "Hello,world! I'm %s" % self.name


>>> foo=Person()
>>> bar=Person()
>>> foo.setName('Nsds')
>>> bar.setName('Ysdy')
>>> foo.greet()
Hello,world! I'm Nsds
>>> bar.greet()
Hello,world! I'm Ysdy

在调用foo的setName和greet函数时,foo自动将自己作为第一个参数传入函数中,因此命名为self。没有self的话,成员方法就没法访问他们要对其特性进行操作的对象本身了

特性是可以外部访问的:

>>> foo.name
'Nsds'
>>> bar.name='Yoda'
>>> bar.greet()
Hello,world! I'm Yoda

 特性、函数、方法

self参数事实上正是方法和函数的区别。方法将它们的第一个参数绑定到所属的实例上,因此这个参数可以不必提供。所以可以将特性绑定到一个普通函数上,这样就不会有特殊的self参数了:

(特性是对象内部的变量,对象的状态由它的特性来描述,对象的方法可以改变它的特性,可以直接从对象外部访问特性)

>>> class Class:
    def method(self):
        print 'I have a self!'


>>> def function():
    print "I don't..."

>>> s=Class()
>>> s.method()
I have a self!
>>> s.method=function
>>> s.method()
I don't...

变量birdsong引用绑定方法bird.sing上,还是对self参数的访问(仍旧绑定到类的相同实例上)

>>> class Bird:
    song='Squaawk'
    def sing(self):
        print self.song


>>> bird=Bird()
>>> bird.sing()
Squaawk
>>> birdsong=bird.sing
>>> birdsong()
Squaawk

在名称前加上双下划线,可以让方法或者特性变为私有(从外部无法访问)

>>> class Secretive:
    def __inaccessible(self):
        print "Bet you can't see me..."
    def accessible(self):
        print "The secret message is:"
        self.__inaccessible()


>>> s=Secretive()
>>> s.__inacessible()

Traceback (most recent call last):
  File "<pyshell#182>", line 1, in <module>
    s.__inacessible()
AttributeError: 'Secretive' object has no attribute '__inacessible'
>>> s.accessible()
The secret message is:
Bet you can't see me...

 在类的内部定义中,所有以双下划线开的名字都被"翻译"成前面加上单下划线和类名的形式

>>> Secretive._Secretive__inaccessible
<unbound method Secretive.__inaccessible>
>>> s._Secretive__inaccessible()
Bet you can't see me...

类的命名空间

 定义类时,所有位于class语句中的代码都在特殊的命名空间中执行---类的命名空间。这个命名空间可由类内所有成员访问。

类的定义其实就是执行代码块

 

>>> class MemberCounter:
    members=0
    def init(self):
        MemberCounter.members+=1


>>> m1=MemberCounter()
>>> m1.init()
>>> m1.members
1
>>> m1.members=2
>>> m1.members
2
>>> m2=MemberCounter()
>>> m2.init()
>>> m2.members
2
>>> m2.init()
>>> m2.members
3
>>> m1.members
2
>>> 

 新members值被写到了m1的特性中,屏蔽了类范围内的变量

超类

>>> class Filter:
    def init(self):
        self.blocked=[]
    def filter(self,sequence):
        return [x for x in sequence if x not in self.blocked]


>>> class SPAMFilter(Filter):
    def init(self):
        self.blocked=['SPAM']


>>> f=Filter()
>>> f.init()
>>> f.filter([1,2,3])
[1, 2, 3]
>>> s=SPAMFilter()
>>> s.init()
>>> s.filter(['SPAM','SPAM','egg','name','ff'])
['egg', 'name', 'ff']

继承,超类

>>> class Filter:
    def init(self):
        self.blockes=[]
    def filter(self,sequence):
        return [x for x in sequence if x not in self.blocked]


>>> class S(Filter):
    def init(self):
        self.blocked=['s']


>>> f=Filter()
>>> f.init()
>>> f.filter([1,2,3])

多个超类

先继承的类中的方法会重写后继承的类中的方法

>>> class C():
    def calculate(self,expression):
        self.value=eval(expression)


>>> class Talker():
    def talk(self):
        print 'Hi,my value is',self.value


>>> class TalkingCalculator(C,Talker):
    pass

>>> tc=TalkingCalculator()
>>> tc.calculate('1+2*3')
>>> tc.talk()
Hi,my value is 7

 

类是什么 可以视为种类或者类型的同义词。所有的对象都属于某一个类,称为类的实例。 例如:鸟就...

对象的魔力

术语对象基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。
对象的优点

  • 多态
  • 封装
  • 继承

多态

多态——就算不知道变量所引用的对象类型是什么,还是能对它进行操作,而它也会根据对象(或者类)类型的不同而表现出不同的行为。

多态和方法

程序接收到一个对象,完全不知道对象的内部实现方式——它可能有多种“形状”。你要做的就是询问价格,这就够了,实现方法是我们熟悉的:

>>> object.getPrice()
2.5

绑定到对象特性上面的函数称为方法

多态的多种形式

任何不知道对象到底是什么类型,但是又要对对象"做点什么"的时候,都会用到多态。
不仅仅限于方法,很多内建的运算符和函数都有多态形式。

封装

封装是指向程序中的其他部分隐藏对象的具体实现细节的原则——也是使用对象而不用知道其内部细节。
多态可以让用户对于不知道是什么类(对象类型)的对象进行方法调用。
封装是可以不用关心对象是如果构建的而直接进行使用。
需要将对象进行抽象,调用方法的时候不用关心其他的东西,比如它是否干扰了全局变量。所以能将名字封装在对象内部——可以将其作为特性存储。特性是作为变量构成对象的一部分,事实上方法更像是绑定到函数上的属性。
对象有它自己的状态。对象的状态由它的特性(比如名称)来描述。对象的方法可以改变它的特性。

笔者sniper这一章节前前后后看了三遍才明白,很多时候我们需要一个直观地感受,但是书中没有列出。我这里写一下自己的感受——特性就相当于是def __init__(self): self.name = [ ],相当于变量名称。而方法就是def function_test(self): print 'This is a test function'。再直观点就是特性是类中的self变量,方法就是类中能直接调用的函数。

继承

集成就是子类集成部分或全部父类的功能,但是还可以拥有属于自己的独特功能。

类和类型

类到底是什么

类——一种对象。所有的对象都属于一个类,称为类的实例。
一个类的定义取决于它所支持的方法。类的所有实例都会包含这些方法,所以所有子类的所有实例都有这些方法。定义子类只是个定义更多(也有可能是重载已经存在的)的方法的过程。

创建自己的类

class Person:
    def setName(self, name):
        self.name = name
    def getName(self):
        return self.name
    def greet(self):
        print "Hello, world! I'm %s." % self.name

>>> foo = Person()
>>> bar = Person()
>>> foo.setName('xxz')
>>> bar.setName('zlr')
>>> foo.greet()
Hello, world! I'm xxz
>>> bar.greet()
Hello, world! I'm zlr

在调用foo的setName和greet函数时,foo自动将自己作为第一个参数传入函数中——因此形象地命名为self。对于这个变量,每个人可能都会有自己的叫法,但是因为它总是对象自身,所以习惯上总是叫做self。
特性可以在外部访问

>>> foo.name
'xxz'

如果知道foo是Person的实例的话,那么还可以把foo.greet()看做Person.greet(foo)方便的简写。

特性、函数和方法

self参数事实上正式方法和函数的区别。方法(绑定方法)将它们的第一个参数绑定到所属的实例上,因此无需显示提供该参数。当然也可以将特性绑定到一个普通函数上,这样就不会有特殊的self参数了。

再论私有化
私有特性——外部无法像foo.name一样访问的特性。只能够使用内部的setName和getName等访问器能够访问的特性。
让方法或者特性变为私有(从外部无法访问),只要在它们名字前加上双下划线即可__
类的内部定义中,所有以双下划线开始的名字都被"翻译"成前面加上单下划线和类名的形式。

s._Secretive__inaccessible()
Bet you can't see me...

*如果不需要使用这种方法但是又想让其他对象不要访问内部数据,那么可以使用单下划线_。这不过是个习惯,但的确有效。前面有下划线的名字都不会被带星号的import语句(from module import )导入。**

类的命名空间

定义类时,所有位于class语句中的代码都在特殊的命名空间中执行——类命名空间。
在实例总重新绑定numbers特性,新的numbers值会被写到m1的特性中,屏蔽了类范围内的变量numbers。

指定超类

子类扩展超类——将其他类的名字写在class语句后的圆括号内就可以指定超类。

class Filter:
    def init(self):
        self.blocked = []
    def filter(self, sequence):
        return [x for x in sequence if x not in self.blocked]

class SPAMFilter(Filter): # SPAMFilter is a subclass of Filter
    def init(self): # Overrides init method from Filter superclass
        self.blocked = ['SPAM']

Filter是个用于过滤的通用类,实际上它不能过滤任何东西。但是可以作为其他类的基类(超类),比如SPAMFilter类,可以将序列中的'SPAM'过滤出去。

  • 这里用提供新定义的方式重写了Filter的init定义
  • filter方法的定义是从Filter类中拿来继承的,所以不用重写它的定义。

检查继承

如果想要查看一个类是否是另一个类的子类,可以使用内建的issubclass函数:

>>> issubclass(SPAMFilter, Filter)
True
>>> issubclass(Filter, SPAMFilter)
False

如果想要知道已知类的基类(们),可以直接使用它的特殊特性__bases__:

>>> SPAMFilter.__bases__
(<class __main__.Filter at 0x171e**)
>>> Filter.__bases__
()

同样,还能使用isinstance方法检查一个对象是否是一个类的实例:

>>> s = SPAMFilter()
>>> isinstance(s, SPAMFilter)
True
>>> isinstance(s, Filter)
True
>>> isinstance(s, str)
False

如果只想知道一个对象属于哪个类,可以使用__class__特性:

>>> s.__class__
<class __main__.SPAMFilter at 0x71e**>

多个超类

一个类可能有多个基类(超类)。

class Calculator:
    def calculate(self, expression):
        self.value = eval(expression)

class Talker:
    def talk(self):
        print 'Hi, my value is ', self.value

class TalkingCalculator(Calculator, Talker):
    pass

>>> tc = TalkingCalculator()
>>> tc.calculate('1+2+3')
>>> tc.talk()
'Hi, my value is 7

这种行为称为多重继承
如果一个方法从多个超类中继承,那么必须注意超类的顺序(先继承的类中的方法会重写后集成类中的方法),例如Calculator类也有一个talk的方法,那么它就会重写Talker类的talk方法。

接口和内省

接口的概念与多态有关。在处理多态对象时,只要关心它的接口(或者称为协议)即可,也就是公开的方法和特性。在Python中,不用显式的指定对象必须包含哪些方法和特性才能作为参数接收。
检查所需方法是否存在:

>>> hasattr(tc, 'talk')
True
>>> hasattr(tc, 'fnord')
False

检查talk特性(包含一个方法)是否可调用

>>> callable(getattr(tc, 'talk', None))
True
>>> callable(getattr(tc, 'fnord', None))
False

本段代码中使用了getattr函数,而没有在if语句中使用hasattr函数直接访问特性,getattr函数允许提供默认值(这里是'None'),以便在特性不存在时使用,然后对返回的对象使用callable函数。与getattr对应的是setattr函数

一些关于面向对象设计的思考

  • 将属于一类的对象放在一起。如果一个函数操纵一个全局变量,那么两者最好都在累内作为特性和方法出现。
  • 不要让对象过于亲密。方法应该只关心自己实例的特性。让其他实例管理自己的状态。
  • 要小心继承,尤其是多重继承。继承机制有时很有用,但也会在某些情况下让事情变得过于复杂。多继承难以正确使用,更难以调试。
  • 简单就好。让你的方法小巧。一般来说,多数方法都应该在30秒内被读完(以及理解),尽量将代码行数控制在一页或者一屏之内。

当考虑需要什么类以及类要有什么方法时,应该尝试下面的方法

  • 写下问题的描述(程序要做什么),把名词、动词、形容词加下划线
  • 对于所有名词,用作可能的类
  • 对于所有动词,用作可能的方法
  • 对于所有形容词,用作可能的特性
  • 把所有的方法、特性分配到类中

小结

对象

多态
封装
继承
接口和内省
面向对象设计

本文由编程应用发布,转载请注明来源:尤为空虚,python中类和项目介绍