目录

1:Python中类的定义:

2:Python中类的实例:

3:Python3中的伪私有属性:

4:property属性:

4.1 内置函数property

4.2 setter和dleter装饰器

5:静态方法和类方法:

5.1:静态方法

5.2:类方法


在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_a1
print(person_1.A1) # 输出test_a1,person_1命名空间是没有A1的,自己没有会去类名的命名空间中找
print(person_2.A1) # 输出test_a1  person_2命名空间也是没有A1的,自己没有会去类名的命名空间中找

print(Person.B1)  #  输出 test_B1_Person
print(person_1.B1) # 输出 test_B1_Person1,person_1命名空间中有B1
print(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+b
person_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': <function add at 0x000001FEA4112EA0>}
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+b
Person.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)  # 可以访问  输出 ixusy88
print(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=gbk
class 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()