一、对象、类变量与实例变量
面向对象(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 # 这是实例变量
可以看出,类变量是在class
内def
外的,而实例变量,是在__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) #通过类访问实例方法时,必须显式地将实例当做参数传入
总结:
- 和实例相关的,都会出现
self
。self.xxx =
只会出现在__init__
里面 - 类变量若在
__init__
中出现,只能作为局部变量 - 无法通过(类名.属性名)的方式访问实例属性