在Python中一切都是对象,Python从设计之初就已经是一门面向对象的语言。
面向对象的三个特征:
1:封装:把具有相同属性和功能的内容封装在一个对象中。
2:继承:子类可以自动拥有父类中除了私有属性外的其他所有内容。
3:多态:同一个对象,可以拥有多种形态,python原生自带多态性。
下面系列文章将从这三个特征中展开介绍Python中的面向对象。
1:Python中类的定义:
其形式如下:
class name(superclass,...): # 与def 一样 Class是一种隐含的赋值运算 attr = value # 类属性 def method(...): # 类方法 (无self参数) pass # 类方法 @classmethod def clsMethod(cls): # cls表示的类 print(cls) obj = cls() # 可以动态的创建对象 print('类方法') def method(self,...): # 实例方法 (有self参数) self.attr = value # 实例属性
Python中的Class语句并不是声明式的,与def一样,Class语句是对象的创建者,并且是一种隐含的赋值运算。与def语句一样,Class语句也是真正的可执行代码,也就是说在执行Class语句之前,所定义的类是不存在的。当执行到Class语句时,就会创建一个变量名为name的对象(也就是类名),这个对象具有自己的属性和方法(类属性,类方法),同时这个对象通过某种调用能够创造其他对象(也就是实例)。
在Class语句内,任何的赋值语句都会产生类属性。任何通过"类名.属性"赋值的语句也会产生类属性。
要点:
a:Class语句不是声明,是隐含的赋值,类名就是变量名。
b:在Class语句内有类方法,类属性,实例方法(这些属于类名命名空间下的属性),实例属性(此属性不属于类名命名空间下);类方法,类属性被类实例所共享。
c:在Class语句内,任何的赋值语句都会产生类属性。以 类名.属性 = xx 形式的赋值也会产生类属性。
d:在Python中,类中的所有属性和方法都是public的(包括_,__开头的属性都是Public的,可以看作是伪私有),同时类中的所有方法都是virtual的。
2:Python中类的实例:
类就是实例工厂,它可以创建其他的多个实例,类属性和类方法存在于类中,可以被多个实例共享。
在Class语句内的实例方法中通过self.属性 = xxx 方式赋值的属性都属于类的实例,多个实例都会有独立的。
实例1.属性1 = xx 形式的赋值只会给实例1添加属性,与其他实例没有关系
示例代码:
# encoding=gbk class Person: # 隐含的赋值(是通过元类来赋值的),Person 就是一个变量名,可以通过 person_1 = Person('德华',45) 的方式创建一个对象 country = '中国' # 静态方法 @staticmethod def printCountry(): print(Person.country) # 类方法, @classmethod def clsMethod(cls): # cls表示的类 print(cls) obj = cls() # 可以动态的创建对象 print('类方法') def __init__(self,name,age): # Person类的构造函数,用于创建实例对象, self.name = name # 实例的属性 self.age = age def setBirthday(self,birthday): self.birthday = birthday def PrintBirthday(self): print('self.birthday=', self.birthday) def printName(self): print('self.name=',self.name) # __dict__ 查看对象中的属性print(Person.__dict__)person_1 = Person('德华',18)person_2 = Person('德纲',19)print(person_1.__dict__) # {'name': '德华', 'age': 18}print(person_2.__dict__) # {'name': '德纲', 'age': 19}print(Person.__dict__) # 输出与第一的一样; 上面的实例化对象,不会对类Person产生影响 print('---01--:'+'*'*60)# 1:添加属性,即赋值操作,给谁赋值就在谁的命名空间中添加属性。(赋值操作不会发生继承搜索)Person.A1 = 'test_a1'person_1.A2 = 'test_a2'person_2.A3 = 'test_a3' Person.B1 = 'test_B1_Person'person_1.B1 = 'test_B1_Person1'person_2.B1 = 'test_B1_Person2' person_1.setBirthday('1990-10')print(person_1.__dict__) # {'name': '德华', 'age': 18, 'A2': 'test_a2', 'B1': 'test_B1_Person1', 'birthday': '1990-10'}print(person_2.__dict__) # {'name': '德纲', 'age': 19, 'A3': 'test_a3', 'B1': 'test_B1_Person2'} person_2没有调用setBirthday,故不会有birthday属性print(Person.__dict__) # 比上次多了 'A1': 'test_a1', 'B1': 'test_B1_Person' print('---02--:'+'*'*60)# 2:访问属性,即属性引用(属性引用会发生继承搜索):首先在自己的命名空间中找,找不到就去创建它的类中找,也找不到就去创建它的类的父类中找,如最后都没有找到,就抛出异常。print(Person.A1) # 输出test_a1print(person_1.A1) # 输出test_a1,person_1命名空间是没有A1的,自己没有会去类名的命名空间中找print(person_2.A1) # 输出test_a1 person_2命名空间也是没有A1的,自己没有会去类名的命名空间中找 print(Person.B1) # 输出 test_B1_Personprint(person_1.B1) # 输出 test_B1_Person1,person_1命名空间中有B1print(person_2.B1) # 输出 test_B1_Person2,person_2命名空间中有B1 print('---03--:'+'*'*60)# 3:方法调用# 类方法:只能是通过类名来调用Person.printCountry()# person_1.printCountry() # 这样会报错# person_2.printCountry() # 这样会报错 # 实例方法:通过实例调用,或者通过类名+传递实例参数调用person_1.printName()person_2.printName()# Person.printName() # 不能这样直接调用,需要传递一个实例参数,如下:Person.printName(person_1) # 这里与 person_1.printName() 调用是等价的Person.printName(person_2) print('---03--:'+'*'*60)# 4:添加方法,同添加属性,给谁添加方法就在谁的命名空间中添加方法。(赋值操作不会发生继承搜索)# 给实例添加方法,被添加方法的实例中才有def add(a,b): return a+bperson_2.add = add #print(person_2.add(10,19)) print(person_1.__dict__) # {'name': '德华', 'age': 18, 'A2': 'test_a2', 'B1': 'test_B1_Person1', 'birthday': '1990-10'}print(person_2.__dict__) # {'name': '德纲', 'age': 19, 'A3': 'test_a3', 'B1': 'test_B1_Person2', 'add': }print(Person.__dict__) # 结果中不会有 add方法 # Person.add(person_2,10,18) 不能这样调用,add只在person_2中才有 # 给类添加实例方法,所有实例都会共享 # def add(a,b):# return a+b# Person.add = add # 这样赋值会导致下面的定义出错# print(person_1.add(10,19)) # 需要添加一个实例对象作为参数。def add2(aaa,a,b): print(aaa) # aaa 就是Person的一个实例 return a+bPerson.add2 = add2 # 这样赋值会导致下面的定义出错print(person_1.add2(100,19))# 也可以通过下面方式调用,因为add2是类Person命名空间中的实例方法print(Person.add2(person_1,200,30))
3:Python3中的伪私有属性:
在Python3中,类中的所有属性都是公有的,即public的。但是在Python3中提供了以双下划线(__)开头的属性,表现为伪私有。
代码如下:(后面会介绍怎么实现这种伪私有)
# encoding=gbk class Person: def __init__(self,name,age): # 以双下划线(__)开头的实例属性,在创建实例的时候,会把属性名修改为:_类名_属性(此处为_Person__name), # 所以 以 实例.__name 访问属性 自然是不能访问的,其效果就是属性__name表现为私有一样, # 你依然可以通过 实例._Person__name 来访问这个属性 self.__name = name self._age = age print(Person.__dict__) p = Person('ixusy88',18)print(p.__dict__) # {'_Person__name': 'ixusy88', '_age': 18}# print(p.__name) # AttributeError: 'Person' object has no attribute '__name' , 没有__name这个属性print(p._Person__name) # 可以访问 输出 ixusy88print(p.__dict__['_Person__name']) # 可以访问 输出 ixusy88
4:property属性:
4.1 内置函数property
attribute = property(fget,fset,fdel,doc)
代码:
# encoding=gbk class Person: def __init__(self,name): self._name = name def getName(self): print('get') return self._name def setName(self, value): print('set',value) self._name = value def delName(self): print('del',self._name) del self._name name = property(getName,setName,delName,'name property') p = Person('ixusy88')print('1:' + '*'*20)print(p.name)print('2:' + '*'*20)p.name = '100'print(p.name)print('3:' + '*'*20)del p.name
4.2 setter和dleter装饰器
# encoding=gbkclass Person: def __init__(self,name): self._name = name @property def name(self): print('get') return self._name @name.setter def name(self, value): print('set',value) self._name = value @name.deleter def name(self): print('del',self._name) del self._name p = Person('ixusy88')print('1:' + '*'*20)print(p.name)print('2:' + '*'*20)p.name = '100'print(p.name)print('3:' + '*'*20)del p.name
5:静态方法和类方法:
类中有如下方法:
实例方法:传入一个self实例对象 (默认方式)
静态方法:不传入额外的对象 (通过staticmethod)
类方法:传入一个类对象 (通过classmethod)
5.1:静态方法
示例:统计实例的数量:
# encoding=gbk # 静态方法,统计实例的数量class Test: InstancesNums = 0 def __init__(self): Test.InstancesNums = Test.InstancesNums + 1 @staticmethod def printInstancesNums(): print(f'InstancesNums is {Test.InstancesNums}') class Sub(Test): pass t = Test()t = Test()t = Test()s = Sub()Test.printInstancesNums()t.printInstancesNums()s.printInstancesNums()
5.2:类方法
统计类实例数量:
# encoding=gbk # 静态方法,统计实例的数量class Test: InstancesNums = 0 def __init__(self): Test.InstancesNums = Test.InstancesNums + 1 @classmethod def printInstancesNums(cls): print(f'InstancesNums is {cls.InstancesNums}') class Sub(Test): @classmethod def printInstancesNums(cls): print(f'InstancesNums is {cls.InstancesNums}') class Other(Test): pass t = Test()t = Test()o = Other()s = Sub()Test.printInstancesNums()t.printInstancesNums()Sub.printInstancesNums()Other.printInstancesNums()
统计每个类实例数量:
# encoding=gbk # 静态方法,统计实例的数量class Test: InstancesNums = 0 def __init__(self): self.count() @classmethod def count(cls): cls.InstancesNums += 1 @classmethod def printInstancesNums(cls): print(f'InstancesNums is {cls.InstancesNums}') class Sub(Test): InstancesNums = 0 def __init__(self): super().__init__() @classmethod def printInstancesNums(cls): print(f'InstancesNums is {cls.InstancesNums}') class Other(Test): InstancesNums = 0 pass t = Test()o = Other()o = Other() s = Sub()s = Sub()s = Sub() Test.printInstancesNums()Other.printInstancesNums()Sub.printInstancesNums()
![894723ca1bc4d61b5ed658e67675f060.png](https://i-blog.csdnimg.cn/blog_migrate/07aa1f5b31b103b7b13f86fea3cd2822.jpeg)