人生苦短,我用python。

一、基本概念

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法:类中定义的函数。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 封装:将数据与方法放在一个类中就构成了封装。通俗的讲是指隐藏对象的属性和实现细节。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
  • 多态:Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

二、类的结构

1、类和对象

1
2
3
4
5
6
7
8
9
10
11
12
#类定义
class MyClass:
i = 12345
def f(self):
return 'hello world'

# 类对象
x = MyClass()

# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())

2、__init__()方法

类的实例化操作会自动调用__init__()方法(构造方法),进行初始化。

1
2
3
4
5
6
7
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart

x = Complex(3.0, -4.5)
print(x.r, x.i)

3、self参数

self代表类的实例,而非类。

类的方法与普通的函数只有一个特别的区别:它们必须有一个额外的第一个参数名称self。

1
2
3
4
5
6
7
class Test:
def prt(self):
print(self) #self代表的是类的实例,代表当前对象的地址
print(self.__class__) # self.class 则指向类

t = Test()
t.prt()

4、类的方法

def关键字来定义一个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0

#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
#定义类的方法
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))

# 实例化类
p = people('dada',10,30)
p.speak()

三、类的继承

1、单继承

class DerivedClassName(BaseClassName): #基类与派生类定义在一个作用域内
class DerivedClassName(modname.BaseClassName): #基类定义在另一个模块中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))

#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

s = student('ken',10,60,3)
s.speak()

2、多继承

class DerivedClassName(Base1, Base2, Base3):
注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))

#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

#另一个类,多重继承之前的准备
class speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))

#多重继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)

test = sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中排前地父类的方法

3、方法重写

如果父类方法的功能不能满足子类的需求,可以在子类重写父类的方法。

1
2
3
4
5
6
7
8
9
10
11
class Parent:        # 定义父类
def myMethod(self):
print ('调用父类方法')

class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')

c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法

ps:super() 函数是用于调用父类(超类)的一个方法。

四、类属性与方法

1、属性与方法

  • 类的私有属性__private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
  • 类的私有方法__private_method():两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类地外部调用。在类内部的方法中使用时 self.__private_method()。
  • 类的属性attrs:公开变量。
  • 类的方法method():公开方法。类方法必须包含参数self,self的名字并不是规定死的,也可以使用this,但是最好还是按照约定是用self。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private

def who(self):
print('name : ', self.name)
print('url : ', self.__url)

def __foo(self): # 私有方法
print('这是私有方法')

def foo(self): # 公共方法
print('这是公共方法')
self.__foo()

x = Site('baidu', 'www.baidu.com')
x.who() # 正常输出
x.foo() # 正常输出
x.__foo() # 报错

2、特殊的类属性

  • 类名.__name__ #类的名字(字符串)
  • 类名.__doc__ #类的文档字符串
  • 类名.__base__ #类的第一个父类(在讲继承时会讲)
  • 类名.__bases__ #类所有父类构成的元组(在讲继承时会讲)
  • 类名.__dict__ #类的字典属性
  • 类名.__module__ #类定义所在的模块
  • 类名.__class__ #实例对应的类(仅新式类中)

我们定义的类的属性到底存到哪里了?有两种方式查看:
方法一: dir(类名)查出的是一个名字列表
方法二: 类名.__dict__查出的是一个字典,key为属性名,value为属性值

3、类的专有方法

  • __init__() #构造函数,在生成对象时调用
  • __del__() #析构函数,释放对象时使用
  • __repr__() #打印,转换
  • __setitem__() #按照索引赋值
  • __getitem__() #按照索引获取值
  • __len__() #获得长度
  • __cmp__() #比较运算
  • __call__() #函数调用
  • __add__() #加运算
  • __sub__() #减运算
  • __mul__() #乘运算
  • __div__() #除运算
  • __mod__() #求余运算
  • __pow__() #乘方

五、类的高级操作

1、魔术方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 类和对象    
class People(object): # 新式类
name = '' # 公有属性
age = 0
__weight = 0 # 私有属性

def __new__(cls, *args): # 是创建类实例的方法,可以自定义类的实例化过程
print('创建实例前先执行__new__')
return super(People, cls).__new__(cls) # __new__方法返回一个类的实例

def __init__(self, n, a, w): # 构造方法
print('创建实例后再执行__init__')
self.name = n
self.age = a
self.__weight = w

def speak(self): # 实例方法,第一个参数是实例本身,惯用self
print('我是父类方法')

@classmethod # 类方法,可以按照不同情况初始化类
def myInfo(cls, info_str): # 类方法第一个参数默认是类,惯用cls
name,age,__weight = info_str.split('-')
return cls(name, int(age), int(__weight))

@staticmethod # 静态方法,调用可以无需创建对象,不能访问实例变量和方法
def mySex(sex): # 静态方法不需要传cls和self
People.sex = sex

def play(self): # 公有方法
print('我是公共方法')

def __play(self): # 私有方法
print('我是私有方法')


class Student(People): # 类的继承
"""我是文档注释"""
grade = ''

def __init__(self,n,a,w,g):
People.__init__(self,n,a,w) # 调用父类的构函
self.grade = g

