《零基础学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>

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

时间: 2024-08-24 14:34:33

《零基础学Python(第二版)》(四)的相关文章

[基础] Java目录(摘自Java核心技术·卷1 基础知识)

Java核心技术·卷1 基础知识(原书第9版) 第1章 Java程序设计概述 1.1 Java程序设计平台 1.2 Java"白皮书"的关键术语 1.2.1 简单性 1.2.2 面向对象 1.2.3 网络技能 1.2.4 健壮性 1.2.5 安全性 1.2.6 体系结构中立 1.2.7 可移植性 1.2.8 解释型 1.2.9 高性能 1.2.10 多线程 1.2.11 动态性 1.3 Java applet与Internet 1.4 Java发展简史 1.5 关于Java的常见误解

《java核心技术 卷1 基础知识》二

<Java核心技术 卷1 基础知识>第4-5章 在Java中没有类就无法做任何事情 new操作符的返回值是一个引用 在Java中,如果使用一个未初始化的指针,运行系统会产生一个运行时错误. Date 用来表示时间点 LocalDate 日历表示法 同时不推荐使用Date类来处理日历 推荐使用LocalDate来处理日历 每一个拥有名字的类都会被编译生成对应的class文件 所有的Java对象都是在堆中构造的,构造器总是随着new操作符一起使用 在Java中,所有的方法都必须在类的内部定义,但并

《Java核心技术 卷1 基础知识》三

<Java核心技术 卷1 基础知识> 第六章 接口和内部类 接口不是类,而是对类的的一组需求描述. 接口不能包含实例域--接口没有实例 可以将接口看作没有实例域的抽象类 要将类声明为实现某个接口,需要使用关键字implements. 类实现一个接口的具体步骤为: 1)使用implements关键字进行声明要实现的接口 2)对接口中的所有方法进行定义 接口中的所有方法默认为public 但在实现接口时需要声明为public 这里介绍了Comparable接口,该接口只有一个方法,compareT

《Java核心技术 卷1 基础知识》七

<Java核心技术 卷1 基础知识> 第10章 图形程序设计 在Java1.0刚出现时,就包含了一个基本GUI程序设计的类库,即抽象窗口工具箱(Abstract Window Toolkit,AWT) 基本AWT库采用将处理用户界面元素的任务委派给每个目标平台(如windows.Macintosh等)的本地GUI工具箱的方式, 由本地工具箱负责用户界面元素的创建和动作 但由于在不同的平台上,操作行为有一些微妙的差别 因此,AWT也由"一次编写,随处使用"变为"一次

《Java核心技术 卷1 基础知识》一

<java核心技术卷1 第1-3章> JDK Java Development Kit ,即Java开发工具包 但这个工具包的1.2-1.4版本被称为Java SDK,随后才改名为JDK JRE Java运行时环境,它包含虚拟机但不包括编译器 Java SE,Java Standard Edition,Java标准版本 Java EE,Java Enterprise Edition,Java企业版本 Java ME,Java Micro Edition,Java微观版本 Java2 这种提法始

《Java核心技术 卷1 基础知识 原书第9版》pdf

下载地址:网盘下载 内容简介 编辑 CayS.Horstmann等编著,公飞编译的<Java核心技术>(CoreJava)自第1版出版以来,一直备受广大Java程序设计人员的青睐,畅销不衰,是Java经典书籍.第8版针对JavaSE6平台进行了全面更新,囊括了Java平台标准版(JavaSE/J2SE)的全部基础知识,提供了大量完整且具有实际意义的应用实例,详细介绍了Java语言基础知识.面向对象程序设计.接口与内部类.事件监听器模型.swing图形用户界面程序设计.打包应用程序.异常处理.登

《Java核心技术 卷1 基础知识》四

第7章 异常.断言和日志 异常 在Java中,所有异常对象都是派生于Throwable类的一个实例. 如果Java内置的异常类不能够满足需求,用户可以创建自己的异常类 Error类层次结构描述了Java运行时系统的内部错误和自愿耗尽错误,应用程序不应该抛出这种类型的对象. Exception层次结构又分解为两个分支,一个分支派生于RuntimeException:另一个分支包含其他异常. 划分这两个分支的规则为: 由程序错误导致的异常属于RuntimeException: 程序本身没有问题,但由

Java核心技术 卷1 基础知识-第一天

基本数据类型 java是一种强数据类的的语言 共有8种基本数据类型 其中: 整型4种 int(4字节) short(2字节) long(8字节) byte(1字节) java中整型的范围与机器无关 长度是一定的,不会因为跨平台造成整数溢出 浮点型 两种 double float double的长度是float长度的两倍,双精度数值 但部分都是使用double ,在表示的时候 如果写作3.24 编译器会人会认为是double型 3.24F是float型 浮点数有三个特殊值 正无穷大 (正整数除以0

Java details from Java核心技术 卷1 基础知识(1)

Java是一种包括语言.虚拟机.即时编译.类库.执行环境的平台: 执行环境提供安全性.跨操作系统的可移植性.自动垃圾收集等服务: 设计初衷:简单性.面向对象.网络技能.健壮性.安全性.体系结构中立.可移植性.解释型.高性能.多线程.动态性 简单性:Java剔除了C++中的:头文件.指针运算(甚至指针语法).结构.联合.操作符重载.虚基类等: 面向对象:一种程序设计技术.C++多继承:Java单继承+接口.Java中元类模型(metaclass): 网络技能:Java应用程序能够通过URL打开和访

Java 核心技术 卷1 基础知识 List 13.1

List 13.1  LinkList/LinkedListTest.java java容器之LinkList package linkList; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; public class LinkListTest{ public static void main(String args[]){ List<String> a=new Linked