Python基础-类和对象

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
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
90
91
92
93
94
95
96
97
98
99
100
"""
类和对象 python为动态语言
class 关键字定义类
___init__ 为构造方法
所有方法第一个参数必须要有 一般用self 用于绑定到调用者
"""


class Person:
"""
这个是注释 person类
"""
# 类变量
hair = "black"

def __init__(self, name="haha", age=10):
# 实例变量
self.name = name
self.age = age

# 方法
def say(self, content):
print(content)


"""
上面是创建了类 下面创建对象
"""
p = Person()
print(p.name, p.age, p.hair)
p.name = "lucy"
print(p.name)
p.say("this is python")

# 为对象增加删除变量、方法
p.li = ['book', 'cook']
print(p.li)
del p.name


# print(p.name) # 删除后无法访问 AttributeError

def info(self):
print("--info--", self)


# 增加方法不会自动将调用者绑定到self
p.foo = info
# p.info() #AttributeError
p.foo(p) # 绑定调用
p.bar = lambda self: print("--lambda--", self)
p.bar(p) # 绑定调用


# 可以使用types模块下的MethodType自动绑定
def intro_fun(self, content):
print("this is a person:%s" % content)


from types import MethodType

p.intro = MethodType(intro_fun, p)
p.intro("holly")

"""
self 引用的是当前方法的调用者
构造函数中引用的是该构造函数正在初始化的方法
普通实例方法中引用调用该方法的对象
"""


# 类方法中调用其他方法
class Dog:
def jump(self):
print("the dog jump")

def run(self):
self.jump() # self代表调用run方法的对象
print("the dog run after jump")


d = Dog()
d.run()


# self 作为对象默认引用时 程序可以像访问普通变量一样访问self
# 甚至作为返回值

class ReturnSelf:
def grow(self):
if hasattr(self, "age"):
self.age += 1
else:
self.age = 1
return self


rs = ReturnSelf()
rs.grow().grow().grow()
print(rs.age)
类的方法
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
方法是类和对象的行为的抽象
"""


# 类可以直接调用实例方法 但是有self参数不自动绑定
class Bird:
def foo():
print("类的方法")

def walk(self):
print(self, " is walk")

bar = 20


Bird.foo()
print(Bird.bar)
# 下面会报错 需要参数
# Bird.walk() # TypeError
bird = Bird()
Bird.walk(bird) # 手动绑定 相当于bird.walk
# 不一定要传入对象
Bird.walk("you")

"""
类方法和静态方法 方法属于类 即使对象调用也是类调用
@classmethod 修饰为类方法 第一个参数自动绑定到类
@staticmethod 修饰静态方法 第一个参数不会自动绑定到类
"""


class User:
@classmethod
def say(cls):
print("say something", cls)

@staticmethod
def info(p):
print("the info is :", p)


User.say()
User.info("hi")
user = User()
user.say() # 结果和User.say()一样 第一个参数绑定到类

"""
@ 函数装饰器 @函数 可以放到另一个函数进行装饰 类似AOP
1.被装饰函数传入@函数
2.被装饰函数变成了@函数的返回值
"""


def auth(fn):
def auth_fn(*args):
print("------执行权限检查------")
fn(*args)

return auth_fn


@auth
def test(a, b):
print("执行检查的参数是%s 和 %s" % (a, b))


test(10, 55)
print(test) # <function auth.<locals>.auth_fn at 0x000002B8B9FB8318>

"""
成员变量 定义在类里面 通过类名来方位
"""


class Address:
city = "上海"
road = "南京路"

def info(self):
# print("city:", city) 报错
print("city:", Address.city)
print("road:", Address.road)


add = Address()
add.info()
add.city = "北京" # 定义新的实例变量 类变量不影响
add.road = "上海路" # 定义新的实例变量 类变量不影响
add.info()
print(add.city, add.road)
Address.city = "广州"
Address.road = "南京路"
print(Address.city, Address.road)

"""
property(fget,fset,fdel,doc) 定义实例变量
参数可读 可修改 可删除 文档说明 类似计算属性
"""


class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height

def set_size(self, size):
self.width, self.height = size

def get_size(self):
return self.width, self.height

def del_size(self):
self.width = 0
self.height = 0

size = property(get_size, set_size, del_size, "this is rectangle size");


print(Rectangle.size.__doc__)
print(help(Rectangle.size))
rect = Rectangle(20, 30)
print(rect.size)
# 修改
rect.size = 50, 60
# 获取
print(rect.size)
# 删除
del rect.size
print(rect.size)
'''
上面注释掉set_size方法 并修改property
size = property(get_size, fdel=del_size, doc="this is rectangle size");
再次运行 由于没有set方法报错 AttributeError: can't set attribute
'''
'''
@property 修饰方法 使其成为属性且方法作为getter方法
@attr.setter 为setter方法 @attr.deleter 删除方法
'''


class Man:
@property
def name(self):
return self._name

@name.setter
def name(self, name):
self._name = name

@name.deleter
def name(self):
self._name = "ha"


m = Man()
m.name = "what"
print(m.name)
del m.name
print(m.name)
类的继承
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""
封装 隐藏
类成员前面双下划线__ 实现隐藏
"""