def speak(self): # 覆写父类的方法
print('我是子类方法')
super(Student, self).speak() # 用子类对象调用父类已被覆盖的方法

def __str__(self): # 实例字符串表示,可读性,打印对象时调用
msg = '我是' + self.name + ',今年' + str(self.grade) + '年级'
return msg

def __repr__(self): # 实例字符串表示,准确性,打印对象时调用
msg = '我是' + self.name + ',今年' + str(self.grade) + '年级'
return msg

def __del__(self): # 析构方法
print('%s 马上被删除了' % self.name)

def __getattribute__(self,attr): # 属性访问时拦截器
if attr == 'age':
print('log: 不方便透露年龄') # 可以用来打log
return '就当我18岁吧' # 也可以限制属性的访问
else: # 注意:要用else返回访问的属性,不然其他属性就访问不到了
return object.__getattribute__(self,attr) # 注意:不要调用返回self.xxx,会陷入死循环


p = People('DaLiu',20,60)
print(p.name, p.age)
p = People.myInfo('DaWang-30-70')
print(p.name, p.age)
p.mySex('man')
print(p.name, p.sex)

s = Student('LiLei',10,50,3) # 实例化对象
s.speak()
print(s.age) # 由于age属性被__getattribute__属性访问器拦截,所以属性可能访问不到
print(s) # 打印实例时,打印的是__str__方法返回的值
print(repr(s)) # 打印实例时,返回的是__repr__返回的值
del s # 删除对象时,自动调用__del__方法析构

print(Student.__name__) # 类的名字(字符串)
print(Student.__doc__) # 类的文档字符串
print(Student.__base__) # 类的第一个父类
print(Student.__bases__) # 类所有父类构成的元组
print(Student.__dict__) # 类的字定义属性(字典)
print(Student.__module__) # 类定义所在的模块
print(Student.__class__) # 实例对应的类(仅新式类中)
print(dir(Student)) # 类的属性列表
print(id(Student)) # 类的id

2、私有化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 私有化
# xx: 公有变量
# _x: 单前置下划线,私有化属性或方法,类对象和子类可以访问,from somemodule import *禁止导入
# __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
# __xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
# xx_:单后置下划线,用于避免与Python关键词的冲突

# 通过name mangling(名字重整)目的就是以防子类意外重写基类的方法或者属性,如:_Class__object)机制就可以访问private了。
class Person(object):
def __init__(self, name, age, taste):
self.name = name
self._age = age # 父类的私有化属性,类对象和子类可以访问
self.__taste = taste # 避免与子类中的属性命名冲突,无法在外部直接访问

def showperson(self):
print(self.name)
print(self._age)
print(self.__taste)

def dowork(self):
self._work()
self.__away()

def _work(self):
print('my _work')

def __away(self):
print('my __away')

class Student(Person):
def construction(self, name, age, taste):
self.name = name
self._age = age # 子类的私有化属性,类对象和子类可以访问
self.__taste = taste # 避免与子类中的属性命名冲突,无法在外部直接访问

def showstudent(self):
print(self.c)
print(self._age)
print(self.__taste)

@staticmethod
def testbug():
_Bug.showbug()

class _Bug(object): # 模块内可以访问,当from cur_module import *时,不导入
@staticmethod
def showbug():
print('showbug')

s1 = Student('jack', 25, 'football')
s1.showperson() # jack 25 football # 调用父类方法
#s1.showstudent() # 无法访问__taste,导致报错
s1.construction('rose', 30, 'basketball')
s1.showperson() # rose 30 football # 调用父类方法,name和_age显示子类方法生成的,__taste显示父类方法生成的
s1.showstudent() # rose 30 basketball # 调用子类方法,name、_age和__taste都是子类方法生成的
Student.testbug() # showbug

3、属性property

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 属性property

# 1、给私有属性添加getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0

def getMoney(self): # getter方法
return self.__money

def setMoney(self, value): # setter方法
if isinstance(value, int):
self.__money = value
else:
print('error:不是整形数字')

# 2、用property函数升级getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0

def getMoney(self):
return self.__money

def setMoney(self, value):
if isinstance(value, int):
self.__money = value
else:
print('error:不是整形数字')

money = property(getMoney, setMoney) # 注意property传入的是getter和setter的方法名

m = Money()
m.money = 100
print(m.money)

# 3、用property属性函数取代getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0

@property # property使方法转换为只读属性
def money(self):
return self.__money

@money.setter # 修改property属性使用:方法名.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print('error:不是整形数字')

m = Money()
m.money = 200
print(m.money)

4、元类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 元类

# 元类就是类的类。
# type()动态创建类,接受一个类的描述作为参数,然后返回一个类:
# type(类名, 由父类名称组成的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

Test = type("Test", (), {}) # 使用type创建类,注意参数中类名是字符串
Foo = type("Foo", (), {'bar':True}) # 创建带有属性的类
FooChild = type('FooChild', (Foo,), {}) # 创建继承的类,注意参数元组中父类名称不是字符串

