首页 > 代码库 > python面向对象
python面向对象
1、python中创建类属性
类是模板,而实例则是根据类创建的对象。
绑定在一个实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
定义类属性可以直接在 class 中定义:
class Person(object): address = ‘Earth‘ def __init__(self, name): self.name = name
因为类属性是直接绑定在类上的,所以,访问类属性不需要创建实例,就可以直接访问:
print Person.address # => Earth
对一个实例调用类的属性也是可以访问的,所有实例都可以访问到它所属的类的属性:
p1 = Person(‘Bob‘) p2 = Person(‘Alice‘) print p1.address # => Earth print p2.address # => Earth
由于Python是动态语言,类属性也是可以动态添加和修改的:
Person.address = ‘China‘ print p1.address # => ‘China‘ print p2.address # => ‘China‘
因为类属性只有一份,所以,当Person类的address改变时,所有实例访问到的类属性都改变了。
2、python中类属性和实例属性名字冲突怎么办
修改类属性会导致所有实例访问到的类属性全部都受影响,但是,如果在实例变量上修改类属性会发生什么问题呢?
class Person(object): address = ‘Earth‘ def __init__(self, name): self.name = name p1 = Person(‘Bob‘) p2 = Person(‘Alice‘) print ‘Person.address = ‘ + Person.address p1.address = ‘China‘ print ‘p1.address = ‘ + p1.address print ‘Person.address = ‘ + Person.address print ‘p2.address = ‘ + p2.address
结果如下:
Person.address = Earth p1.address = China Person.address = Earth p2.address = Earth
我们发现,在设置了 p1.address = ‘China‘ 后,p1访问 address 确实变成了 ‘China‘,但是,Person.address和p2.address仍然是‘Earch‘,怎么回事?
原因是 p1.address = ‘China‘并没有改变 Person 的 address,而是给 p1这个实例绑定了实例属性address ,对p1来说,它有一个实例属性address(值是‘China‘),而它所属的类Person也有一个类属性address,所以:
访问 p1.address 时,优先查找实例属性,返回‘China‘。
访问 p2.address 时,p2没有实例属性address,但是有类属性address,因此返回‘Earth‘。
可见,当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
当我们把 p1 的 address 实例属性删除后,访问 p1.address 就又返回类属性的值 ‘Earth‘了:
del p1.address print p1.address # => Earth
可见,千万不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。
3、python中定义实例方法
一个实例的私有属性就是以__开头的属性,无法被外部访问,那这些属性定义有什么用?
虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。除了可以定义实例的属性外,还可以定义实例的方法。
实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的:
class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name
get_name(self) 就是一个实例方法,它的第一个参数是self。__init__(self, name)其实也可看做是一个特殊的实例方法。
调用实例方法必须在实例上调用:
p1 = Person(‘Bob‘) print p1.get_name() # self不需要显式传入 # => Bob
在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度.
练习:
请给 Person 类增加一个私有属性 __score,表示分数,再增加一个实例方法 get_grade(),能根据 __score 的值分别返回 A-优秀, B-及格, C-不及格三档。
# -*- coding:utf-8-*- class Person(object): def __init__(self, name, score): self.__name=name self.__score=score def get_grade(self): if self.__score>=80: return "A-优秀" elif self.__score>=60: return "B-及格" return "C-不及格" p1 = Person(‘Bob‘, 90) p2 = Person(‘Alice‘, 65) p3 = Person(‘Tim‘, 48) print p1.get_grade() print p2.get_grade() print p3.get_grade()
4、python中方法也是属性
我们在 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 types def 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 = score p1 = Person(‘Bob‘, 90) p1.get_grade = types.MethodType(fn_get_grade, p1, Person) print p1.get_grade() # => A p2 = Person(‘Alice‘, 65) print p2.get_grade() # ERROR: AttributeError: ‘Person‘ object has no attribute ‘get_grade‘
# 因为p2实例并没有绑定get_grade
给一个实例动态添加方法并不常见,直接在class中定义要更直观。
python面向对象