Python学习总结三:类的基本知识

本人录制技术视频地址: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 的使用

  1. Python是动态语言,默认是可以添加属性与方法的。
  2. 但如果使用了 slots 的话,只能添加指定的属性或者方法
  3. 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
  1. 需要调用初始化方法绑定方法 def init(self, fget = None, fset = None, fdel = None) ,主要有三个方法需要绑定(get, set, fdel)
  2. 而核心的代码就是
    def setter(self, fn):
    print(‘setter called, %s’ % fn)
    self.fset = fn

    def 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)

猜你喜欢

转载自blog.csdn.net/sinat_27706697/article/details/79070472