Python入门教程(三)


  按理说,这篇是收尾了。可能有一点术语,但大都是顾名思义的。重要概念【】在第二个标题下说明。html


函数式编程(缩写:FP)python

  若是对此有兴趣,能够看scheme视频教程(SICP公开课)(scheme是lisp的一种),也能够直接看SICP中译本。我只是“知其大略”罢了。算法

  语言若是有如下特征之一,能够被认为有“函数式编程风格”(若是代码使用了这些特征,也说这些代码“有函数式编程风格”):编程

  1:函数和数分庭抗礼,毕竟都是用符号表示而已。若是你在中学时对函数有了不错的理解(测试:f(x)什么意思?为何这样写?),那么会很容易明白下面这几行代码在作什么:
数组

def f(x):
	return 2*x

g = f
print(g(3))

  2:容许用lambda 表达式。这个慢慢会理解的,意思是函数的本质在内容,不在名字,所以操做能够不取名,直接用内容表示。用处主要在,某些函数(好比map)要求你传入一个函数当作参数,你能够不取名(用def定义必须取名)而一会儿传入。在tk中遇到过用lambda强制传参,呃……到时候上网查。ide

  3:能够在函数内再定义函数,python中能够这么作,但官方不但愿这么作。函数内部的东西是对外隐藏的,所以若是在A函数内部定义B函数,那么只有在A内部才可使用B函数(变量也同样)。可是Python做为解释性语言,每次调用函数就是把内部语句(包括def)全执行一遍,这很是浪费。咱们仅仅是想表示“B函数只能被A引用”,却要负担如此后果,彷佛不值得。可是并列放置,难免看起来没有层次……(这对强迫症尤为重要)函数式编程


面向对象(缩写:OOP)函数

  也是一种风格,和FP不冲突,和FP也有交集。顾名思义,就是关注对象。说某种语言面向对象,主要是说有“类”这么个概念。面向对象也被称为“贴近人的思考过程”,人就是面向对象的(能够先不理解这个说法)。测试

  ……python的类真的不大好讲。好比要储存一个点,你能够用一个字典(比元组好,由于不须要顺序而且份量有名字),像这样:ui

