python面向对象Object Oriented Programming
参考资料
https://pythonhowto.readthedocs.io/zh_CN/latest/object.html?utm_source=pocket_saves#id6
基本概念
python中万物皆对象,即object
object对象
每一个对象,无论是数值、变量、数据类型、类、实例、函数等,都包含下面三个属性
- id():获取对象的内存地址
- type() == .
__class__
:获取对象的数据类型 - print():打印对象的值
# 1.值:ID,类型,值
print(id(1), type(1), 1) # 140716375728936 <class 'int'> 1
# 2.变量:ID,类型,值
a = 2
print(id(a), type(a), a) # 140716375728968 <class 'int'> 2
# 3.数据类型::ID,类型,值
print(id(int),type(int),int) # 140716374253104 <class 'type'> <class 'int'>
# 4.type:ID,类型,值
print(id(type),type(type),type) #140716374265744 <class 'type'> <class 'type'>
# 5.自定义类:ID,类型,值
class Foo: pass
print(id(Foo), type(Foo), Foo) # 2193622277152 <class 'type'> <class '__main__.A'>
# 6.实例:ID,类型,值
f = Foo()
print(id(f), type(id), id) # 2193590183440 <class '__main__.A'> <__main__.A object at 0x000001FEBC29E610>
# 7.函数:ID,类型,值
def hello(): pass
print(id(hello),type(hello),hello)
1320842727232 <class 'function'> <function hello at 0x00000133885C8F40>
-
__bases__
:当前对象的直接父类a = 1 # 1.数据类型的直接父类 print(int.__bases__) # (<class 'object'>,) # 2.type的直接父类 print(type.__bases__) # (<class 'object'>,) # 3.变量的直接父类 print(a.__bases__) ------------------------------------------ Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> a.__base__ AttributeError: 'int' object has no attribute '__base__'.
type类型
python中万物皆对象,每个对象object都有type,type也自然就离不开对象object。
type决定了object的可执行操作,如‘type=int’,则其接收的数据必为整型,也只能进行整数的操作
class类
由下面的代码,我们知道定义一个类class,其实就是定义了一个新类型type的对象object
# 5.自定义类:ID,类型,值
class Foo: pass
print(id(Foo), type(Foo), Foo) # 2193622277152 <class 'type'> <class '__main__.A'>
class其实就是一种type,只不过type通常是python内置的数据类型,class是指用户自定义的一种类型。
-
__bases__
:当前对象的直接父类class A: pass class B: pass class C(A,B): pass print(A.__bases__) print(B.__bases__) print(C.__bases__) ------------------------------- (<class 'object'>,) (<class 'object'>,) (<class '__main__.A'>, <class '__main__.B'>)
-
issubclass(A,B):判断A是不是B的子类
print(issubclass(C,A)) print(issubclass(C,B)) --------------------------------- True True
-
利用type动态创建一个类:
type(name, bases, dict):
- name:类的名称
- bases:基类元祖
- dict:定义属性和函数
# 利用class定义类 class X: name = haha def print_name(self): print(self.name) # 利用type等价定义类 def print_name(self): print(self.name) type('X', (object,), {'name': haha, 'print_name': print_name})
Instance实例
type 与 class,object 与 instance其实都是不同情镜下的同一种东西
- 1是int类型(type)的对象(object)
- 1是int类(class)的对象(object)
- 1是int类型(type)的实例(instance)
- 1是int类(type)的实例(instance)
isinstance(obj,class):判断obj是不是class的实例
- obj:实例对象
- class:类
class Foo(): pass
f = Foo()
print(isinstance(f,Foo)) # True
print(ininstance(f,object)) # True
区分type()和isinstance():
- type不考虑继承关系
- instance考虑继承关系
object 和 type
object和type是python中的顶级元素
- python中万物皆对象,即object是所有对象的基类,而它的类型是type,type也继承于object。
- python中的对象分为两类:
- 数据型对象(Type):int,str,list,dict,tuple…
- 非数据型对象(Non-Type):数值,变量,实例
- 数据型对象除了是object的子类,也是type类型的实例
- 而非数据型对象是数据型对象的实例。
类和对象
类属性
1)含义:类中封装在函数外,一般定义在类的头部的变量
2)访问:通过类名或者实例访问
class Student():
school = "三中"
def __init__(self,name,age):
self.name = name
self.age = age
# 1.类名访问
print(Student.school) # 三中
# 2.实例访问
s = Student("petty",18)
print(s.school) # 三中
3)改值:
-
直接对类属性赋值,则该类的所有实例对象的类属性都会修改
Student.school = "一中" print(Student.school)
-
对实例对象的属性赋值,修改过程中会进行拷贝,该实例的类属性将脱离类的属性,实现了属性的解绑定,把原来类属性覆盖了,该属性成为了实例的私有属性,其他实例不会受影响。
s = Student("petty",18) s.school = "一中" print(s.chool)
类私有属性__
1)定义:变量名前加上两个下划线__
2)访问:不能通过类名或者实例直接访问,只能通过类方法访问。或者可以通过实例._类名__属性
的方式访问,但是这种写法不规范
class Student:
__school = "三中"
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def get_school(cls):
return cls.__school
@classmethod
def set_school(cls, school):
cls.__school = school
# 1.类名访问
print(Student.__school)
# 2.实例访问
s = Student("petty",18)
print(s.__school)
# 3.类方法访问
print(s.get_school())
print(Student.get_school())
# 4._类名__属性
print(s._Student__school)
3)修改:修改过程不会拷贝,在内存中只有一份,通过类方法修改后,再创建该类的实例对象时,其私有属性会改变
s1 = Student("petty",18)
s2 = Student("alice",19)
print(s1.get_school())
print(s2.get_school())
s.set_school("一中")
print(s1.get_school())
print(s2.get_school())
print(Student.get_school())
>>>
三中
三中
一中
一中
一中
类方法classmethod
1)定义:类中定义的函数,并添加装饰器@classmethod
,必须参数为cls,即类本身
2)调用:可通过类名或者实例调用
class Student:
__school = "三中"
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def get_school(cls):
return cls.__school
@classmethod
def set_school(cls, school):
cls.__school = school
s = Student("petty",18)
# 1.实例访问
print(s.get_school())
# 2.类名访问
print(Student.get_school())
类静态方法staticmethod
1)定义:类中定义的函数,并添加装饰器@staticmethod
2)调用:类名或者实例调用
class Student:
......
@staticmethod
def static_get():
print("This is a class static method")
s = Student("petty",18)
Student.static_get()
s.static_get
>>>
This is a class static method
This is a class static method
3)注意:无论是类方法还是类的静态方法都只能通过类名加 ‘.’ 的方式调用,不能间接调用它们
class Student():
.....
@classmethod
def get_school(cls):
return cls.__school
func_map = {'get_school':get_school}
def call_func_map(self):
self.get_school() # 可用
self.func_map['get_school']() #报错
s = Student("petty",18)
s.call_func_map()
>>>
三中
TypeError: 'classmethod' object is not callable
查看类属性和方法dir
dir()内建函数:用于获取任意对象的所有属性和方法
class Student:
__school = "三中"
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def get_school(cls):
return cls.__school
@classmethod
def set_school(cls, school):
cls.__school = school
@staticmethod
def static_get():
print("This is a class static method")
dir(Student)
>>>
['_Student__school', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_school', 'set_school','static_get']
-
其中大部分继承了object的属性与方法
-
自定义的属性与方法有:
['_Student__school', '__init__', 'get_school', 'set_school', 'static_get']
-
可以看到私有属性的命名方式比较特别,其在原定义的变量名上加上了
_类名
的前缀
print(type(Student.__init__))
print(type(Student.get_school))
print(type(Student.set_school))
print(type(Student.static_get))
>>>
<class 'function'>
<class 'method'>
<class 'method'>
<class 'function'>
注:类中没有明确声明为类方法的函数类型均为 function,只有类方法的类型为 method
方法与属性总结
# 1) 类名调用:带参数cls
# 2) 实例调用:带参数self,即实例对象本身
class Student:
# 类属性
city = "北京"
# 私有属性
__school = "三中"
# 魔法方法:初始化函数
def __init__(self, name, age, id):
# 实例属性
self.name = name
self.age = age
# 实例私有属性
self.__id = id
# 类方法:参数cls为类本身Student
# 类方法获取私有属性
@classmethod
def cls_get_school(cls):
return cls.__school
# 类方法设置私有属性
@classmethod
def cls_set_school(cls, value):
cls.__school = value
print("类方法设置私有属性")
# 静态方法,不带参数
@staticmethod
def static_get():
print("静态方法不带参")
# 实例方法:参数self为实例对象本身
# 实例方法访问实例私有属性
def get_id(self):
return self.__id
# 实例方法设置实例私有属性
def set_id(self, value):
self.__id = value
# 1.创建实例对象,name="petty", age=19, id=1
s = Student("petty", 19, 1)
print("类:", dir(Student))
print("实例:", dir(s))
# 下面只展现我们自定义的部分,有关object的给省略了
# 类: ['_Student__school', 'city', 'cls_get_school', 'cls_set_school', 'get_id', 'set_id', 'static_get']
# 实例: ['_Student__id', '_Student__school', 'age', 'city', 'cls_get_school', 'cls_set_school', 'get_id', 'name', 'set_id', 'static_get']
# 实例比类多了 name, age, _Student__id
print("*"*20)
# 2.访问属性
# 2.1 访问类属性
print("类名访问类属性:城市", Student.city) # 类名访问类属性:城市 北京
print("实例访问类属性:城市", s.city) # 类名访问类属性:城市 北京
print("*"*10)
# 2.2 访问类私有属性
# print("类名访问类私有属性:学校", Student.__school) # type object 'Student' has no attribute '__school'
# print("实例访问类私有属性:学校", s.__school) # 'Student' object has no attribute '__school'
# 2.3 访问实例属性
# print("类名访问实例属性:姓名", Student.name) # type object 'Student' has no attribute 'name'
print("实例访问实例属性:姓名", s.name) # 实例访问实例属性:姓名 petty
print("*"*10)
# 2.4 访问实例私有属性
# print("类名访问实例私有属性:id", Student.__id) # type object 'Student' has no attribute '__id'
# print("实例访问实例私有属性:id", s.__id) # 'Student' object has no attribute '__id'
print("*"*20)
# 3.调用方法
# 3.1 调用类方法
print("类名-调用类方法:获取类私有属性-学校", Student.cls_get_school()) # 类名-调用类方法:获取类私有属性-学校 三中
Student.cls_set_school("一中") # 类方法设置私有属性
print("类名-调用类方法:获取类私有属性-学校", Student.cls_get_school()) # 类名-调用类方法:获取类私有属性-学校 三中
print("实例-调用类方法:获取类私有属性-学校", s.cls_get_school()) # 实例-调用类方法:获取类私有属性-学校 一中
print("*"*10)
# 3.2 调用静态方法
print("类名-调用静态方法", Student.static_get()) # 静态方法不带参 类名-调用不带参静态方法 None
print("实例-调用静态方法", s.static_get()) # 静态方法不带参 类名-调用不带参静态方法 None
print("*"*10)
# 3.3 调用实例方法
# print("类名-调用实例方法", Student.get_id()) # Student.get_id() missing 1 required positional argument: 'self'
print("实例-调用实例方法,获取实例私有属性id", s.get_id())
动态绑定类属性和方法【类】
1)何为动态?
即不在类定义中绑定的属性和方法,而是在类定义外通过类.
的方式绑定属性和方法。若该属性名或方法名已存在,则会覆盖原有值;反之,则重新创建该属性并赋值。
2)动态绑定类属性
# 类
class Student(): pass
# 1.动态绑定属性
Student.school = "三中"
# 2.类名访问类属性
print(Student.school)
# 3.实例访问类属性
s = Student()
print(s.school)
>>>
三中
三中
3)动态绑定类方法
# 类
class Student(): pass
# 函数
def hello(self): print("hello")
# 1.动态绑定方法
Student.hello = hello
# 2.类名调用类方法
Student.hello()
# 3.实例调用类方法
s = Student()
s.hello()
>>>
hello
hello
动态绑定属性和方法【实例】
同样可以对一个对象进行动态添加属性和方法,只是它们均为这个对象所私有,不会影响类的其他实例对象。如果对象方法已经存在,则被覆盖。
class Student: pass
# 1.动态绑定对象属性
s = Student()
s.name = "alice"
print("动态绑定实例属性后,实例访问属性",s.name)
print("动态绑定实例属性后,类访问属性",Student.name)
# 2.动态绑定对象方法
def say_goodbye(self): print("goodbye")
from types import MethodType
s = Student()
s.say_goodbye = MethodType(say_goodbye) #
对象中的函数被称为 method 方法类型,普通函数类型为 function,这里需要借助 types 模块中的 MethodType() 将一个函数转化为一个对象的方法。