Python基础:Python类(真累~
类的声明:
一、类的属性
(私有属性和公有属性)
(类属性)
二、类的方法
(构造方法、析构方法、自定义方法、特殊成员方法)
(静态方法、类方法、类属性)
三、类的继承
(方法和属性的继承,方法的重构)
(抽象类,多重继承)
四、类的多态
(实现接口的重用)
五、类的特殊装饰
(@staticmethod、@classmethod、@property)
六、类的来源和原类(metaclass)
七、反射
类的声明
使用class声明类,建议类名单词首字母大写。
“新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。
新式类:
class Management(object):
def add():
pass
经典类:
class Management:
pass
类的属性
类的属性就是类定义的变量值。
公有属性:在类里直接定义的属性,它在类名下面直接定义。
调用:1、类中调用:类名.属性名 ,更改原公有属性值
2、实例调用:实例.属性名
class Management(object):
num = 10
def add(self):
Management.num +=10 # 类中调用公有属性并更改值,num=11
pass
s1 = Management()
s2 = Management()
# 第一种情况:s1实例中调用公有属性,s2实例没有调用公有属性
s1.num +=1
Management.num += 2
"""
<结果>
s1不变,s2和Management都改变了
s1_num:11 s2_num:12 Manage_num:12
"""
# 第二种情况:先调用s1实例公有属性,再通过S1调用add更改,然后再使用类更改
s1.num +=1
s1.add()
Management.num += 2
"""
<结果>
先调用的s1实例num依然不变,s2和Management都被修改了
s1_num:11 s2_num:22 Manage_num:22
"""
问题:为什么修改num的值以后,实例s1和实例s2会有不同的结果呢 ?
因为公有属性查找的顺序是:先找实例的公有属性,没找到再找类里的公有属性
可以这样理解:Management相当于一个微信群,num是群里发的一张照片,S1和S2是群里面的两个人。
情况1:S1把照片存到本地,P了个双眼皮,S2说太难看了,我也不会P图,不保存。这个时候发照片的Management说我也觉得难看,把图撤回,重新发了一个P的图。S2就只能保存最新的图片。
情况2:S1找到Management说你的图太丑了,重新改一下吧,Management说好!撤回图片修改了~
私有属性:加两个下划线,__membername,编译的时候自动加上类名,变成_classname__membername,这种技术叫变量名压缩(mangling),以达到外部不能调用的目的。实际使用_classname__membername是可以调用的,但是不符合规定。标准方法是通过定义函数来获取。
class Classname(object):
'''this is a demo!'''
def __init__(self):
self.__membername = 88
def read_membername(self): # 标准的外部访问方法,使用函数来读取私有属性。
return self.__membername
s= Classname()
print(s._Classname__membername)
print(s.read_membername())
'''
<结果>
88
88
------像下面的调用,会出现AttributeError错误------
print(s.__membername)
'''
类属性: 类自带的属性,需要注意的是实例化的类属性,和原类的类属性不同。用上面的例子作演示。
属性 | 作用 | 示例 | 结果 |
__doc__ | 类的文档字符串 | print(s.__doc__) print(Classname.__doc__) | this is a demo! this is a demo! |
__dict__ | 类的属性组成的字典 | print(s.__dict__) print(Classname.__dict__) | {'_Classname__membername': 88} {'__init__':, '__module__': '__main__', '__doc__': '\nthis is a demo!\n', 'read_membername':} |
__name__ | 类的名字(字符串) | ##不能用于实例print(s.__name__ ) print(Classname.__name__ ) | Classname |
__bases__ | 类的所有父类组成的元组 | #不能用于实例print(s.__bases__) print(Classname.__bases__) | (,)为什么没有值?可能是编译器问题 |
__module__ | 类所属的模块 | print(s.__module__) print(Classname.__module__) | __main__ __main__ |
__class__ | 类对象的类型 | print(s.__class__) print(Classname.__class__) | 待测 |
__slots__ | 限定类属性,在类属性位置定义 未在slots定义的属性都是非法属性 | __slots__.('name','age','sexy') | 使用'name','age','sexy'的以外属性会报错 |
类的方法
类的方法就是类里面定义的函数。类的构造方法、析构方法、自定义类方法、静态方法、类方法、属性方法、特殊成员方法。
构造方法:__init__
实例化类后就会运行的函数。self代表的就是实例本身
修改实例的属性,希望初始化的参数放置在init下面。(个人觉得,这个初始化参数可以是一切对象!)
class A(object):
def instense(self):
print("init obj A")
class B(object):
def __init__(self, para):
self.init_para = para
self.obj_A = A()
self.num = 1
def show(self):
print(self.init_para)
self.obj_A.instense()
print(self.num)
haha = B("this is para")
haha.show()
----------
this is para
init obj A
1
析构方法:
__del__:销毁实例时,方法才会执行。
class Hello(object):
def __del__(self):
print("你删除了实例")
# 在python上测试
instance = Hello()
del instance
# 当然也可以使用实例调用,但没有这么用的~~
instance.__del__()
自定义方法:
除去类中自带的以_下划线开头的函数,在类中定义一个函数,实现相应的功能。
class Person(object):
def __init__(self,person_name, person_age)
静态方法:
@staticmethod,不需要访问类里的任何参数。所带的参数都是从外部传入的。
class Person(object):
def __init__(self,person_name, person_age):
self.name = person_name
self.age = person_age
@staticmethod
def info(country):
print(country)
类方法:
@classmethod,第一个参数必须是类属性。
class Person(object):
country = "china"
def __init__(self,person_name, person_age):
self.name = person_name
self.age = person_age
@classmethod
def info(country):
print(country)
属性方法:
@property把一个函数变成一个静态属性
直接调用函数名字,不需要加括号,就能获取到函数返回值。一般用在不注重过程,只要结果的情况!
class Person(object):
country = "china"
def __init__(self,person_name, person_age):
self.name = person_name
self.age = person_age
@property
def health_point(self):
print("HP:【{}】".format(self.age*2))
return self.age*2
P = Person("laowang",23)
P.health_point # 不需要括号,看起来完全是一个属性,这就是属性方法
'''上面的类属性只是只读的,即然是叫属性,那么只读就显得太LOW了'''
类属性装饰器@property,装饰以后,函数就有:赋值setter\销毁deleter两个方法。
class Person(object):
country = "china"
def __init__(self,person_name, person_age):
self.name = person_name
self.age = person_age
@property
def health_point(self):
self.age = self.age*2
print("HP:【{}】".format(self.age))
return self.age
@health_point.setter # 增加了一个赋值方法
def health_point(self, add):
self.age = add
@health_point.deleter # 增加了一个销毁属性的方法
def health_point(self):
del self.age
P = Person("laowang", 33)
print(P.health_point)
P.health_point = 22 # 给health.point赋值
print(P.health_point)
del P.health_point # 销毁属性
特殊成员方法:
方法 | 作用 | 示例 | 结果 |
__call__ | 默认未定义 类实例化后,调用实例运行的方法 | p = Person() p() | Person是类名 实例p没有调用函数,加()运行call方法 |
__str__ | 默认未定义,定义时必须有返回值 定义时,打印实例,输入str返回值 | p = Person() print (p) | Person是类名 打印实例p,运行str方法,打印返回值 |
__getitem__ | 用于索引操作,如字典。获取数据 | p = Person() p['name'] | 自动运行getitem |
__setitem__ | 用于索引操作,如字典。赋值 | p = Person() p['name'] = 'David' | 自动运行setitem |
__delitem__ | 用于索引操作,如字典。删除数据 | p = Person() del p['name'] | 自动运行delitem |
__new__ | __new__是创建类实例的方法,并且会阻止init运行,使用return 返回new创建的实例值, 创建实例完成, 这个时候实例初始化,调用__init__ |
| 类实例化时的值t,t = Test() 就是由__new__方法return得到的 |
__len__ | 待续 | ||
__cmp__ | 待续 |
'''例子一call\str\getitem\setitem\delitem方法'''
class Person(object):
def __call__(self):
print("print call")
def __str__(self):
print("print str:",end='')
return "1"
def __getitem__(self,key):
print("getitem:",key)
def __setitem__(self,key,value):
print('setitem:',key,value)
def __delitem__(self,key):
print('delitem:',key)
p = Person()
p()
print(p)
print('-----------')
get = p['name']
p['name'] = 'David'
del p['name']
'''例子二:__new__/__init__'''
class Test(object):
def __init__(self):
print('my name is __init__!')
def __new__(cls, *args, **kwargs):
print('__new__!', cls, *args, **kwargs)
print('__new__ 创建的实例:',object.__new__(cls, *args, **kwargs))
return object.__new__(cls, *args, **kwargs)
# 这句最重要,把创建的实例返回给类,如果不返回,类就不能实例化,t=Test()无效
# return super(Test, cls).__new__(cls, *args, **kwargs) # 第二种写法
def __call__(self, *args, **kwargs):
print('__call__里面的self参数也是这个实例:', self)
# 测试以下三个语句都是一个实例。
t = Test()
# 结果:
"""
__new__! <class '__main__.Test'>
__new__ 创建的实例: <__main__.Test object at 0x0108D810>
my name is __init__!
"""
print('实例t:', t)
# 结果:
"""
实例t: <__main__.Test object at 0x0108D810>
"""
t()
# 结果:
"""
__call__里面的self参数也是这个实例: <__main__.Test object at 0x0108D810>
"""
类的来源和元类:
http://blog.jobbole.com/21351/中文版详细解答。下面写一个自己理解的简版的。
首先,类也是对象,可以:
1) 你可以将它赋值给一个变量
2) 你可以拷贝它
3) 你可以为它增加属性
4) 你可以将它作为函数参数进行传递
类也是是由type()这个函数创建的,type是类的类,类的爹。学名叫元类!
也许有人会问那为啥type()能查看到数据类型呢?
可能你会注意到,type的结果前是class。。。因为数据类型在Python中都是类定义的,这也说明了,为什么数字,字符等等全是对象。
看了一篇文章,换个思路理解元类:
1、很久以前天地一片混沌,混沌之中孕育了一尊原始大神--type
2、原始大神大斧一挥,创造出了宇宙(元类)--classmate
3、宇宙生成山峰,树木,江河、日月、等等具体的物体。(类)--class
4、后来这些物体繁衍出不同的品种,比如树木,杨树、松树、银杏树。。。(实例)--instance
5、这些树木都有自已不同的特点和用途。。。(属性和方法)--attributes\methods
type格式:
type(what,bases,dict)--what:我是谁?bases:我来自哪里?dict:我有什么?
type(类名,(父类元组),{属性和方法的字典}) , 父类元组可以没有;后面两个典省略时,默认值为None。···················
'''一言不合就上例子'''
Person = type('Person',(),{'country':'china'})
print(Person.country)
# 带继承Person类的用法
def run(): # 定义函数,把run传给Action的leg方法。
print('running...')
Action = type('Action',(Person,),{'leg':run})
print(Action.country)
Action.leg()
metaclass元类:
创建类的时候,使用metaclass元类创建类,找不到则使用type创建。
class MyType(type): # 定义元类
def __init__(self,*args,**kwargs): # 参数中严格说应该是what,bases,dict这三个type参数
super(MyType,self).__init__(*args,**kwargs) # 继承元类的参数,可省略此句,但是不严谨
print("Mytype __init__1",*args,**kwargs)
def __call__(self, *args, **kwargs):
print("Mytype __call__1", *args, **kwargs) # 默认方法,实例化类以后,不调用任何类方法,默认调用__call__
obj = self.__new__(self)
print("obj ",obj,*args, **kwargs)
print(self)
self.__init__(obj,*args, **kwargs)
return obj
def __new__(cls, *args, **kwargs): # __new__方法总是先于__init__方法执行
print("Mytype __new__1",*args,**kwargs)
return type.__new__(cls, *args, **kwargs) # 返回的是new创建的实例,有了实例开始执行__init__
# return super(Test, cls).__new__(cls, *args, **kwargs) # 第二种写法
print('here...')
class Foo(object,metaclass=MyType): # classmate指定元类
def __init__(self,name):
self.name = name
print("Foo __init__2")
def __new__(cls, *args, **kwargs):
print("Foo __new__2",cls, *args, **kwargs)
return object.__new__(cls)
f = Foo("Alex")
print("f",f)
print("fname",f.name)
结果:
here...
# 第一步初始化元类
Mytype __new__1 Foo (<class 'object'>,) {'__module__': '__main__', '__init__': <function Foo.__init__ at 0x0068B468>, '__qualname__': 'Foo', '__new__': <function Foo.__new__ at 0x0068B4B0>}
Mytype __init__1 Foo (<class 'object'>,) {'__module__': '__main__', '__init__': <function Foo.__init__ at 0x0068B468>, '__qualname__': 'Foo', '__new__': <function Foo.__new__ at 0x0068B4B0>}
Mytype __call__1 Alex
# 第二步创建实例
Foo __new__2 <class '__main__.Foo'>
obj <__main__.Foo object at 0x0067C810> Alex
<class '__main__.Foo'>
Foo __init__2
# print("f",f)
f <__main__.Foo object at 0x0067C810>
# print("fname",f.name)
fname Alex
类的继承
代码重用。
Python3中类有单继承和多继承,其中多继承与Python2的继承顺序不同。
子类方法与父类重名,子类方法会覆盖父类
单继承:
'''一言不合就上例子'''
class Person(object):
def __init__(self,person_name):
self.name = person_name
def info(self):
print("this is personal info:\nname:{}".format(self.name))
class Action(Person):
def __init__(self,person_name):
'''父类析构函数有两种继承方法'''
super(Action, self).__init__(person_name) # 方法一
# Person.__init__(self, person_name) # 方法二
# ----
# 如果自已带参数写在继承的参数前面,然后在super里再声明一下父类变量
# def __init__(self,person_sex,person_name):
# super(Action,self).__init__(person_name)
# ----
def run(self):
print("{} is running...".format(self.name))
a = Action('Alex')
a.run() # 继承了Person的属性。
a.info() # 继承了Person的方法。
多重继承:
不能同时继承两父亲类和爷爷类比如B继承A,C继承时就不能同时写A和B,只写B就可以了。
class ROOT(object):
def __init__(self):
print("this is root")
def action(self):
print("ROOT is action...")
class A(ROOT):
def __init__(self):
super(A, self).__init__()
print ('init A...')
def action(self):
print("A is action...")
class B(ROOT):
def __init__(self):
super(B, self).__init__()
print ('init B...')
def action(self):
print("B is action...")
class C(A):
def __init__(self):
super(C, self).__init__()
print ('init C...')
def action(self):
print("C is action...")
class D(B,C):
def __init__(self):
super(D, self).__init__()
print ('init D...')
def action(self):
print("D is action...")
d = D()
要理解继承的顺序,因为当方法重名时,顺序靠后的方法覆盖前面的方法。
类的继承关系: D(A,B)实例化时候的继承先后顺序:先找B(及其父类),再找C(及其父类)
# 多重继承的参数
class A(object):
def __init__(self,sever_ip):
self.ip = sever_ip
def show(self):
print('IP:',self.ip)
class B(object):
def __init__(self,server_port):
self.port = server_port
def show(self):
print('PORT:',self.port)
class C(A,B):
def __init__(self,server_port,server_ip): # 先写B的参数,再写A的参数。
super(C,self).__init__(server_port) # B的参数继承
super(A,self).__init__(server_ip) # C的参数继承
def show_b(self):
print(self.ip,self.port)
c = C('192.168.1.1',1234)
c.show_b()
c.show() # 先继承B的show,再继承A的show,A把B的show 替换掉了,所以此处运行的是A的show方法
类的多态
多态就是同一个父类的方法,不同子类继承可以进行不同的改写,实现多种不同的功能。
任何依赖父类作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
'''接着上面的例子'''
# 定义一个函数,把ROOT类传进里面
def who_action(class_name):
class_name.action()
who_action(ROOT())
who_action(D())
who_action(A())
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341