python 类(Class)和实例(Instance)

版权声明:本文为博主原创文章,欢迎一起学习交流。 https://blog.csdn.net/ym01213/article/details/86698455

类是抽象的模板,实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

通过类定义数据类型的属性(数据)和方法(行为),属性用来描述数据,方法(即函数)用来描述这些数据相关的操作。也就是说,“类将行为和状态打包在一起”。

python中一切皆对象,类也称为“类对象”,类的实例也称为“实例对象”。

一个类创建实例对象时,每个对象会共享这个类的行为(类中定义的方法),但会有自己的属性值(不共享状态)。更具体一点:“方法代码是共享的,属性数据不共享”。

类的定义:

class 类名:
     类体

class Person:

    count = 0 #类属性

    #构造器
    def __init__(self,name,age):
        self.name = name #实例属性
        self.age = age
        Person.count += 1
    #实例方法
    def say(self):
        print('我叫{0},今年{1}岁。'.format(self.name,self.age))
# 创建实例对象
p1 = Person('张三',12)
p1.say()

p2 = Person('李四',18)
p2.say()

print('共创建了{0}个对象'.format(Person.count))

一个 Python 对象包含如下部分:
1. id(identity 识别码)
2. type(对象类型)
3. value(对象的值)
(1) 属性(attribute)
(2) 方法(method)
创建实例对象,我们需要定义构造函数__init__()方法。构造方法用于执行“实例对象的初始化工作”,即对象创建后,初始化当前对象的相关属性,无返回值,如上示例中初始化实例对象的name与age属性。如果我们不定义__init__方法,系统会提供一个默认的__init__方法。如果我们定义了带参的__init__方法,系统不创建默认的__init__方法。通过“类名(参数列表)”来调用构造函数。调用后,将创建好的对象返回给相应的变量。

self相当于java中的this,指代当前创建的实例对象。名字任意,一般为self。

实例

实例属性
从属于实例对象的属性。一般在__init__方法中定义,self.实例属性名 = 初始值。

实例方法

从属于实例对象的方法。

def 方法名(self [, 形参列表]):
     函数体

定义时第一个参数必须是self,调用方法时,不需要给self传参。self由解释器自动传参。

class Person:
    def __init__(a,name,age):
        a.name = name #实例属性
        a.age = age
    def say(a):
        print('我叫{0},今年{1}岁。'.format(a.name,a.age))

p1 = Person('张三',12)
#对象调用方法
p1.say()
#解释器翻译成下面形式,自动传参,结果一样
Person.say(p1)

函数与方法,本质都是完成特定功能的语句块,区别在于,直观上看,方法定义需要传递self,函数不需要;方法通过对象来调用,函数没有此特点;

其他操作:

1. dir(obj)可以获得对象的所有属性、方法
2. obj.__dict__ 对象的属性字典
3. pass 空语句
4. isinstance(对象,类型) 判断“对象”是不是“指定类型”

类对象

class Person:
    pass

print(type(Person)) #<class 'type'>
print(id(Person)) #类对象的地址

从上面示例中可以看出,构建的Person类是type类的实例,称为类对象。

类属性

类属性是从属于“类对象”的属性,也称为“类变量”,可以被所有实例对象共享。
类属性的定义方式:
class 类名:
     类变量名= 初始值

类属性通过类名.类变量名进行访问。

类方法

类方法是从属于“类对象”的方法。用于操作类属性。类方法通过装饰器@classmethod 来定义,格式如下:
@classmethod
def 类方法名(cls [,形参列表]) :
函数体

class Person:

    count = 0 #类属性

    @classmethod
    def printCount(cls): #cls 代表类本身
        print(cls.count)

Person.printCount()

调用类方法格式:“类名.类方法名(参数列表)”。 参数列表中,不需要也不能给 cls 传值。
类方法中不能访问实例属性和实例方法。
子类继承父类方法时,传入 cls 是子类对象,而非父类对象。

静态方法

“静态方法”和在模块中定义普通函数没有区别,只不过“静态方法”放到了“类的名字空间里面”,需要通过“类调用”。
静态方法通过装饰器@staticmethod 来定义,格式如下:
@staticmethod
def 静态方法名([形参列表]) :
函数体

class Person:

    count = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    #类方法
    @classmethod
    def printCount(cls): #cls 代表类本身
        print(cls.count)
        # print(self.name) #不能访问实例属性
    #静态方法
    @staticmethod
    def staticSum(a,b):
        print('{0}与{1}的和是:{2}'.format(a,b,a+b))
        # print(self.name) #不能访问实例属性


Person.printCount()
Person.staticSum(1,2)

静态方法格式:“类名.静态方法名(参数列表)”。
静态方法中也不能访问实例属性和实例方法。

