-
拿到一个变量,除了用 isinstance() 判断它是否是某种类型的实例外,还有没有别的方法获取到更多的信息呢?例如,已有定义:class Person(object): def __init__(self, name, gender): self.name = name self.gender = genderclass Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score def whoAmI(self): return 'I am a Student, my name is %s' % self.name首先可以用 type() 函数获取变量的类型,它返回一个 Type 对象:>>> type(123)<type 'int'>>>> s = Student('Bob', 'Male', 88)>>> type(s)<class '__main__.Student'>其次,可以用 dir() 函数获取变量的所有属性:>>> dir(123) # 整数也有很多属性...['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]>>> dir(s)['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']对于实例变量,dir()返回所有实例属性,包括`__class__`这类有特殊意义的属性。注意到方法`whoAmI`也是 s 的一个属性。如何去掉`__xxx__`这类的特殊属性,只保留我们自己定义的属性?回顾一下filter()函数的用法。dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了:>>> getattr(s, 'name') # 获取name属性'Bob'>>> setattr(s, 'name', 'Adam') # 设置新的name属性>>> s.name'Adam'>>> getattr(s, 'age') # 获取age属性,但是属性不存在,报错:Traceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'Student' object has no attribute 'age'>>> getattr(s, 'age', 20) # 获取age属性,如果属性不存在,就返回默认值20:20
查看全部 -
函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类,它们本质上都是数据类型。假设有如下的 Person、Student 和 Teacher 的定义及继承关系如下:class Person(object): def __init__(self, name, gender): self.name = name self.gender = genderclass Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = scoreclass Teacher(Person): def __init__(self, name, gender, course): super(Teacher, self).__init__(name, gender) self.course = coursep = Person('Tim', 'Male')s = Student('Bob', 'Male', 88)t = Teacher('Alice', 'Female', 'English')当我们拿到变量 p、s、t 时,可以使用 isinstance 判断类型:>>> isinstance(p, Person)True # p是Person类型>>> isinstance(p, Student)False # p不是Student类型>>> isinstance(p, Teacher)False # p不是Teacher类型这说明在继承链上,一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法。我们再考察 s :>>> isinstance(s, Person)True # s是Person类型>>> isinstance(s, Student)True # s是Student类型>>> isinstance(s, Teacher)False # s不是Teacher类型s 是Student类型,不是Teacher类型,这很容易理解。但是,s 也是Person类型,因为Student继承自Person,虽然它比Person多了一些属性和方法,但是,把 s 看成Person的实例也是可以的。这说明在一条继承链上,一个实例可以看成它本身的类型,也可以看成它父类的类型。
查看全部 -
如果已经定义了Person类,需要定义新的Student和Teacher类时,可以直接从Person类继承:class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender 定义Student类时,只需要把额外的属性加上,例如score:class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score一定要用 super(Student, self).__init__(name, gender) 去初始化父类,否则,继承自 Person 的 Student 将没有 name 和 gender。函数super(Student, self)将返回当前类继承的父类,即 Person ,然后调用__init__()方法,注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写)。
查看全部 -
和属性类似,方法也分实例方法和类方法。在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。要在class中定义类方法,需要这么写:class Person(object): count = 0 @classmethod def how_many(cls): return cls.count def __init__(self, name): self.name = name Person.count = Person.count + 1print Person.how_many()p1 = Person('Bob')print Person.how_many()通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count。因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。
查看全部 -
我们在 class 中定义的实例方法其实也是属性,它实际上是一个函数对象:class Person(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): return 'A' p1 = Person('Bob', 90) print p1.get_grade# => <bound method Person.get_grade of <__main__.Person object at 0x109e58510>>print p1.get_grade()# => A 也就是说,p1.get_grade 返回的是一个函数对象,但这个函数是一个绑定到实例的函数,p1.get_grade() 才是方法调用。因为方法也是一个属性,所以,它也可以动态地添加到实例上,只是需要用 types.MethodType() 把一个函数变为一个方法:import typesdef fn_get_grade(self): if self.score >= 80: return 'A' if self.score >= 60: return 'B' return 'C'class Person(object): def __init__(self, name, score): self.name = name self.score = scorep1 = Person('Bob', 90)p1.get_grade = types.MethodType(fn_get_grade, p1, Person)print p1.get_grade()# => Ap2 = Person('Alice', 65)print p2.get_grade()# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'# 因为p2实例并没有绑定get_grade给一个实例动态添加方法并不常见,直接在class中定义要更直观。
查看全部 -
我们可以给一个实例绑定很多属性,如果有些属性不希望被外部访问到怎么办?Python对属性权限的控制是通过属性名来实现的,如果一个属性由双下划线开头(__),该属性就无法被外部访问。看例子:class Person(object): def __init__(self, name): self.name = name self._title = 'Mr' self.__job = 'Student'p = Person('Bob')print p.name# => Bobprint p._title# => Mrprint p.__job# => ErrorTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'Person' object has no attribute '__job'可见,只有以双下划线开头的"__job"不能直接被外部访问。但是,如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"__xxx__"定义。以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。
查看全部 -
python中偏函数当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。比如,int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:>>> int('12345') 12345但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做 N 进制的转换:>>> int('12345', base=8) 5349 >>> int('12345', 16) 74565假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:def int2(x, base=2): return int(x, base)这样,我们转换二进制就非常方便了:>>> int2('1000000') 64 >>> int2('1010101') 85functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:>>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85所以,functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。
查看全部 -
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写 f = decorate(f) 这样的代码。考察一个@log的定义:def log(f): def fn(x): print 'call ' + f.__name__ + '()...' return f(x) return fn对于阶乘函数,@log工作得很好:@logdef factorial(n): return reduce(lambda x,y: x*y, range(1, n+1))print factorial(10)结果:call factorial()...3628800但是,对于参数不是一个的函数,调用将报错:@logdef add(x, y): return x + yprint add(1, 2)结果:Traceback (most recent call last): File "test.py", line 15, in <module> print add(1,2)TypeError: fn() takes exactly 1 argument (2 given)因为 add() 函数需要传入两个参数,但是 @log 写死了只含一个参数的返回函数。要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:def log(f): def fn(*args, **kw): print 'call ' + f.__name__ + '()...' return f(*args, **kw) return fn现在,对于任意函数,@log 都能正常工作。
查看全部 -
高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算 f(x)=x2 时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])[1, 4, 9, 16, 25, 36, 49, 64, 81]通过对比可以看出,匿名函数 lambda x: x * x 实际上就是:def f(x): return x * x关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码:>>> sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))[9, 5, 3, 1, 0]返回函数的时候,也可以返回匿名函数:>>> myabs = lambda x: -x if x < 0 else x >>> myabs(-1)1>>> myabs(1)1
查看全部 -
def cmp_ignore_case(s1, s2):
return cmp(s1.upper() , s2.upper())
print sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case)
这样可以直接转换大小写,不需要另设置变量
查看全部 -
为什么实现了倒序呢??查看全部
-
闭包:内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况。
闭包的特点:返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。
查看全部 -
upper()-字母变成大写 lower()-字母变成小写
查看全部 -
s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符。 当rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' '),查看全部
-
装饰器的作用
查看全部
举报
0/150
提交
取消