python的类(一)
- 类的初步认识和基本概念
- 问题空间
问题空间是问题解决者对一个问题所达到的全部认识状态,它是由问题解决者利用问题所包含的信息和已贮存的信息主动地构成的。
一个问题一般有下面三个方面来定义:
初始状态——一开始时的不完全的信息或令人不满意的状况;
目标状态——你希望获得的信息或状态;
操作——为了从初始状态迈向目标状态,你可能采取的步骤。
这三个部分加在一起定义了问题空间(problem space)。
- 对象
- 对象(object),台湾译作物件,是面向对象(Object Oriented)中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。
- 对象:一个对象有自己的状态、行为和唯一的标识;所有相同类型的对象所具有的结构和行为在他们共同的类中被定义:
- 状态(state):包括这个对象已有的属性(通常是类里面已经定义好的)在加上对象具有的当前属性值(这些属性往往是动态的)
- 行为(behavior):是指一个对象如何影响外界及被外界影响,表现为对象自身状态的改变和信息的传递。
- 标识(identity):是指一个对象所具有的区别于所有其它对象的属性。(本质上指内存中所创建的对象的地址)
- 面向对象
- 面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
- 类和实例化类
- 类:
class 美女:
胸围 = 90
腰围 = 58
臀围 = 83
皮肤 = white
唱歌()
做饭()
- 实例化:
王美女 = 美女()
a = 王美女.胸围
王美女.皮肤 = black
- 类的基础
- 新式类和旧式类
- 旧式类:
- 新式类和旧式类
>>> class test:
... pass
>>> c = test()
- 新式类:
>>> class test2(object):
... pass
>>> d = test2()
- 新旧区别:
>>> type(c)
<type 'instance'>
>>> c.__class__
<class __main__.test at 0x218b870>
>>> type(d)
<class '__main__.test2'>
>>> d.__class__
<class '__main__.test2'>
两者对于多重继承的查找和调用方法不同,旧式类是深度优先,新式类是广度优先
2.2版本后,建议使用新式类,使用方法两种:__metaclass__ == type
- 类的命名
- class Person,这是在声明创建一个名为"Person"的类。类的名称一般用大写字母开头。如果名称是两个单词,那么两个单词的首字母都要大写。
- 很多程序员喜欢把类里面的函数叫做“方法”,它们本质是一样的。
- 函数的命名方法是以def发起,并且函数名称首字母不要用大写,可以使用aa_bb的样式,也可以使用aaBb的样式。
- 类中的函数(方法)的参数跟以往的参数样式有区别,那就是每个函数必须包括self参数,并且作为默认的第一个参数。
- 构造函数
-
函数
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
def color(self, color):
print "%s is %s" % (self.name, color)
- def __init__(self, name): 叫做初始化函数。self这个参数是必须的,但是很多时候,并不是每次都要从外面传入数据,有时候给初始化函数的某些参数设置默认值,如果没有新的数据传入,就应用这些默认值。
- def getName(self): 返回self.name,即初始化函数中的self.name
-
实例化:
girl = Person('canglaoshi')
name = girl.getName()
- def color(self, color): 同上,但是在调用这个方法的时候,要为后面那个参数传值:
girl = Person('canglaoshi')
girl.color("white")
- 实例化及方法和属性
- “类提供默认行为,是实例的工厂”(源自Learning Python),这句话非常经典,一下道破了类和实例的关系。所谓工厂,就是可以用同一个模子做出很多具体的产品。类就是那个模子,实例就是具体的产品。所以,实例是程序处理的实际对象。类是由一些语句组成,但是实例,是通过调用类生成,每次调用一个类,就得到这个类的新的实例。对于类的:class Person,class是一个可执行的语句。如果执行,就得到了一个类对象,并且将这个类对象赋值给对象名(比如Person)。
- self的作用
- self就是一个实例
- 类的属性
- 类属性和实例属性
-
类属性:renlei
实例属性:
a\b
>>> class renlei(object):
... shengao = 170
... tizhong = 70
>>> a = renlei.shengao
>>> b = renlei.tizhong
>>> a
170
>>> b
70
比如人类是类属性,张三=人类,张三继承人类的属性,则张三是实例属性
互不影响:属性变化后实例属性也会变化,实例属性变化不会影响类属性,如果对实例属性进行修改,则新的实例属性会覆盖旧的实例属性,此时再修改类属性则对新的实例属性无影响,但可以用del删除新的实例属性,并还原为旧的实例属性。
相互影响:当属性是一个可变对象时,变更实例属性或类属性时都会互相影响,比如当属性为一个列表时
相互影响
>>> class B(object):
... y = [1,2,3]
...
这次定义的类中,变量引用的是一个可变对象。
>>> B.y #类属性
[1, 2, 3]
>>> bar = B()
>>> bar.y #实例属性
[1, 2, 3]
>>> bar.y.append(4)
>>> bar.y
[1, 2, 3, 4]
>>> B.y
[1, 2, 3, 4]
>>> B.y.append("aa")
>>> B.y
[1, 2, 3, 4, 'aa']
>>> bar.y
[1, 2, 3, 4, 'aa']
-
- 类内外数据流转
-
为此脚本添加注释
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
def breast(self, n):
self.breast = n
def color(self, color):
print "%s is %s" % (self.name, color)
def how(self):
print "%s breast is %s" % (self.name, self.breast)
girl = Person('canglaoshi')
girl.breast(90)
girl.color("white")
girl.how()
图片
-
- 命名空间
- 命名空间是从所定义的命名到对象的映射集合。不同的命名空间,可以同时存在,当彼此相互独立互不干扰。
- 命名空间因为对象的不同,也有所区别,可以分为如下几种:
- 内置命名空间(Built-in Namespaces):Python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如前面的id(),不需要做什么操作,拿过来就直接使用了。
- 全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。
- 本地命名空间(Function&Class: Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。
- 命名空间中的数据存储结构和dictionary是一样的。
- 访问本地命名空间的方法,用print locals() 完成;访问全局命名空间,可以使用 print globals()
- 作用域
- 作用域是指 Python 程序可以直接访问到的命名空间。"直接访问"在这里意味着访问命名空间中的命名时无需加入附加的修饰符。
- 如果在不同的命名空间有相同名字的变量,则优先选择本地的变量,如果该同名变量是属于其他本地命名空间,则本地作用域也无法访问
- 如果要将某个变量在任何地方都使用,且能够关联,那么在函数内就使用global 声明,其实就是曾经讲过的全局变量。
- 类属性和实例属性
- 继承
- 继承
-
函数:
Girl继承了Person的属性和方法,如果存在冲突,Girl的属性优先
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def speak(self):
print "I love you."
def setHeight(self):
print "The height is: 1.60m ."
def breast(self, n):
print "My breast is: ",n
class Girl(Person):
def setHeight(self):
print "The height is:1.70m ."
if __name__ == "__main__":
cang = Girl()
cang.setHeight()
cang.speak()
cang.breast(90)
-
- 多重继承
-
函数1
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def eye(self):
print "two eyes"
def breast(self, n):
print "The breast is: ",n
class Girl:
age = 28
def color(self):
print "The girl is white"
class HotGirl(Person, Girl):
pass
if __name__ == "__main__":
kong = HotGirl()
kong.eye()
kong.breast(90)
kong.color()
print kong.age
函数2:
继承的顺序:从左往右,先父后子(广度优先)
print C.__mro__可以打印顺序
#!/usr/bin/env python
# coding=utf-8
class K1(object):
def foo(self):
print "K1-foo"
class K2(object):
def foo(self):
print "K2-foo"
def bar(self):
print "K2-bar"
class J1(K1, K2):
pass
class J2(K1, K2):
def bar(self):
print "J2-bar"
class C(J1, J2):
pass
if __name__ == "__main__":
print C.__mro__
m = C()
m.foo()
m.bar()
-
- super函数
-
调用父类的方法(如果被重写过):
在子类中,__init__方法重写了,为了调用父类同方法,使用super(Girl, self).__init__()的方式。
super函数的参数,第一个是当前子类的类名字,第二个是self,然后是点号,点号后面是所要调用的父类的方法。
同样在子类重写的about方法中,也可以调用父类的about方法。
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def __init__(self):
self.height = 160
def about(self, name):
print "{} is about {}".format(name, self.height)
class Girl(Person):
def __init__(self):
super(Girl, self).__init__()
self.breast = 90
def about(self, name):
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
if __name__ == "__main__":
cang = Girl()
cang.about("canglaoshi")
-
- 继承
- 静态方法和类方法
- 静态方法和类方法
-
函数
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class StaticMethod:
@staticmethod
def foo():
print "This is static method foo()."
class ClassMethod:
@classmethod
def bar(cls):
print "This is class method bar()."
print "bar() is part of class:", cls.__name__
if __name__ == "__main__":
static_foo = StaticMethod() #实例化
static_foo.foo() #实例调用静态方法
StaticMethod.foo() #通过类来调用静态方法
print "********"
class_bar = ClassMethod()
class_bar.bar()
ClassMethod.bar()
对于这部分代码,有一处非常特别,那就是包含了“@”符号。在python中:
@staticmethod表示下面的方法是静态方法
@classmethod表示下面的方法是类方法
-
- 两者的区别
- 先看静态方法,虽然名为静态方法,但也是方法,所以,依然用def语句来定义。需要注意的是文件名后面的括号内,没有self,这和前面定义的类中的方法是不同的,也正是因着这个不同,才给它另外取了一个名字叫做静态方法,否则不就“泯然众人矣”。如果没有self,那么也就无法访问实例变量、类和实例的属性了,因为它们都是借助self来传递数据的。
- 再看类方法,同样也具有一般方法的特点,区别也在参数上。类方法的参数也没有self,但是必须有cls这个参数。在类方法中,能够方法类属性,但是不能访问实例属性(读者可以自行设计代码检验之)。
- 简要明确两种方法。下面看调用方法。两种方法都可以通过实例调用,即绑定实例。也可以通过类来调用,即StaticMethod.foo()这样的形式,这也是区别一般方法的地方,一般方法必须用通过绑定实例调用。
- 文章标题是:python中的staticmethod和classmethod的差异。原载:www.pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/。此地址需要你准备梯子才能浏览。后经国人翻译,地址是:http://www.wklken.me/posts/2013/12/22/difference-between-staticmethod-and-classmethod-in-python.html
- 类的文档
- 静态方法和类方法
- 多态和封装
- 多态
-
猫狗实验
#!/usr/bin/env python
# coding=utf-8
"the code is from: http://zetcode.com/lang/python/oop/"
__metaclass__ = type
class Animal:
def __init__(self, name=""):
self.name = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print "Meow!"
class Dog(Animal):
def talk(self):
print "Woof!"
a = Animal()
a.talk()
c = Cat("Missy")
c.talk()
d = Dog("Rocky")
d.talk()
-
- 封装和私有化
-
封装:
python中私有化的方法也比较简单,就是在准备私有化的属性(包括方法、数据)名字前面加双下划线
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class ProtectMe:
def __init__(self):
self.me = "qiwsir"
self.__name = "kivi"
def __python(self):
print "I love Python."
def code(self):
print "Which language do you like?"
self.__python()
if __name__ == "__main__":
p = ProtectMe()
print p.me
print p.__name
调用
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class ProtectMe:
def __init__(self):
self.me = "qiwsir"
self.__name = "kivi"
@property
def name(self):
return self.__name
if __name__ == "__main__":
p = ProtectMe()
print p.name
-
- 多态