本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。
在前面章节中介绍的Python知识点,主要是集中在Python的环境布置及基本使用,今天这一章节主要介绍Python中类的相关信息。
一、类的基本定义
有一下几点进行说明:
1. Python中类的定义都以class开头。
2. 下面定义的name为类的属性, 可以直接访问。
3. 类中可以定义自己想要使用的方法,用于进行常规的操作。
class Foo:
# 这里我们可以创建一个类级别的变量
# 它不会随着由此类创建的变量而变化
name = 'Jan'
def bar(self):
print('Bar')
def hello(self, name):
print('you are %s' % self.name)
print('I am %s' % name)
print('\n')
obj1 = Foo()
obj2 = Foo()
obj1.hello('jason')
obj2.hello('rose')
最终打印的结果为:
you are Jan
I am jason
you are Jan
I am rose
二、构造函数
Python中的构造函数与其他编程语言中的构造函数一样,都是在初始化创建对象的时候,对属性进行初始化操作。
在调用完 obj = Foo() 后,self.name 的值就是 ‘Jane’ 了。
class Foo:
def __init__(self):
self.name = 'Jane'
def hello(self, name):
print('you are %s' % self.name)
print('I am %s' % name)
print('\n')
obj = Foo()
obj.hello('July')
最终打印的结果为:
you are Jane
I am July
三、继承
Python 中的继承与其他语言中的继承是同样的道理,即子类可以使用或者重写父类的属性、方法。Python中的继承是使用小括号体现的,例如下面的PrimaryStudent 和 CollegeStudent 都继承自 Student。
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def detail(self):
print(self.name)
print(self.age)
class PrimaryStudent(Student):
def lol(self):
print('sala')
class CollegeStudent(Student):
def __init__(self, name, age, gf):
self.name = name
self.age = age
self.gf = gf
def gf_detail(self):
print(self.gf)
obj1 = PrimaryStudent('王文宇', 24)
obj1.lol()
obj1.detail()
obj2 = CollegeStudent('李飞', 31, '王文宇')
obj2.detail()
obj2.gf_detail()
最终打印的结果为:
sala
王文宇
24
李飞
31
王文宇
四、模拟多态
Pyhon不支持多态并且也用不到多态, 可以用 自定义Func 模拟多态
class F1:
pass
class S1(F1):
def show(self):
print('S1.show')
class S2(F1):
def show(self):
print('S2.show')
def Func(obj):
# Func函数需要接收一个F1类型或者F1子类的类型
obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
最终打印的结果为:
S1.show
S2.show
五、获取对象信息
print('type(123): %s' % type(123))
print('type(\'str\'): %s' % type('str'))
print('type(None): %s' % type(None))
print('type(abs): %s' % type(abs))
class a:
def __init__(self):
pass
print('type(a): %s' % type(a))
# isinstance()可以告诉我们,一个对象是否是某种类型(包括继承关系)。
isinstance('a', str)
六、slots 的使用
- Python是动态语言,默认是可以添加属性与方法的。
- 但如果使用了 slots 的话,只能添加指定的属性或者方法
- slots 对子类不起作用
import traceback
from types import MethodType
class MyClass(object):
__slots__ = ['name', 'set_name']
def set_name(self, name):
self.name = name
cls = MyClass()
cls.name = 'Jack'
cls.set_name = MethodType(set_name, cls)
cls.set_name('Rose')
print(cls.name)
try:
cls.age = 30
except AttributeError:
traceback.print_exc()
代码中,通过MethodType动态的为MyClass类绑定了set_name方法。所以打印cls.name 是正常的。 但是由于使用了slots 限制了只能添加 ‘name’ 和 ‘set_name’ 所以赋值 cls.age = 30 就会报错了,报错信息为:
AttributeError: ‘MyClass’ object has no attribute ‘age’
七、getter 与 setter 方法
Python中,getter与setter两个方法的组合,可以实现属性值的过滤操作。
代码中在score方法上面添加了 @property 系统注解,标明 score是getter方法,(注意这里的score方法参数只有self)。然后在带有输入参数的score方法上面使用了 @score.setter 注解,标明他是 setter 方法。而readOnlyScore 方法只有 @property 注解,所以他是只读方法。
import traceback
class Person:
@property
def score(self):
return self._score
@score.setter
def score(self, score):
if not isinstance(score, int):
raise ValueError('not int')
elif score < 0 or score > 100:
raise ValueError('score is not betweent 0 ~ 100')
self._score = score
# readOnlyScore 这个属性就是只读的,因为没有 setter方法
@property
def readOnlyScore(self):
return self._score * 2
p = Person()
p.score = 30
print('my score: %d' % p.score)
try:
p.score = 'good'
except:
traceback.print_exc()
try:
p.score = 200
except:
traceback.print_exc()
print('read only score: %d' % p.readOnlyScore)
try:
p.readOnlyScore = 30
except:
traceback.print_exc()
八、注解
第七点中使用到了系统的@property注解,现在我们自己定义一个自定义的注解,来了解一下注解的实现原理及流程。
class MyProperty:
def __init__(self, fget = None, fset = None, fdel = None):
print('__init__ called.')
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, cls):
if self.fget:
return self.fget(instance)
def __set__(self, instance, value):
if self.fset:
print('__set__ called, %d' % value)
self.fset(instance, value)
def __del__(self, instance):
if self.fdel:
self.fdel(instance)
def setter(self, fn):
print('__setter__ called, %s' % fn)
self.fset = fn
def getter(self, fn):
self.fget = fn
def deler(self, fn):
self.fdel = fn
- 需要调用初始化方法绑定方法 def init(self, fget = None, fset = None, fdel = None) ,主要有三个方法需要绑定(get, set, fdel)
而核心的代码就是
def setter(self, fn):
print(‘setter called, %s’ % fn)
self.fset = fndef getter(self, fn):
self.fget = fn
这两个方法的处理,其中 fn 就是 被注解的方法。
使用如下:
class Person:
@MyProperty
def score(self):
return self._score
@score.setter
def score_setter(self, score):
self._score = score
p = Person()
p.score = 100
print('result is %d' % p.score)
九、构造一个类
由于Python是动态语言,所以我们可以在开发过程中构造一个类。
def init(self, name):
self.name = name
def say_hello(self):
print('hello, %s!' % self.name)
Hello = type('Hello', (object, ), dict(__init__ = init, hello = say_hello))
h = Hello('Jack')
h.hello()
对type构造的参数说明
Hello 是返回的实例, ‘Hello’ 是类名 , (object, ) 是继承的类,但必须是元组形式,所以有逗号。
十、元类(Metaclass)
Python中,类的类型就是元类,它本身也是类。
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
print(cls)
print(name)
print(bases)
print(attrs)
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass = ListMetaclass):
pass
mli = MyList()
mli.add(1)
mli.add(2)
mli.add(3)
print(mli)