p1 = {'x' : 3, 'y' : 4}       #表示横坐标为3,纵坐标为4的点
print(

  类和这很类似,以致于我不懂类的时候,把一个pygame程序中的(简单的)类全用字典表示了。若是用类,能够达到这种效果:(省略了定义类的步骤,因此不要尝试运行)

p1 = Point(3,4)
print(p1.x)
print(p1.y)

  若是你须要好几个点,那么这无疑比字典好得多了。或者遇到这种状况:

a = People('Jack', 7)
print(a.name)
print(a.age)

  这至少看着很优雅。这里,People和Point是“类”,p1和a是对应类的“实例”,建立实例又称“实例化”。我如今补上定义部分,应该很容易懂,至少对于一部分……

class Point:
	def __init__(self,a,b):
		self.x = a
		self.y = b
		
class People:
	def __init__(self,a,b):
		self.name = a
		self.age = b

  我一开始也不懂self是啥,并且教程说“能够把self换成任何东西”。你必定但愿写这样的代码,或者假如是这样你就能懂——(你知道init是英文“定义”的缩写)

class Point:
	def init(a,b):
		x = a
		y = b
		
class People:
	def init(a,b):
		name = a
		age = b

  实不相瞒,若是不是python,好比C#,那么就是这样子的,并无self 。你彻底就能够把self当成摆设,先用习惯,而后听我下面的解释(我认真的)。

  如下两段代码作的事是彻底相同的:

class People:
	def __init__(self,a,b):
		self.name = a
		self.age = b

x = People('Jack',7)
class People: pass
x = object.__new__(People)
x.name = 'Jack'
x.age = 7

  首先,name和age看似成了“固有属性”,其实压根没有这回事。在默认状况下,python中的类是能够【随时】添加【任意】属性的。你能够在上述(任一)代码段后加上一句x.hello = 1,而后hello就也成了x的属性。对于第二段代码,第一行显然是“建立了一个叫People 的类,但没有内容”,第二行是建立了一个People的对象,但显然它没有属性,毕竟定义类的时候什么都没写,剩下两行给这个对象追加了两个属性。其实你大概已经想到,建立和初始化是两个过程,建立是建立空对象,初始化则添加属性。而添加什么属性,就写在初始化函数里。self你也该明白个大概了,若是我再改一改写法——(先后双下划线表示这个函数是官方的,比较特殊,初始化显然如此)

class People:
	def self.__init__(a,b):
		self.name = a
		self.age = b

  若是写成这样,就“差很少是那个意思”了,把self全换成x,就是x的初始化过程。其实还有一重内幕,那就是用点表示属性也是为了好看,真实状况是这样的:

x.__init__(a,b)     #实际上是下一行的缩写,相传python真的会如出一辙地处理
type(x).__init__(x,a,b)    #type函数返回x的类,等价于下一行
People.__init__(x,a,b)

  既然python内部都把__init__当作有三个参数,那咱们定义的时候写三个参数就合乎情理了。思考:假如你不写self,你以为python会怎么错误地【试图】运行你的东西?

  简洁模式的People('Jack', 7),其实就是先搞一个空对象,而后(不让你看地)执行了x.__init__('Jack', 7) 。请注意!这个函数的惟一特殊之处就是,会在用普通方法建立对象时被调用。你能够在里面写任何东西,包括print,就像对待一个普通函数——而不是方法。你若是不用类而写一个如出一辙的函数,除了不能用“.”来调用,其余事情彻底相同。甚至你能够建立完了继续调用__init__,把x.__init__('Jack', 7)写多少遍都没问题(能够在修改后用它还原),反正python在建立时执行了一遍就无论了。你能够随便写多少个方法。不写self的后果是,你依然能够用People.f(a,b)调用之,原理就是刚才的过程。


编程风格/范式

  能够参考《冒号课堂——编程范式与OOP思想》,不过要注意python没有变量类型,致使没有参数类型,因此自己就是“泛型”;python的一切都是指针(没有变量类型致使), a = 1 意味着在某处建立一个 1,而后把 a 指向那里——而 b = a,表示把 a 储存的位置(这里是那个1的位置)复制给 b ,函数的参数天然本质上也是这些东西,可是这些地址通常都是不可见也不须要可见的;也所以(“不让你看到任何与内存有关的东西”),python不自带数组,python列表和lisp链表是一致的,等等。python不多在意底层算法,python使咱们更容易写出程序结构。


迭代器

  试试 a = range(100) 后 print(a) ,你会发现很奇怪的结果。可是list(a) 就是一个从0到99的列表了,a也并不是全无用处,能够用 for i in a取代for i in range(100) 。在老版的python中,range(100)就等于0-99的列表,若是打印就会显示一个列表。可是只是为了重复100遍,彻底不必先创建一个如此长的列表,只须要计数就能够了,这就是迭代器。它很像一个列表,但并无储存每一项,而是每次计算下一项。这是一类专门用于迭代的对象,能够用list()来转换成列表,也能够直接用for循环遍历。除了range返回的对象有这种性质,map等函数也是如此。若是你想获得列表却获得了奇怪的东西(不止一种),那颇有可能这个东西具有上述两个性质,是迭代器。迭代器被称为“很具备python风格的用法”


修饰器(装饰器)

  有一种有趣的函数,它的输入是一个函数,输出也是一个函数。这种函数就能够做为修饰器,修饰器有个特殊用法,能够经过在某个def上一行写@后跟修饰器名,就能够把那个函数传入修饰器,并用返回的新函数(“修饰后的函数”)覆盖原有函数。好比这个例子:

def h(func):
	def func2(x):
		r = func(x)
		print("Be called:",func)
		return r
	return func2
	
	
@h
def f(x):
	return 2*x


	

a = f(3) + 1

  另外自行搜索@property,还有知乎回答这个连接解释了@staticmethod 和 @classmethod,我是这个回答下的评论。(我感受本身是对的……)


内置函数

  就是python自带的函数,好比print,input等等。

  (耐心查看) 

  Python 内置函数 | 菜鸟教程



  最后,你应该知道,python开发人员给咱们留下了一些忠告,虽然不是硬性规定——(运行如下代码)

import this

  (完)

相关文章
相关标签/搜索