__del__方法(析构函数)和垃圾回收机制

__del__方法称为“析构方法”,用于实现对象被销毁时所需的操作。如释放对象占用的资源,包括打开的文件资源、网络连接等。
Python 自动的进行垃圾回收,当对象没有被引用时(引用计数为 0),由垃圾回收器调用__del__方法。
我们也可以通过 del 语句删除对象,从而保证调用__del__方法。
系统会自动提供__del__方法,一般不需要自定义析构方法。

class Person:

    def __del__(self):
        print('释放资源')
        print('销毁实例对象{0}'.format(self))

p1 = Person()
del p1

__call__方法和可调用对象

定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用。

class Person:

    def __call__(self, name):
        print('姓名:{0}'.format(name))
        return dict(name=name)

p1 = Person()
a = p1('张三')
print(a)

方法没有重载

java中具有重载机制,方法名相同,参数列表不同。

python中没有重载。因为方法的参数没有声明类型(调用方法时传入确定的参数类型),参数的数量也可以由可变参数控制。

如果在类体中定义了重名的方法,只有最后一个有效!

class Person:

    def say(self,name):
        print('我的姓名是:{0}'.format(name))

    def say(self,name,age):
        print('我的姓名是:{0},年龄是:{1}'.format(name,age))

p1 = Person()
# p1.say('张三') # 报错:say() missing 1 required positional argument: 'age'
p1.say('李四',12)

方法的动态性

Python 是动态语言,可以动态的为类添加新的方法,或者动态的修改类的已有的方法。

class Person:

    def work(self):
        print('工作中,请勿打扰!')

def work2(self):#必须带self,指定当前对象
    print('加油工作')

def play(s):
    print('休息中...')

p1 = Person()
p1.work() #工作中,请勿打扰!
#对象不能直接调用类外方法
p1.work2() # 'Person' object has no attribute 'work2'
Person.work = work2
p1.work() #加油工作
Person.game = play
p1.game() #休息中...

可见,Person类动态新增了一个geme方法,以及用work2替换了work方法。

私有属性和私有方法(实现封装)

Python 对于类的成员没有严格的访问控制限制,这与java有明显区别。

方法本质上也是属性!只不过是可以通过()执行而已。所以,此处讲的私有属性和公有属性,也同时讲解了私有方法和公有方法的用法。
1. 通常约定,两个下划线开头的属性是私有的(private),其他为公共的(public)。
2. 类内部可以访问私有属性(方法)
3. 类外部不能直接访问私有属性(方法)
4. 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)

class Person:
    __country = 'China' #私有的类属性,dir()可以查到为 _Person__country

    def __init__(self,name,age):
        self.__name = name #私有的实例属性
        self.__age = age

    def __work(self): #私有方法
        print('work hard!')

    def say(self):
        print('国籍:',self.__country) #访问私有类属性
        print('姓名:{0},年龄:{1}'.format(self.__name,self.__age)) #访问私有实例属性

p = Person('张三',12)
# 类外不能直接访问私有属性
# print(Person.country) # type object 'Person' has no attribute 'country'
# print(p.name)#'Person' object has no attribute 'name'
p.say() #私有属性在类内部可以访问
# 通过 对象._类名__私有属性(方法) 调用
print(p._Person__country)
print(p._Person__name)
p._Person__work()

print(dir(p)) #['_Person__age', '_Person__country', '_Person__name', '_Person__work', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'say']

可以看出,私有属性“__name”在实际存储时是按照“_Person__name”这个属性来存储的。

@Property 与@私有属性.setter 装饰器实现getter和setter

在java中,对私有属性的赋值与获取采用getter与setter方法,python中可以使用装饰器(注解)实现同样功能。

@property 可以将一个方法的调用方式变成“属性调用”。

class Person:

    def __init__(self,name,age):
        self.__name = name
        self.__age = age #私有属性

    # java中的getter与setter方法
    '''
    def getAge(self):
        return self.__age
    def setAge(self,age):
        self.__age = age    
    '''
    # 使用装饰器
    @property
    def age(self): #为了调用方便,方法名可与私有属性保持一致
        return self.__age

    @age.setter # 被property装饰的方法名.setter
    def age(self,age): # 为了调用方便,方法名可与私有属性保持一致
        if age>0:
            self.__age = age

p = Person('张三',12)
# p.setAge(18)
# print(p.getAge())

print(p.age) # 直接获取私有属性
p.age = 20 # 直接设置私有属性
print(p.age)

属性和方法的命名总结:

_xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访问这些成员
· __xxx__:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。在类外部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员。

猜你喜欢

转载自blog.csdn.net/ym01213/article/details/86698455
今日推荐