面向对象是一种认知世界,分析世界的方法论,将万事万物抽象为类
类class :类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合,在计算机语言里就是 属性和方法的集合
对象instance object
对象是类的具象,是一个实体
属性,他是对象状态的抽象,用数据结构来描述
操作,他是对象行为的抽象,用操作名和实现该操作的方法来描述
哲学:
一切皆对象
对象是数据和操作的封装
对象是独立的,但是对象之间可以相互作用
目前OOP是最接近人类认知的编程方式
面向对象3要素
1,封装
组装将数据和操作组装到一起
隐藏数据:对外只暴露一些接口,通过接口访问对象
2,继承
多复用,继承来的就不用自己在写
多继承少修改,OCP, 使用继承来改变,来体现个性
3,多态
面向对象编程最灵活的地方,动态绑定
python的类
定义 class ClassName :
语句块
1,必须使用class关键字
2,类名必须是大驼峰命名
3,类定义完成后,就产生了一个类对象,绑定到了ClassName上
例子(1,0)
class MyClass : """ A example class""" x = 'abc' #类属性 def foo(self) : #类属性foo 也是方法 return 'My Class' print(MyClass.x) print(MyClass.foo) print(MyClass.__doc__)
类对象及类属性
类对象,类的定义就会生成一个类对象
类的属性, 类定义中的变量和类中定义的方法都是类的属性
类变量,x是MyClass的变量
MyClass中,x,foo都是类的属性,__doc__也是类的属性
foo方法是类的属性,需要实例的调用才能使用
foo是method方法对象,不是普通的函数对象function了,他至少有一个参数,且第一个参数必须是self(self可以换名字),整个参数位置就留给了self
self 指代当期实例本身
实例化
a = MyClass( ) #实例化
使用这个语法就 在类对象名称后面加上一个括号,就调用类的实例化方法,完成实例化
实例化就真正创建一个该类的对象(实例),例如 tom jerry
实例化后获得的实例,是不同的实例,即使是使用同样的参数实例化,也得到不同的对象
python类实例化后,会自动调用__init__方法,整个方法第一个参数必须留给self , 其他参数任意
例子(1,1):
class Person: #定义类 age = 20 #类的属性 def __init__(self,name): #初始化属性值,也是类的方法or属性 self.name = name def foo(self): #类的方法 return 'Person' Person.age = 353 #可在外部通过类直接修改其内部的属性 tom = Person('tom') #实例化!!!!!!!!! jerry = Person('jerry') #实例化 , 不是一个对象,它们的id不一样 print(tom.age ,jerry.age) #若初始化后没有age整个元素,那么就会去类的内部查找; # 若类里没有,会直接new一个类属性到类的属性字典中 #print(Person.name) #类没有名字 print(Person.__dict__) #查看Person类的属性字典 print(tom.foo()) #如何去调用一个类里面的类的方法 Pe = Person( ) #会 调用__init__
__init__方法
例子(1,1)中 :
Pe实际上调用的是__init__(self)方法,可以不定义,如果没有定义,会在实例化后隐式调用
他的作用: 对实例初始化
!!!注意:
初始化函数可以有很多的参数,但是第一个位置必须是 self,例如init(self,name,age)
__init__( ) 方法不能有返回值,也就是说只能是None!
实例对象instance
类实例化后一定会获得一个对象,就是实例对象
(1,1)中,tom jerry就是Person类的实例
__init__方法的第一参数self就是指代某一个实例
类实例化出一个实例对象,实例对象会绑定方法,调用对象时会采用 jerry.showage( )的方式
定义的showage(self)这个self就是jerry,python会把方法的调用者作为第一参数self的实参传入
self.name就是jerry对象的name , name是保存在了jerry对象上,而不是在Person类上,所以称为实例变量
self
class Person: def __init__(self): print('{}'.format(id(self))) c = Person() #会调用__init__ print('c ={}'.format(id(c)))
打印结果为:
2322420470280
c =2322420470280
上例说明,self就是调用者,就是c对应的实例对象
self 整个名字只是一个管理,它可以修改,为了代码的可读性,不要去修改
实例变量和类变
实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法
特殊属性
|
含义
|
__name__
|
对象名
|
__class__
|
对象的类型
|
__dict__
|
对象的属性的字典
|
__qualname__
|
类的限定名
|
举例
class Person: age =3 height =170 def __init__(self,name,age=18): self.name = name self.age = age tom = Person('tom') jerry = Person('jerry',20) Person.age = 30 print(Person.age,tom.age,jerry.age) print(tom.height,jerry.height,Person.height) jerry.height = 175 #修改jerry字典中的数据 print(Person.height,tom.height,jerry.height) tom.height += 10 print(Person.height,tom.height,jerry.height) Person.height +=15 print(Person.height,tom.height,jerry.height) Person.weight = 70 print(Person.weight,tom.weight,jerry.weight) print(tom.__dict__['height']) print(tom.__dict__['weight']) #weight属于类的字典里的属性,不属于tom的字典里的属性,所以会出错
class Person: age =3 height =170 def __init__(self,name,age=18): self.name = name self.age = age tom = Person('tom') jerry = Person('jerry',20) Person.age = 30 print(Person.age,tom.age,jerry.age) print(tom.height,jerry.height,Person.height) jerry.height = 175 #修改jerry字典中的数据 print(Person.height,tom.height,jerry.height) tom.height += 10 print(Person.height,tom.height,jerry.height) Person.height +=15 print(Person.height,tom.height,jerry.height) Person.weight = 70 print(Person.weight,tom.weight,jerry.weight) #tom和jerry的属性字典里没有weight元素,会在类的属性里查找 print(tom.__dict__['height']) print(tom.__dict__['weight']) #weight属于类的字典里的属性,不属于tom的字典里的属性
#总结
#是类的,也是这个类所有实例的,其实例都是可以访问到的;是实例的,就是这个实例自己的,通过类访问不到
#类的变量,类下的方法都可以拿来用,但是不存在于类下的方法字典
#类变量是属于类的变量,这个类的所有实例可以共享这个变量
#实例可以动态的给自己增加一个属性。实例.__dict__[变量名]和实例.变量名都可以访问到
#实例的同名变量会隐藏这类变量,或者说是覆盖了这个类变量
实例属性的查找顺序
#指的是实例使用.来访问属性,会先找自己的__dict__,如果没有,通过属性__class__找到自己的类,再去类的.__dict__中找
#如果实例 使用__dict__[变量名]访问变量,就不会按照上面的查找顺序找变量了
#一般来说 , 类变量使用全大写来命名
#装饰一个类
#增加类的变量
# def add_name(name,clz): # clz.NAME = name #动态增加属性
#改成装饰器
# def add_name(name): # def add_arg(clz): # clz.NAME = name # return clz # return add_arg # # @add_name('tom') # class Person: # AGE = 3 # # print(Person.__dict__)
#之所以能够装饰,本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象
#类方法和静态方法
#前面的例子中定义的__init__等方法都是类的属性第一个参数必须是self。而self必须指向一个对象,也就是类必须实例化之后,由实例来调用这个方法
#普通函数:
class Person: def normal_method(self): print('nomal') print(Person.__dict__) Person.normal_method()
#这个方法只是被Person这个名词空间管理的一个普通的方法,normal_method这是Person的一个属性而已
#由于normal_method 在定义的时候没有指定self,所以不能完成实例对象的绑定,不能用Person().normal_method()调用
# !虽然语法没问题,但是没人这么写,所以禁止这样写
# 类方法
class Person: @classmethod def class_method(cls): print('class={0.__name__}{0}'.format(cls)) cls.HEIGHT = 170 Person.class_method() print(Person.__dict__)
#类方法
#1,在类定义中,使用@classmethod装饰器修饰的方法
#2,必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
#3,cls这个标识符可以是任意合法名称,但是为了易读,请不要修改
#4,通过cls可以直接操作类的属性,但是不能操作类的实例
#静态方法
# class Person: # @classmethod # def class_method(cls): #cls是啥? # print('class = {0.__name__}{0}'.format(cls)) # cls.HEIGHT = 170 # # @staticmethod #静态方法 # def static_methd(): # print(Person.HEIGHT) #Person.class_method() #Person.static_methd() #print(Person.__dict__)
#静态方法
# 在类定义中,使用@staticmethod装饰器修饰的方法
# 调用时,不会隐式的传入参数
#静态方法,定位于类定义的命名空间中,他不会对任何实例类型进行操作,类对象和实例都可以调用静态方法
#方法的调用
#怎么去调用一个类方法
# class Tu: # def __init__(self,name,age =18): # self.name = name # self.age = age # def hi(self): #实例方法会去外部调用缺省的参数 # print(self.name) # print(1,Person.normal_method()) #可以调用,并执行normal_method()方法, # print(2,Person.method()) #需要一个实例参数 # print(3,Person.class_method()) #可以调用,因为动态方法,将其类本身传给了这个方法 # print(4,Person.static_methd()) #静态属性不能调用类或者实例的方法 # x = Tu('heihei') # print(x.hi())
类对象可以调用类方法,类对象不能调用实例的方法;
实例对象可以调用类方法,和实例的方法
实例方法,第一个参数必须默认传实例对象,一般习惯用self
静态方法,参数没有要求 静态方法可以在其内部定义需要做的操作,因此可以不需要特定的去传参数
类方法,第一个参数默认必须是传 类 ,一般习惯用cls
#访问控制
#私有属性
# class Person: # def __init__(self,name,age=18): # self.name = name # self.age = age # def group(self,i = 1): # if i >0 and i < 150: #控制逻辑 # self.age += i # p1 = Person('tom') # p1 .group(20) #正常的范围 # p1.age = 160 # 超过了范围,并绕过了控制逻辑 # print(p1.age)
#本来是想控制属性范围,结果在外界直接就被绕过逻辑直接改了,这样非常危险。但是python给我们提供了相关的解决办法
#私有属性
#使用双下划线开头的属性名,就是私有属性
# class person: # def __init__(self,name,age= 18): # self.name = name # self .__age = age # def group(self,i = 1): # if i >0 and i<150: # self.__age += i # p1 = person('tom') # p1.group(20) # print(p1.__age) #外部已经访问不到__age了,怎么访问这个变量呢? # class Person: # def __init__(self,name,age=18): # self.name = name # self.__age = age # def group(self,i=1): # if i > 0 and i<150: # self.__age+=i # def getage(self): # return self.__age # # # print(Person.getage.__dict__)
#如何动态的增加一个看不到的参数呢?
# class Person: # def __init__(self,name,age =18): # self.name = name # self.__age = age # # def growup(self,i=1): # if i> 0 and i <150: # self.__age += i # def getage(self): # # return self.__age # # p1 =Person('tom') # print(p1.growup(20)) # p1.__age = 28 # print(p1.__age) # print(p1.getage()) # print(type(p1)) # print(p1.__dict__)
#私有变量的本质
#类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称为_类名__变量名的名称,所以用原来的名字访问不到
#但是直到了私有变量的名称后,通过实例还是可以对其的属性进行修改
#保护变量
#在变量名前使用一个下划线,称为保护变量
# class Person: # def __init__(self,name,age = 18): # self.age = age # self._name =name #保护变量 # # tom = Person('tom') # print(tom._age) # print(tom.__dict__)
#可以看出,这个_age属性根本就没有改变名称,和普通的属性一样,解释器不做任何处理,是开发者的约定
#私有方法
#和保护变量差不多,多了双下划线命名
class Person: def __init__(self,name,age=18): self.name = name self._age = age def _getname(self): return self.name def __getage(self): return self._age tom = Person('tom') # print(tom._getname()) #没改名4 # print(tom.__getage()) #没有这个属性 print(tom.__dict__) print(tom.__class__.__dict__) print(tom._Person__getage()) #改名了
#私有方法的本质,单下划线的方法只是开发者之间的约定,解释器不做任何结婚死
#双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量有关,_类__变量名
#方法变量都可以在类的__dict__中找到
#总结:
#在Python中使用_单下划线或者__双下划线来标识一个成员被保护,或者被私有化隐藏了起来
#Python没有绝对的安全的保护成员或者私有成员,并不能真正的阻止用户修改类的成员
#前导的下划线只是一种警告或者提醒,一般都是遵守约定,除非真有必要,不要修改或者使用保护成员或者私有成员
相关参考网站: https://github.com/pythonpeixun/article/blob/master/python/python_classmethod_staticmethod.md#%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E7%B1%BB%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8%E5%8C%BA%E5%88%AB%E6%88%96%E8%80%85%E8%AF%B4%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF 面对对象多态参考网站: blog.csdn.net/shangzhihaohao/article/details/7065675