class A(object):
# 类属性
name = 'cong'
# 类方法
@classmethod
def cm(cls, p1):
print(p1)
# 构造函数
def __init__(self, n):
# 定义实例对象属性并赋值
self.age = 20
# 定义实例对象的私有属性,双下划线开头表示私有访问,外部访问不到
self.__city = 'shanghai'
A.name = n # 给类对象属性赋值
# 静态方法
@staticmethod
def sm(p1, p2):
print(p1, p2)
# 实例方法
def do_something(self):
print('hello')
# 定义实例对象的私有方法,双下划线开头表示私有访问,外部访问不到
def __set_city(self, city):
self.__city = city
# 对属性进行的封装
def get_city(self):
print('he is from %s' % self.__city)
a = A('congcong')
print(A.name) # cong,使用类对象调用
print(a.name) # cong,当使用实例去调的时候,实际指向类对象的引用
print(a.age) # 20
A.cm('a') # 类对象调用类方法
a.cm('a') # 实例对象调用类方法
A.sm('a', 'b') # 类对象调用静态方法
a.sm('a', 'b') # 实例对象调用静态方法
a.do_something() # 使用实例去调用函数
# ---------------在外部设置新的属性-------------------------
A.sex = 'Male' # 在类的外部定义新的类属性
a.birthday = '2019-6-16' # 在类的外部定义新的实例属性
print(A.sex)
print(a.sex)
print(a.birthday)
# ---------------在外部设置新的方法-------------------------
# 在外部,定义一个函数作为实例方法
def newF1(self):
print('this is external method 1')
# 第一种方法,给类对象设置此实例方法
A.newF1 = newF1
a.newF1()
# 第二种方法,行不通,给实例对象设置此实例方法
# a.newF1 = newF1 # 不能这样设置,会报TypeError: newF1() missing 1 required positional argument: 'self'
# 第三种办法,动态绑定实例方法
from types import MethodType
a.newF1 = MethodType(newF1, a)
a.newF1()
"""
Python所有的类都继承一个统一的基类object
Python子类可以继承多个父类,这是与JAVA/C# 最大的不同,子类会继续所有直接父类和间接父类的所有方法和属性,包括类方法,静态方法等
如果两个父类中有两个相同的方法,Python是通过MRO(Method Resolution Order方法解析顺序)来解决的
"""
# A是根父类
class A(object):
def f(self):
print('A.f')
# B继承于A
class B(A):
# 如果对继承于父类的访问不满意,可以对此方法进行重写,重写的方式是:在子类中定义与父类中同名的属性或方法(包括装饰器)
def f(self):
print('B.f')
# C继承于A
class C(A):
def f(self):
print('C.f')
# D继承于两个父类B和C
class D(B, C):
def f(self):
# 可以通过super()来调用父类的方法
super().f() # B.f
super(D, self).f() # B.f, super的第一个参数是类对象,第二个参数是实例对象
# 根据D的MRO顺序是D->B->C->A,那如果想改这个顺序呢
super(B, self).f() # C.f, 以B的下一个类对象作为被指定的父类
super(C, self).f() # A.f
d = D()
d.f() # B.f 如果两个父类中有两个相同的方法,Python是通过MRO来解决的
# 通过调用类对象上的mro()方法,可以查看到解析顺序
# [, , , , ]
print(D.mro())
"""
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"
具体主要使用方法是在父类中定义了一个方法,在不同的子类中对此方法进行重写,在运行过程中根据变量所引用对象的类型,动态地决定调用哪个对象中的方法
"""
class ParentClass(object):
def f(self):
print('ParentClass.f')
class ChildClass1(ParentClass):
def f(self):
print('ChildClass1.f')
class ChildClass2(ParentClass):
def f(self):
print('ChildClass2.f')
def exec(obj):
obj.f()
"""
在JAVA/C#中,调用于必须用
ParentClass p = new ParentClass(); p.f();
ParentClass p = new ChildClass1(); p.f();
ParentClass p = new ChildClass2(); p.f();
这种方法来明确指定p的类型后,才能调用f方法,但在Python中不必要这样
Python是动态语言,它崇尚"鸭子类型":当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来像鸭子,那这只鸟就是鸭子,而在JAVA/C#中必须先明确知道对象的类型是什么,然后才会执行对应的方法
在鸭子类型中,我们并不关心对象的类型是什么,到底是不是鸭子,只关心对象的行为,代码如下
"""
a = ParentClass()
exec(a) # ParentClass.f
a = ChildClass1()
exec(a) # ChildClass1.f
a = ChildClass2()
exec(a) # ChildClass2.f