一、对象、类变量与实例变量

面向对象(Object Oriented Programming,又称OOP)是相对于面向过程的,比如你要充话费,你会想,可以下个支付宝,然后绑定银行卡,然后在淘宝上买卡,自己冲,这种种过程。但是对于你女朋友就不一样了,她是面向“对象”的,她会想,谁会充话费呢?当然是你了,她就给你电话,然后你把之前的做了一遍,然后她收到到帐的短信,说了句,亲爱的。这就是面向对象!女的思维大部分是面向“对象”的!她不关心处理的细节,只关心谁可以,和结果。

那到底什么是对象呢?
在Python中,这个问题十分简单,可以说对象就是变量

class A:
myname="class a"

这是一个类

a=A()

而这里a就是一个对象,其中a中有一个属性是myname

对象有以下五个特征:

  • 世间万物皆对象
  • 每个对象都是唯一的
  • 对象具有属性和行为(方法)
  • 对象具有状态
  • 对象分为类对象和实例对象两大类
class Person:

    move = True    # 这是类变量

    def __init__(self , name , age):

        self.name = name  # 这是实例变量

        self.age = age  # 这是实例变量

可以看出,类变量是在classdef外的,而实例变量,是在__init__内部的。

class Person:

    move = True    # 这是类变量,


    def __init__(self , name):

        self.name = name  # 这是实例变量,必须声明在实例函数内,用self关键字修饰

        # move = True  # 类变量不能再函数体内声明,在这个位置声明的又没有self关键字修饰,只能是一个局部变量


    # self.age = age  # 这是错误的,实例变量不能再这里声明

   eat = True  # 这是类变量,可以在函数体外,类内部任意位置
二、属性及可见性
1.类属性和实例属性
  • 类属性
    类对象所有的属性,类对象和实例对象均可以访问,被它们共同拥有
    通过类名.类属性来访问
  • 实例属性
    通过方法定义的属性
    有两种调用方式:
    1.在类对象的内部:
    self.属性名 2.在类对象的外部
    实例对象.属性名
class Test(object):
    a = 100                            #类属性
    def __init__(self, b):             #实例属性
        self.b = b
t = Test(100)

print(t.a)                             #通过实例化对象访问 类属性
print(Test.a)                          #通过类名访问 类属性
print(t.b)                             #通过实例化对象访问 实例属性

print(Test.b)                          #通过类名访问 实例属性
#error 无法通过(类名.属性名)的方式访问实例属性
2.私有属性

在类对象某个属性或方法前添加__,那么在类对象的外部就不能直接访问该属性或方法了

class MyClass(object):
    def __init__(self):
        self.__pia = 18
    def __pim(self):
        print("__pim()被调用了")
    def do_sth(self):
        print(self.__pia)
        self.__pim()
#mc = MyClass()
#print(mc.__pia())
#会出现:AttributeError: 'MyClass' object has no attribute '__pia'

可以通过dir(mc)来查看是否存在私有属性,若有_类名__属性名(左边一个_,右边两个__),则该属性为私有属性。
所以,在类对象的外部仍然可以通过_类名__属性名访问该属性或方法,但是,强烈建议不要这样访问,因为不同版本Python解释器可能会把属性或方法改成不同的名字

mc = MyClass()
print(mc._MyClass__pia)        #结果:18
mc._MyClass__pim()             #结果:__pim()被调用了
三、静态方法、类方法与实例方法
  • 静态方法
    静态方法是指在定义时,使用@staticmethod装饰器来修饰,无序传入self或cls关键字即可进行创建的方法。在调用过程时,无需将类实例化,直接通过“类名.方法名()”方式调用方法。当然,也可以在实例化后通过“实例名.方法名()”的方式调用。在静态方法内部,只能通过“类名.类变量名”的方式访问类变量。
class Person:

    move = True

    def __init__(self , name , age):

        self.name = name

        self.age = age

    @staticmethod

    def static_fun():          # 声明一个静态方法

        print(Person.move)

p1 = Person('张三' , 20)       # 实例化

p1.static_fun()                #输出结果:这是静态方法(实例名.方法名形式调用)

Person.static_fun()            #输出结果:这是静态方法(类名.方法名调用)
  • 类方法
    类方法需要使用@classmethod装饰器来修饰,且传入的第一个参数为cls,指代的是类本身。类方法在调用方式上与静态方法相似,即可以通过“类名.方法名()”和“实例名.方法名()”两种方式调用。但类方法与静态方法不同的是,类方法可以在方法内部通过cls关键字访问类变量。在类方法内部,既能通过“类名.类变量名”的方式访问类变量,也能通过“cls.类变量名”的方式访问类变量。
class Person:

    move = True

    def __init__(self , name , age):

        self.name = name

        self.age = age

    @classmethod

    def class_fun(cls):           # 声明一个类方法

        print(cls.move)

        print(Person.move)        # cls 指的就是Person类,等效

p1 = Person('张三' , 20)

p1.class_fun()                    #输出结果:True True

Person.class_fun()                #输出结果:True True
  • 实例方法
    在一个类中,除了静态方法和类方法之外,就是实例方法了,实例方法不需要装饰器修饰,不过在声明时传入的第一个参数必须为self,self指代的就是实例本身。实例方法能访问实例变量,静态方法和类方法则不能。在实例方法内部只能通过“类名.类变量名”的方式访问类变量。在调用时,实例方法可以通过“实例名.实例方法名”来调用,如果要通过类来调用,必须必须显式地将实例当做参数传入。
class Person:

    move = True

    def __init__(self , name , age):

        self.name = name

        self.age = age

    def instance_fun(self):        # 声明一个实例方法

        print(Person.move)         # 访问类变量
 
        print(self.name , self.age)

p1 = Person('张三' , 20)

p1.instance_fun()

Person.instance_fun(p1)            #通过类访问实例方法时,必须显式地将实例当做参数传入

总结:

  • 和实例相关的,都会出现selfself.xxx =只会出现在__init__里面
  • 类变量若在__init__中出现,只能作为局部变量
  • 无法通过(类名.属性名)的方式访问实例属性