码迷,mamicode.com
首页 > 编程语言 > 详细

《零基础学Python(第二版)》(四)

时间:2015-07-30 17:05:52      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:读书笔记   python   

下面开始是进阶部分了。

四、类

       1. 类 

       在Python2.2之前使用的是旧式类,2.2版本之后使用的是新式类,但是在Python3之后就不存在这个问题了。下面谈论的问题是关于新式类的。

        关于新式类的定义有两种方式。

       1)继承性定义。

<span style="font-size:18px;">class A(object):
	pass
a = A()
print a.__class__		#<class '__main__.A'>
print type(a)			#<class '__main__.A'></span>
       2)在类的前面写上这么一句:__metaclass__ == type(表示下面定义的类是新式类),然后定义类的时候,就不需要在名字后面写(object)了。

<span style="font-size:18px;">__metaclass__ = type
class A:
	pass
a = A()
print a.__class__		#<class '__main__.A'>
print type(a)			#<class '__main__.A'></span>
       下面介绍了创建一个新的类。类中的方法的参数必须包括self参数,并且作为默认的第一个参数。def __init__叫做初始化函数。

<span style="font-size:18px;">__metaclass__ = type
class Person:
	def __init__(self,name):
		self.name = name
	def getName(self):
		return self.name
	def age(self,age):
		print "%s is %d years old" % (self.name,age)
p = Person('why')
print p.getName()	#why
p.age(22.5)			#why is 22 years old

</span>

        当类中变量引用的是不可变数据时,实例属性不会影响类属性,而类属性会影响实例属性。当类中变量引用的是可变对象时,类属性和实例属性都能直接修改这个对象,从而影响另一方的值。 

<span style="font-size:18px;">class A(object):
	x = 3
	y = [1,2,3]
a = A()
a.x = 4
print A.x		#3
print a.x		#4
a.y.append(4)
print A.y		#[1, 2, 3, 4]
print a.y		#[1, 2, 3, 4]</span>
         在类确定或者实例化之后,也可以增加和修改属性,其方法就是通过类或者实例的点号操作来实现,即object.attribute,可以实现对属性的修改和增加。但是增加实例属性,类属性不会变。

<span style="font-size:18px;">class A(object):
	x = 3
	y = [1,2,3]
