类:class
类是抽象的概念,是万事万物的抽象,是一类事物的共同特性的集合
用计算机语言来描述类,就是属性和方法的集合
对象instance、object
对象是类的具象,是一个实体
对于我们每个人这个个体,都是抽象概念人类的不同的实体
举例:
你吃鱼
你,就是对象,鱼也是对象,吃就是动作
你是具体的人,是具体的对象,你属于人类,人类是个抽象的概念,是无数个具体的个体的抽象
鱼也是具体的对象,就是你吃的这一条具体的鱼,这条鱼属于鱼类,是无数条具体的鱼抽象出来的概念
吃,是动作,也是操作,也是方法,这个吃是你的动作,也就是人类具有的方法。
属性,它是对象状态的抽象,用数据结构来描述;
因为属性是放在类里面的,而类是个抽象概念,所以说属性也是抽象的概念
操作(方法),是个动作(说到底就是函数),它是对象行为的抽象,用操作名和实现该操作的方法来描述
面向对象的三要素:
1、封装:
- 组装:将数据和操作组装到一起
- 隐藏数据:对外只暴露一些接口,通过接口访问对象,比如驾驶员驾驶汽车,不需要了解汽车的构造细节,只要知道使用什么部件,怎么驾驶就行,踩了油门就能跑,可以不了解后面的机动原理
2、继承:
- 多复用,继承来的就不用自己写了
- 多继承少修改,使用继承来改变,来体现个性
3、多态:
- 面向对象编程最灵活的地方,动态绑定
人类就是封装
人类继承自动物类,孩子继承父母特性,分为单一继承,多继承
多态,继承自动物类的人类、狗类的操作“吃”不同
class ClassName
语句块
1、必须使用class关键字
2、类名必须是用大驼峰命名
3、类定义完成后,就产生了一个类对象,绑定到了ClassName上
class MyClass:
"""A example class"""
x = 'abc' # 类属性
def foo(self): # 类属性foo,也是方法
return 'My class'
print(MyClass.x)
print(MyClass.foo)
print(MyClass.__doc__)
a = MyClass() # 实例化
print(a.foo())
类对象,类的定义就会生成一个类对象
类的属性,类定义中的变量和类中定义的方法都是类的属性、
类变量,x是MyClass的变量
在MyClass中,x、foo都是类的属性,__doc__也是类的属性
foo方法是类的属性,如同吃是人类的方法,但是每一个具体的人才能吃东西,也就是说吃是人的实例才能调用方法
foo是method方法对象,不是普通的函数对象function,它必须至少有一个参数,且第一个参数必须是self(self可换名)
self代指当前实例本身
实例化:a = MyClass(),就是调用类的实例化方法,完成实例化,实例化后获得的实例,是不同的实例,即使是使用
同样的参数实例化,也得到不一样的对象
class Person:
x = 'abc'
def __init__(self, name, age):
self.name = name #实例的属性 python中以self开头的
self.age = age
tom = Person('tom', 28)
jerry = Person('tom', 28)
print(tom == jerry) False
print(tom is jerry) False
#实例的属性 python中以self开头的
Python类实例化后,会自动调用__init__方法,这个方法第一个参数必须留给self,其它参数随意
MyClass()实际上调用的是__init__(self)方法,可以不定义,如果没有定义将隐式的调用
其作用:对实例进行初始化(并非创建,创建好了才能初始化,也只能在这之后初始化,修改不是初始化)
初始化函数可以多参,第一个位置必须是self,例如init(self, name, age)
class Person:
x = 'abc'
def __init__(self, name, age):
self.name = name
self.age = age
def showage(self, t, y):
print('{} is {}.类属性x为{}'.format(self.name, self.age, self.x))
self.age = t
Person.x = y
tom = Person('tom', 28)
jerry = Person('jerry', 30)
jerry.age += 1
print(tom.x, jerry.x)
print(tom.name, jerry.age)
print(jerry.name, jerry.age)
jerry.showage(100, 'a')
print(jerry.age)
print(jerry.x)
输出:
abc abc
tom 31
jerry 31
jerry is 31.类属性x为abc
100
a
__init__()方法不能有返回值,就是只能返回None
实例对象:类实例化后一定会获得一个对象,就是实例对象
上面的jerry,tom就是Peron类的实例
__init__方法的第一个参数self就是指代某一个实例
class MyClass:
def __init__(self):
print('self in init = {}'.format(id(self)))
c = MyClass()
print('c = {}'.format(id(c)))
print(type(MyClass))
print(MyClass.__class__)
out:
self in init = 2046181910960
c = 2046181910960
<class 'type'>
<class 'type'>
__name__ 对象名
__class__ 对象的类型
__dict__ 对象的属性字典
__qualname__ 类的限定名
class Person:
"""hello"""
x = 'abc'
def __init__(self, name, age):
self.name = name
self.age = age
def showage(self):
print(self.name, self.age)
tom = Person('tom', 28)
jerry = Person('jerry', 30)
print(1, Person.__class__)
print(2, tom.__class__) # 返回的是一个类
print(3, tom.__class__.__qualname__) # 返回的是字符串
print(4, tom.__class__.__name__) # 返回的是字符串
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print(5, isinstance(jerry, tom.__class__)) # jerry是不是tom.__class__这个类型的
print(6, isinstance(jerry, int.__class__))
print(7, int.__class__)
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print(8, Person.__dict__)
print(9, tom.__dict__)
print(10, jerry.__dict__)
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('hehe', sorted(Person.__dict__.items()), end='\n\n')
print('heihei', sorted(tom.__dict__.items()), end='\n\n')
输出:
1 <class 'type'>
2 <class '__main__.Person'>
3 Person
4 Person
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 True
6 False
7 <class 'type'>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 {'x': 'abc', '__doc__': 'hello', '__init__': <function Person.__init__ at 0x00000264F7B65AE8>, '__module__': '__main__', 'showage': <function Person.showage at 0x00000264F7B65EA0>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__dict__': <attribute '__dict__' of 'Person' objects>}
9 {'age': 28, 'name': 'tom'}
10 {'age': 30, 'name': 'jerry'}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hehe [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', 'hello'), ('__init__', <function Person.__init__ at 0x00000264F7B65AE8>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('showage', <function Person.showage at 0x00000264F7B65EA0>), ('x', 'abc')]
heihei [('age', 28), ('name', 'tom')]
类属性保存在类的__dict__中,实例属性保存在实例的__dict__中,如果从实例访问类的属性,
就需要借助__class__找到所属的类
class Person:
age = 3
height = 176
def __init__(self, name, age=18):
self.name = name
self.age = age
Person.age = 30
tom = Person('tom')
jerry = Person('jerry', 20)
print(Person.age, tom.age, jerry.age)
print(Person.height, tom.height, jerry.height)
Person.height += 20
print(Person.height, tom.height, jerry.height)
tom.height = 186
print(Person.height, tom.height, jerry.height)
jerry.height += 10
print(Person.height, tom.height, jerry.height)
print(tom.__dict__)
print(jerry.__dict__)
print(Person.__dict__)
输出:
30 18 20
176 176 176
196 196 196
196 186 196
196 186 206
{'name': 'tom', 'age': 18, 'height': 186}
{'name': 'jerry', 'age': 20, 'height': 206}
{'height': 196, '__init__': <function Person.__init__ at 0x000002719C565AE8>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__module__': '__main__', '__doc__': None, 'age': 30, '__dict__': <attribute '__dict__' of 'Person' objects>}
是类的,也是这个类所有实例的,是实例的,就是实例自己的,通过类访问不到
Person.weight = 70
print(Person.__dict__['weight'])
print(tom.weight) # 可以通过搜索机制,自己字典没有就去类的字典找
print(tom.__dict__['weight']) # 而这不行,是看自己的字典里有没有,没有KeyError
实例属性的查找顺序:
指的是实例使用 . 来访问属性,会先找自己的__dict__,如果没有,就通过属性__class__找到自己的类
再去类的__dict__中找
如果是使用__dict__[变量]访问变量,有就有,没有就不会去找类的
一般,类变量使用全大写来命名
装饰一个类:
def add_name(name):
def wrapper(cls):
cls.NAME = name
return cls
return wrapper
@add_name('jerry')
class Person:
age = 123
print(Person.NAME)
类方法:
class Person:
age = 123
@classmethod
def clsmtd(cls):
print('{}.age = {}'.format(cls.__name__, cls.age))
Person.clsmtd()
a = Person()
a.clsmtd() # a.__class__.clsmtd()
print(a.__class__)
1、在类定义中,使用@classmethod装饰器修饰的方法
2、必须至少有一个参数,且第一个参数留给了cls,cls指代调用者,就是类对象自身
3、cls这个标识符可以是任意合法名称,但是为了易读,请不要修改
4、通过cls可以直接操作类的属性,不可操作类的实例
静态方法:
class Person:
age = 123
@staticmethod
def staticmtd():
print('static')
Person.staticmtd()
a = Person()
a.staticmtd()
1、在类定义中,使用@staticmethod装饰器修饰方法
2、调用时,不会隐式的传入参数,静态方法,只是表明这个方法属于这个名词空间,函数归在一起,方法组织管理
以上这些方法怎么调用?
class Person:
def normal_method():
print('normal')
def method(self):
print("{}'s method".format(self))
@classmethod
def class_method(cls):
print('class = {0.__name__} ({0})'.format(cls))
cls.HEIGHT = 176
@staticmethod
def staticmtd():
print(Person.HEIGHT)
print(1, Person.normal_method())
# print(2, Person.method()) 这个不行
# TypeError: method() missing 1 required positional argument: 'self'
print(3, Person.class_method())
print(4, Person.staticmtd())
print(Person.__dict__)
print('----------------')
tom = Person()
# print(1, tom.normal_method()) 这个不行
# TypeError: normal_method() takes 0 positional arguments but 1 was given
print(2, tom.method())
print(3, tom.class_method())
print(4, tom.staticmtd())
out:
normal
1 None
class = Person (<class '__main__.Person'>)
3 None
176
4 None
{'class_method': <classmethod object at 0x000001A1A65CA5C0>, 'method': <function Person.method at 0x000001A1A66E2048>, '__module__': '__main__', 'normal_method': <function Person.normal_method at 0x000001A1A65C5F28>, 'staticmtd': <staticmethod object at 0x000001A1A65CA7B8>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'HEIGHT': 176, '__dict__': <attribute '__dict__' of 'Person' objects>}
----------------
<__main__.Person object at 0x000001A1A65CA898>'s method
2 None
class = Person (<class '__main__.Person'>)
3 None
176
4 None
类几乎可以调用所有内部定义的方法,但调用普通方法时会报错,原因是第一个参数必须是实例
实例也几乎可以调用所有的方法,普通的函数调用一般不可能出现,因为不允许这么定义
普通方法传入实例自身,静态方法和类方法需要找到实例的类
class Person:
def __init__(self, name, age=18):
self.name = name
self.age = age
def growup(self, i=1):
if 0 < i < 150: # 控制逻辑
self.age += i
p1 = Person('tom')
p1.growup(20)
print(p1.age)
p1.age = 160 # 超过了范围,并绕过了控制逻辑
print(p1.age)
out:
38
160
上例,本来是想通过方法控制属性,但由于属性在外部可以访问,或者说可见,就可以直接绕过方法,
直接修改这个属性。
Python提供了私有属性可以解决这个问题
私有属性:使用双下划线开头的属性名
如下面例子:
class Person:
def __init__(self, name, age=18):
self.name = name
self.__age = age # 私有变量
def growup(self, incr=1):
if 0 < incr < 150:
self.__age += incr
def getage(self):
return self.__age
tom = Person('tom')
tom.growup(5)
print(tom.getage()) # 此时,外部已经访问不到__age,使用getage这个方法来获取
print(tom.__dict__)
print(tom._Person__age) # 这样找还是找的到的
out:
23
{'_Person__age': 23, 'name': 'tom'} # 其实就是改了个名字,所以外部找不到了
23