python基础题(1)
1、python传参问题
def fun(a):
a = 2
fun(a)
print(a) # 1
a = []
def fun(a):
a.append(1)
fun(a)
print(a) # [1]
关键:只需要记住类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而 list, dict, set 等则是可以修改的对象。(那么在传参之后,如果赋值对象的数据类型数可变的,参数值就会改变,而地址不会变;如果赋值对象数据类型数不可变的,原来的引用地址和值就不会变,但是赋值对象的地址和值是会变的)
例如: 下面a是列表,可变类型,在进行了a.append()操作后,a的值改变,地址不变
a = []
def fun(a):
print( "func_in",id(a) # func_in 53629256
a.append(1)
print ("func_out",id(a)) # func_out 53629256
fun(a)
print(a) # [1]
再例如:下面a是numbers不可变类型,在进行a=2赋值操作,当时a指向了2这个地址,a地址就变成了2的地址,但是函数出来之后,a的地址还是回到了1地址并没有改变
a = 1
def fun(a):
print("func_in",id(a)) # func_in 41322472
a = 2
print ("re-point",id(a), id(2)) # re-point 41322448 41322448
print("func_out",id(a), id(1)) c# func_out 41322472 41322472
fun(a)
print a # 1
2、实例方法,类方法@classmethod和静态方法@staticmethod
先看一下:
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,self和cls是对类或者实例的绑定,可以替换别的参数,但是python的约定是这俩,还是不要改的好.
(1)一般方法,我们可以这么调用foo(x),这个函数就是最常用的,它的工作跟任何东西(类,实例)无关。
(2)实例方法,我们知道在类里每次定义方法的时候都需要绑定这个实例,就是foo(self, x),调用时:a.foo(x) (本质其实是foo(a, x))
(3)类方法一样,只不过它传递的是类而不是实例,A.class_foo(x)。
(4)静态方法,其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用的时候需要使用a.static_foo(x)或者A.static_foo(x)来调用.

3、类变量和实例变量
类变量:
是可在类的所有实例之间共享的值(也就是说,它们不是单独分配给每个实例的)。例如下例中,num_of_instance 就是类变量,用于跟踪存在着多少个Test 的实例。
实例变量:
实例化之后,每个实例单独拥有的变量。
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
这里name就是类变量,参考上面讲的传参问题,因为“aaa”是字符串类型,所以实例p1调用这个类变量,并不会改变类变量本身的地址,所以实例p2调用时,变量值并不会变,而如果类变量类型是可变的,调用他,变量值就会改变但是地址不会变,看下面的例子:
class Person:
name=[]
p1=Person()
p2=Person()
p1.name.append(1)
print(p1.name) # [1]
print( p2.name) # [1]
print( Person.name) # [1]
4、Python自省
这个也是python彪悍的特性.
自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.不用定义,赋什么类型的值它就会是什么类型的变量,比如type(),dir(),getattr(),hasattr(),isinstance().
a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print(type(a),type(b),type(c)) # <type 'list'> <type 'dict'> <type 'bool'>
print(isinstance(a,list)) # True