a = A()
a.z = 'why'
print a.z	#why
print A.z	#AttributeError: type object 'A' has no attribute 'z'
A.q = 22.5
print a.q	#22.5
print A.q	#22.5</span>

          命名空间因为对象的不同,也有所区别,可以分为如下几种:

          1)内置命名空间(Built-in Namespaces):Python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如d(),不需要做什么操作,拿过来就直接使用了。

          2)全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。

          3)本地命名空间(Function&Class: Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。

          此外,还谈到了数据轮转和作用域的问题。

          下面是谈了类的继承和方法的重写,由于和JAVA差不多,所以不再赘述。

          在旧式类中多重继承的顺讯是依照深度优先来的,而在新式类中是按照广度优先来的。类的__mro__属性可以得到类的继承顺序。

<span style="font-size:18px;">class A(object):</span>
<span style="font-size:18px;">	def foo(self):
		print "foo A"
class B(object):
	def foo(self):
		print "foo B"
	def bar(self):
		print "bar B"
class C(A,B):
	pass
class D(A,B):
	def bar(self):
		print "bar D"
class E(C,D):
	pass
print E.__mro__	   #(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
e = E()
e.foo()		#foo A
e.bar()		#bar D</span>
         在新式类中如果要调用父类的方法,可使用super函数,尤其是在初始化函数的时候。super函数的参数,第一个是当前子类的类名字,第二个是self,然后是点号,点号后面是所要调用的父类的方法。

<span style="font-size:18px;">__metaclass__ = type
class Person:
	def __init__(self):
		self.name = 'why'
	def p(self):
		print "My name is {}".format(self.name)
class Employer(Person):
	def __init__(self):
		super(Employer,self).__init__()
		self.age = 22.5
	def p(self):
		print "I am {} years old".format(self.age)
		super(Employer,self).p()
e = Employer()
e.p()
# I am 22.5 years old
# My name is why</span>

        在python中:@staticmethod表示下面的方法是静态方法,@classmethod表示下面的方法是类方法。静态方法依然用def语句来定义。需要注意的是文件名后面的括号内没有self,那么也就无法访问实例变量、类和实例的属性了,因为它们都是借助self来传递数据的。类方法的参数也没有self,但是必须有cls这个参数。在类方法中,能够访问类属性,但是不能访问实例属性。两种方法都可以通过实例调用,即绑定实例。也可以通过类来调用。关于两者的差异看以参见这篇文章PYTHON中STATICMETHOD和CLASSMETHOD的差异

        在函数、类或者文件开头的部分写文档字符串说明,一般采用三重引号。这样写的最大好处是能够用help()函数看。

<span style="font-size:18px;">"""This is python lesson"""
def start_func(arg):
    """This is a function."""
    pass
class MyClass:
    """This is my class."""
    def my_method(self,arg):
        """This is my method."""
        pass</span>

        2. 多态和封装        

       count()函数的作用是数一数某个元素在对象中出现的次数。

<span style="font-size:18px;">print "wwhhy".count('w')		#2
print [1,1,2,3,4].count(2)		#1</span>
        repr()函数能够针对输入的任何对象返回一个字符串。用它可以体现出多态。

<span style="font-size:18px;"><span style="font-size:18px;">def length(x):
	print "the length of " , repr(x) , "is ", len(x)
length([1,2,3])				#the length of  [1, 2, 3] is  3
length('why')				#the length of  'why' is  3
length({1:'why',2:'zmq'})	#the length of  {1: 'why', 2: 'zmq'} is  2</span></span>
        python中私有化的方法也比较简单,就是在准备私有化的属性(包括方法、数据)名字前面加双下划线。如果要调用那些私有属性可以使用property函数。用了@property之后,在调用那个方法的时候,用的是p.xx的形式,就好像在调用一个属性一样,

<span style="font-size:18px;">__metaclass__ = type
class A:
    def __init__(self):
        self.me = "why"
        self.__name = "zmq"
    @property
    def name(self):
        return self.__name
if __name__ == "__main__":
    p = A()
    print p.name		#zmq</span>

        3. 特殊方法        

        接下来介绍了几个特殊方法:

        1)__dict__:保存了对象的属性。下面是一个综合的例子,属性和方法的情况都类似。

<span style="font-size:18px;">class A(object):
	name = 'why'
print A.__dict__	#{'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, 'name': 'why', '__doc__': None}
print A.__dict__['name']	#why
print A.name				#why
a = A()						
print a.__dict__			#{}
print a.name				#why
a.name = 'zmq'
print a.__dict__			#{'name': 'zmq'}
print a.__dict__['name']	#zmq
print a.name				#zmq
print A.__dict__	#{'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, 'name': 'why', '__doc__': None}
print A.__dict__['name']	#why
print A.name				#why
del a.name
print a.__dict__			#{}
print a.name				#why
a.age = 22.5
print a.__dict__			#{'age': 22.5}
print a.age					#22.5
print A.__dict__['age']		#KeyError: 'age'
print A.age					#AttributeError: type object 'A' has no attribute 'age'
A.major = 'computer'
print a.__dict__			#{'age': 22.5}
print a.major				#computer</span>
         2)_slots__:能够限制属性的定义,在编程中非常重要的方面是优化内存使用。_slots__已经把实例属性牢牢地管控了起来,但更本质是的是优化了内存。这种优化会在大量的实例时候显出效果。

<span style="font-size:18px;">class A(object):
	__slots__ = ('name','age')
print A.__slots__		#('name', 'age')
a = A()
print a.__slots__		#('name', 'age')
A.name = 'why'
print a.name			#why
# a.name = 'zmq'			#AttributeError: 'A' object attribute 'name' is read-only
a.age = 22.5
print a.age				#22.5
print A.age				#<member 'age' of 'A' objects>
A.age = 23
print a.age				#23
a.major = 'computer'	#AttributeError: 'A' object has no attribute 'major'</span>
         3)__setattr__(self,name,value):如果要给name赋值,就调用这个方法。

         4)__getattr__(self,name):如果name被访问,同时它不存在的时候,此方法被调用。