class User:
def __hide(self):
print("this is hide method")

def setname(self, name):
print("setname method")
self.__name = name

def getname(self):
print("getname method")
return self.__name

name = property(getname, setname)


u = User()
# u.__hide() #错误 AttributeError
# u.__name #错误 AttributeError
u.name = "haha"
print(u.name)
'''
其实并不是真正的隐藏 python把__成员 前面加了_类名
因此还是都可以访问
'''
u._User__hide()
u._User__name = "break"
print(u.name)

"""
继承 python支持多继承 语法如下
class SubClass(SuperClass1,SuperClass2,...)
没有指定父类 则默认继承object类
"""


class Person:
def say(self):
print("hello I am person")

def do_something(self):
print("this is person method")


class Man:
def info(self):
print("I am man")

def do_something(self):
print("this is man method")


class Lu(Man, Person):
pass


lu = Lu()
lu.say()
lu.info()
# 如果父类中有相同的方法 前面的父类会屏蔽后面父类的方法
lu.do_something()

'''
子类可以重写父类的方法 进行覆盖
子类可以使用父类.method(self) 来调用父类被重写的方法
'''


class Base:
def foo(self):
print('From Base')

def goo(self):
print("this is goo")


class SubClass(Base):
def foo(self):
print('From SubClass')

def bar(self):
self.goo()
Base.foo(self)
print("method bar")


s = SubClass()
s.foo()
s.bar()


# 子类也会继承父类的构造函数
# 多个父类会优先使用最前面父类的构造函数
# 想要继承多个分类的构造函数 需要重写构造函数,使用类名.方法或者super()函数
class People:
def __init__(self, name):
print("----people init---")
self.name = name

def print_name(self):
print("name is :", self.name)


class Woman:
def __init__(self, age, height):
print("----woman init---")
self.age = age
self.height = height

def info(self):
print("age is :%s,height is %s" % (self.age, self.height))


class Xiao(People, Woman):
def __init__(self, name, age, height):
print(Xiao.__mro__)
super().__init__(name)
Woman.__init__(self, age, height)


print(help(super))
xiao = Xiao("xiaowu", '10', '150')
xiao.print_name()
xiao.info()
类的动态和枚举
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
"""
前面介绍了动态的给对象增加方法
如果要所有实例对象都添加方法 只需要通过类添加方法
"""


class Cat:
def __init__(self, name):
self.name = name


def walk_func(self):
print("the name is :", self.name)


d1 = Cat('ha')
d2 = Cat('bai')
Cat.walk = walk_func # 第一个参数自动绑定
d1.walk()
d2.walk()
'''
__solts__属性(元组)
可以限制该类的实例对象能够动态增加的属性和方法
1.对象有效 对类无效 类可以增加方法
2.只对本类有效 对派生的子类无效
'''