def echo_bar(self): # 添加实例方法
print(self.bar)
FooChild = type('FooChild', (Foo,), {'echo_bar':echo_bar}) # 添加实例方法也在参数字典中指定
my_foo = FooChild() # 实例化对象
my_foo.echo_bar()

@classmethod # 添加类方法
def testClass(cls):
print(cls.bar)
FooChild = type('FooChild', (Foo,), {'echo_bar':echo_bar, 'testClass':testClass})
my_foo = FooChild() # 实例化对象
my_foo.testClass()

@staticmethod # 添加静态方法
def testStatic():
print('static method')
FooChild = type('FooChild', (Foo,), {'echo_bar':echo_bar,'testStatic':testStatic})
my_foo = FooChild() # 实例化对象
my_foo.testStatic()



def upper_attr(future_class_name, future_class_parents, future_class_attr): # metaclass属性指定的方法
#遍历属性字典,把不是__开头的属性名字变为大写
newAttr = {}
for name,value in future_class_attr.items():
if not name.startswith('__'):
newAttr[name.upper()] = value
#调用type来创建一个类并返回
return type(future_class_name, future_class_parents, newAttr)
class Foo(object, metaclass=upper_attr): # 创建类时优先使用metaclass属性指定的方法,优先级高于type
bar = 'bip'
f = Foo()
print(Foo.BAR)
print(f.BAR)

5、类的动态特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 类的动态特性

import types
class Person(object):
def __init__(self, name=None, age=None):
self.name = name
self.age = age
def eat(self):
print("eat food")

def run(self, speed): # 定义一个实例方法
print('%s 的奔跑速度是 %s km/h'%(self.name,speed))

@classmethod # 定义一个类方法
def testClass(cls):
cls.num = 100

@staticmethod # 定义一个静态方法
def testStatic():
print('---static method----')

P = Person('小明', '24')
Person.sex = None # 运行过程中给类添加属性
P.sex = 'male' # 运行过程中给对象添加属性
P.eat()
P.run = types.MethodType(run, P) # 运行过程中给对象添加实例方法
P.run('100')
Person.testClass = testClass # 运行过程中给类添加类方法
Person.testClass()
print(Person.num)
Person.testStatic = testStatic # 运行过程中给类添加静态方法
Person.testStatic()
del P.sex # 运行过程中删除属性、方法
delattr(P,'run') # 运行过程中删除属性、方法
print(hasattr(P,'sex'))
print(hasattr(P,'run'))


# 限制实例的属性
class Person(object):
__slots__ = ('name','age') # __slots__变量限制该类实例能添加的属性
P = Person()
P.name = '老王'
P.age = 20
P.score = 100 # 注意__slots__定义的属性仅对当前类实例起作用,对继承子类不起作用

六、设计模式

工厂模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 工厂模式

# 定义伊兰特车类
class YilanteCar(object):
# 定义车的方法
def move(self):
print("---车在移动---")
def stop(self):
print("---停车---")

# 定义索纳塔车类
class SuonataCar(object):
# 定义车的方法
def move(self):
print("---车在移动---")
def stop(self):
print("---停车---")

# 定义一个生产汽车的工厂,让其根据具体的订单生产车
class CarFactory(object): # 工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体
def createCar(self,typeName):
if typeName == '伊兰特':
car = YilanteCar()
elif typeName == '索纳塔':
car = SuonataCar()
return car

class CarStore(object):
def __init__(self):
self.carFactory = CarFactory()
def order(self, typeName):
car = self.carFactory.createCar(typeName)
return car

# 定义了一个创建对象的接口(可以理解为函数),但由子类决定要实例化的类是哪一个,工厂方法模式让类的实例化推迟到子类
carStore = CarStore()
suonata = carStore.order('索纳塔')
suonata.move()
suonata.stop()

单例模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 单例模式

# 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

# 1、创建单例-保证只有1个对象
class Singleton(object):
__instance = None

def __new__(cls, age, name):
# 如果类数字能够__instance没有或者没有赋值,那么就创建一个对象,并且赋值为这个对象的引用
# 保证下次调用这个方法时,能够知道之前已经创建过对象了,这样就保证了只有1个对象
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance

a = Singleton(18, "W")
b = Singleton(8, "H")
print(id(a)) # 95378192
print(id(b)) # 95378192
a.age = 19
print(b.age) # 19


# 2、创建单例时,只执行1次__init__方法
class Singleton(object):
__instance = None
__first_init = False

def __new__(cls, age, name):
# 如果类数字能够__instance没有或者没有赋值,那么就创建一个对象,并且赋值为这个对象的引用
# 保证下次调用这个方法时,能够知道之前已经创建过对象了,这样就保证了只有1个对象
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance

def __init__(self, age, name):
if not self.__first_init:
self.age = age
self.name = name
Singleton.__first_init = True

a = Singleton(18, "W")
b = Singleton(8, "H")
print(id(a)) # 95244336
print(id(b)) # 95244336
print(a.age) # 18
print(b.age) # 18
a.age = 19
print(b.age) # 19

持续更新…

最后更新: 2018年12月04日 13:55

原始链接: http://pythonfood.github.io/2017/12/30/python类和对象/

× 多少都行~
打赏二维码