函数参数由实参传递给形参的过程,是由参数传递机制控制的。根据实际参数的类型不同,函数参数的传递方式分为值传递和引用传递(地址传递)。
值传递:实际上是将实际参数值的副本(复制品)传入函数,而参数本省不会受到影响。因此,在函数内部的操作,不会影响实际参数值。
def swap(a , b) : # 下面代码实现a、b变量的值交换 a, b = b, a print("swap函数里,a的值是", \ a, ";b的值是", b) a = 6 b = 9 swap(a , b) print("交换结束后,变量a的值是", \ a , ";变量b的值是", b) # 结果 #swap函数里,a的值是 9 ;b的值是 6 #交换结束后,变量a的值是 6 ;变量b的值是 9
引用传递(地址传递):当实际参数的数据类是可变对象时,函数参数的传递方式为引用传递。在函数内部的操作也会影响实际参数。
def swap(dw): # 下面代码实现dw的a、b两个元素的值交换 dw['a'], dw['b'] = dw['b'], dw['a'] print("swap函数里,a元素的值是",\ dw['a'], ";b元素的值是", dw['b']) dw = {'a': 6, 'b': 9} swap(dw) print("交换结束后,a元素的值是",\ dw['a'], ";b元素的值是", dw['b']) # 结果 swap函数里,a元素的值是 9 ;b元素的值是 6 交换结束后,a元素的值是 9 ;b元素的值是 6
@staticmethod:静态方法,@classmethod:类方法,另外还有 实例方法。
def foo(x): print "executing foo(%s)"%(x) class A(object): def foo(self,x): print "executing foo(%s,%s)"%(self,x) @classmethod def class_foo(cls,x): print "executing class_foo(%s,%s)"%(cls,x) @staticmethod def static_foo(x): print "executing static_foo(%s)"%x a=A()
类定义中 self或cls是对实例或类的绑定。对于普通函数,直接调用foo(x);但对于实例方法,在类中定义方法时,需要绑定这个实例,即foo(self,x),那么调用时是a.foo(x)(其实是foo(a,x));类方法一样,但它传递的是类,不需要实例化类就可以被类本身调用;对于静态方法,不需要对谁进行绑定,但调用时仍需要a.static_foo(x)来调用.
类变量:是可在类的所有实例之间共享的变量。
实例变量:实例化后,每个实例单独拥有的变量
class Test(object): num_of_instance = 0 def __init__(self, name): self.name = name # 实例变量 Test.num_of_instance += 1 # 类变量 if __name__ == '__main__': print Test.num_of_instance # 0 t1 = Test('jack') print Test.num_of_instance # 1 t2 = Test('lucy') print t1.name , t1.num_of_instance # jack 2 print t2.name , t2.num_of_instance # lucy 2
class Person: name="aaa" p1=Person() p2=Person() p1.name="bbb" print p1.name # bbb print p2.name # aaa print Person.name # aaa class Person: name=[] p1=Person() p2=Person() p1.name.append(1) print p1.name # [1] print p2.name # [1] print Person.name # [1]
定义类时,name同样是指类变量,但p1.name="bbb"是实例调用类变量并进行赋值操作,在p1的作用域中把类变量的引用改变了,就变为一个实例变量。
而p1.name.append(1)对应的类变量是可变变量,在进行操作时,引用传递,会对类变量产生影响。
自省是指 面向对象的语言所写的程序在运行时,就能知道对象的特性,即运行时能够获得对象的类型。如
type() # 输出对象的类型 dir() # 获得当前模块的属性列表 getattr(object, name, default) # 用于返回一个对象属性值。 hasattr() # 用于判断对象是否包含对应的属性 isinstance() # 判断一个对象是否是一个已知的类型
d = {key: value for (key, value) in iterable}
>>> class MyClass(): ... def __init__(self): ... self.__superprivate = "Hello" ... self._semiprivate = ", world!" ... >>> mc = MyClass() >>> print mc.__superprivate Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: myClass instance has no attribute '__superprivate' >>> print mc._semiprivate , world! >>> print mc.__dict__ {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__foo __:一种约定,python内部的名字,用于区分其他用户自定义的命名。
_foo: 一种约定,用于表明 变量私有,因此无法通过import导入,其他方面与公有属性一样访问。
__foo: 表示私有成员,不能直接访问,但可以通过_class__foo进行访问,可以有效降低有意无意的修改。
"hi there %s" % name
%最烦人的是它无法同时传递一个变量和元组.
迭代器利用iter()创建一个迭代器对象,利用next()输出迭代器的下一个元素。 此外,对于可迭代对象(列表、元组、字符串、集合、字典)等可以利用 for语句进行遍历。
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter __() 与 __next __() 。
class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() myiter = iter(myclass) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) # StopIteration异常用于标识迭代的完成,防止出现无限循环的情况 在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。 class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)
生成器利用 yied 关键字返回一个迭代器,即生成器时一个返回迭代器的函数,只用于迭代操作。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
import sys def fibonacci(n): # 生成器函数 - 斐波那契 a, b, counter = 0, 1, 0 while True: if (counter > n): return yield a a, b = b, a + b counter += 1 f = fibonacci(10) # f 是一个迭代器,由生成器返回生成 while True: try: print (next(f), end=" ") except StopIteration: sys.exit()
>>> L = [x*x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x*x for x in range(10)) >>> g <generator object <genexpr> at 0x0000028F8B774200>
对于上述代码,将列表生成中的 [] 改成 ()后数据结构会发生改变,g改变为一个生成器。
通过列表生产可以直接创建一个列表,但是,受到内存限制,列表容量是有限的。因此可以采用生成器的方式:边循环、边计算。
当你不确定你的函数里将要传递多少参数时你可以用*args传递元组参数(将参数打包成元组传递给函数);**kwargs传递关键字参数(将参数打包成dict传递给函数)。
*args必须在 **kwargs之前,且二者都在形式参数和默认值参数之后。
python垃圾回收机制主要有引用计数、标记-清除、分代回收。
引用计数:PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,其ob_refcnt就会增加;当引用它的对象被删除时,其ob_refcnt就会减少;当引用计数变为0时,该对象生命结束,进行回收。
优点:简单、实时性。
缺点:维护引用计数消耗资源、循环引用
标记-清除:先按需分配,等到没有空闲内存时,从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫内存空间,把所有没标记的对象释放。
分代技术:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个代,垃圾回收频率随着代的存活时间的增大而减少。存活时间通常利用经过几次垃圾回收来度量。
is比较二者的地址是否一致,==比较二者的值是否一致。
python中的拷贝分为 浅拷贝和深拷贝。
浅拷贝:拷贝父对象(将父对象进行拷贝指向不同地址),但对于父对象中的子对象不会进行拷贝(对于子对象指向同一地址)。
深拷贝: 对父对象和子对象同时进行拷贝(指向不同地址)
import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy.deepcopy(a) #对象拷贝,深拷贝 a.append(5) #修改对象a a[4].append('c') #修改对象a中的['a', 'b']数组对象 print 'a = ', a print 'b = ', b print 'c = ', c print 'd = ', d 输出结果: a = [1, 2, 3, 4, ['a', 'b', 'c'], 5] b = [1, 2, 3, 4, ['a', 'b', 'c'], 5] c = [1, 2, 3, 4, ['a', 'b', 'c']] d = [1, 2, 3, 4, ['a', 'b']]
with:上下文管理器,在打开文件时使用,打开文件在进行读写时可能会出现异常状况,如果不用with自己要try,except,finally。with实现了finally中的f.close