class Dog:
__slots__ = ('walk', 'age', 'name')

def __init__(self, name):
self.name = name

def test(self):
print("the test method")


t = Dog('the_dog')
from types import MethodType

t.walk = MethodType(lambda s: print('the name is %s' % s.name), t)
t.walk()
t.age = 22
print(t.age)
# t.height = 220 #AttributeError: 'Dog' object has no attribute 'height'

'''
用type()创建类
class创建类的时候 类型都是type
可以理解为class创建类时 解释器创建了个type对象并赋值给该类
'''
print(type(t)) # <class '__main__.Dog'>
print(type(Dog)) # <class 'type'>


def fn(self):
print("this is fn method")


# 参数1-类名 2-父类(元组) 3-类的属性或者方法
Person = type('Person', (object,), dict(walk=fn, age=30))

p = Person()
print(p.age)
p.walk()
print(type(p))
print(type(Person))

'''
metaclass 是某一批类具有某种特征 动态修改类
需要继承type 重写__new__()方法
'''


class MyMetaclass(type):
# 参数 类 、类名、父类、属性和方法
def __new__(cls, name, bases, attrs):
attrs['cal_price'] = lambda self: self.price * self.discount
return type.__new__(cls, name, bases, attrs)


class Book(metaclass=MyMetaclass):
__slots__ = ('name', 'price', '__discount')

def __init__(self, name, price):
self.name = name
self.price = price

@property
def discount(self):
return self.__discount

@discount.setter
def discount(self, discount):
self.__discount = discount


b = Book('python', 19)
b.discount = 0.5
print(b.cal_price())
'''
类型检测
issubclass(cls,class_or_turple) cls是否为后一个类或者元组包含的多个类中任意类的子类
isinstance(obj,class_or_turple) obj是否为后一个类或者元组包含的多个类中任意类的对象
'''
hello = 'Hello'
print("isinstance('hello',str):", isinstance(hello, str))
print("isinstance(hello,object): ", isinstance(hello, object))
print("isinstance(b,Book): ", isinstance(b, Book))
print("issubclass(str,object):", issubclass(str, object))
'''
__bases__ 查看所有父类 返回元组
__subclasses__() 查看所有子类 返回列表
'''


class A:
pass


class B:
pass


class C(A, B):
pass


print(A.__bases__)
print(B.__bases__)
print(C.__bases__)
print(A.__subclasses__())
print(B.__subclasses__())
print(C.__subclasses__())

'''
枚举类 使用Enum列出多个枚举值创建或者继承Enum
'''
import enum

# 参数 1-类名 2-枚举值元组
Season = enum.Enum('Season', ('Spring', 'Summer', 'Fall', 'Winter'))
# 枚举值有name value属性 name是值 value为序号 1开始
print(Season.Spring)
print(Season.Summer.name)
print(Season.Summer.value)
# 变量名或者值访问
print(Season['Fall'])
print(Season(4))
# __members__属性 返回所有枚举实例的字典
for name, member in Season.__members__.items():
print(name, member, member.value)


# 继承Enum类
class Orientation(enum.Enum):
# 指定value
EAST = "1001"
WEST = "1002"
SOUTH = '1003'
NORTH = '1004'

def info(self):
print("this value is :", self.value)


print(Orientation.EAST.value)
print(Orientation.EAST.name)
print(Orientation('1003'))
print(Orientation['NORTH'])
Orientation.WEST.info()


# 枚举构造器 枚举实例必须为构造器设置值

class Gender(enum.Enum):
# 对应构造器参数
MALE = '男', '阳刚'
FEMALE = '女', '温柔'

def __init__(self, cn_name, desc):
self.__cn_name = cn_name
self.__desc = desc

@property
def desc(self):
return self.__desc

@property
def cn_name(self):
return self.__cn_name


print(Gender.MALE)
print(Gender.MALE.name)
print(Gender.MALE.value)
print(Gender.FEMALE.cn_name)
print(Gender.FEMALE.desc)