<span style="font-size:18px;">class A(object):
	def __getattr__(self, name):
		print "You use getattr"
	def __setattr__(self, name, value):
		print "You use setattr"
		self.__dict__[name] = value
a = A()
a.x				#You use getattr
a.x = 3			#You use setattr
print a.x		#3</span>

         5)__getattribute__(self,name):当name被访问时自动被调用(注意:这个仅能用于新式类),无论name是否存在,都要被调用。

         6)__delattr__(self,name):如果要删除name,这个方法就被调用。

<span style="font-size:18px;">class B(object):
	def __getattribute__(self, name):
		print "you are useing getattribute"
		return object.__getattribute__(self, name)
b = B()
b.y				#you are useing getattribute     AttributeError: 'B' object has no attribute 'y'
b.y = 4
print b.y			#4</span>
         通过实例获取其属性,如果在__dict__中有相应的属性,就直接返回其结果;如果没有,会到类属性中找。如果没有定义__getattr__()方法,就会引发AttributeError。
<span style="font-size:18px;">__metaclass = type
class A:
	name = 'why'
	def __getattr__(self,key):
		if key != 'name':
			return "check again"
a = A()
print a.name		#why
print a.major		#check again</span>
         4. 迭代器
         __iter__就是对象的一个特殊方法,它是迭代规则的基础。对象如果没有它,就不能返回迭代器,就没有next()方法,就不能迭代。可以让自己写的对象能够迭代。
<span style="font-size:18px;">__metaclass__ = type
class A:
	def __init__(self,n):
		self.i = 0
		self.n = n
	def __iter__(self):
		return self
	def next(self):
		if self.i < self.n:
			i = self.i
			self.i += 1
			return i
		else:
			raise StopIteration()
if __name__ == "__main__":
	a = A(7)
	print a.next()
	print a.next()
	print "------------"
	for i in a:
		print i
# 0
# 1
# ------------
# 2
# 3
# 4
# 5
# 6</span>

         关于列表和迭代器之间的区别,还有两个非常典型的内建函数:range()和xrange()。range()返回的是一个列表,xrange()返回的是一个对象,在循环的时候稍快并有更高的内存效率。即通过range()得到的列表,会一次性被读入内存,而xrange()返回的对象,则是需要一个数值才从返回一个数值。下面的例子将会体现xrange()函数的优势。

<span style="font-size:18px;">__metaclass__ = type
a = range(4)
b = xrange(10000)
print zip(a,b)		3[(0, 0), (1, 1), (2, 2), (3, 3)]</span>
        5. 生成器
        生成器必须是可迭代的,它比列表有更好的执行效率。表示形式是将列表解析的 { } 其换成 ( ) 。

<span style="font-size:18px;"><span style="font-size:18px;">a = (i**2 for i in range(4))
for i in a:
	print i,		#0 1 4 9
print ""
for i in a:
	print i,		#</span></span>
            yeild关键词是生成器的标识。函数返回值是一个生成器类型的对象,这个生成器对象就是迭代器。我们把含有yield语句的函数称作生成器。生成器是一种用普通函数语法定义的迭代器。

<span style="font-size:18px;">def a():
	yield 0
	yield 1
	yield 2
a = a()
print a.next()		#0
print a.next()		#1
print a.next()		#2
print a.next()		#StopIteration
</span>
         发现yield除了作为生成器的标志之外,还有一个功能就是返回值。return会结束函数体的执行,而yeild则会暂时挂起,等到下次调用next方法时再继续。

<span style="font-size:18px;">def a():
	print "before"
	for i in range(4):
		return i
		print "after"
aa = a()				#before
print aa				#0
print aa				#0
def b():
	print "before"
	for i in range(4):
		yield i
		print "after"
bb = b()				#before
print bb.next()			#0
print bb.next()			#after 1</span>


版权声明:本文为博主原创文章,未经博主允许不得转载。

《零基础学Python(第二版)》(四)

标签:读书笔记   python   

原文地址:http://blog.csdn.net/u012421846/article/details/47092717

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!