Python类、实例、方法、继承与模块引用

本文介绍了Python中的类和实例的概念,包括属性、方法、初始化方法`__init__`,以及如何调用方法和修改属性。讨论了类的继承,多态,以及私有属性和保护属性的使用。还提到了模块引用和特殊方法,如`__str__`和`__repr__`。此外,文章还涵盖了类方法、实例方法和多态的概念,以及如何通过`super()`函数处理继承关系。
摘要由CSDN通过智能技术生成

Python类、实例、方法、继承与模块引用

原创:丶无殇  2023-02-16


Python类

包含:属性 attribute、方法 method

一个人的身高、体重和年龄,这些都是属性,而吃饭、说话和洗澡都是方法

实例对象是有区别的,类是抽象,是模板,而实例则是根据类创建的对象

比如类:动物,只是一个抽象,并没有动物的详细信息,而猫、狗等,则是具体的动物,是类的对象。

在class外部定义的可执行函数叫做function,类内部的函数叫做方法method

格式

类名开头大写,无括号,在Python3PersonPerson()Person(object),效果一样,但在Python2中需要写成Person(object)

class Person: # Person/Person()/Person(object)

换行缩进后定义属性和方法,属性为变量;方法的定义和函数一样(def开头)

class Person:
    # 属性
    name='zhangsan'
    age=29
    height=1.82

    # 方法
    def greet(self):# 打招呼方法
        print(f"你好,我叫{self.name},我今年{self.age}岁")

# 创建实例
p1=Person()

# 调用方法
p1.greet()

输出:

你好,我叫zhangsan,我今年29

类的定义是一个具体实例(instance)的设计蓝图,在创建实例的时候,只需要调用类名()就可以了

p1.greet()是方法调用的示范,在实例后面加上.可以调用方法属性,如p1.name

类的编写规范

类名使用:大骆驼命名法(UpperCamelCase)

实例和模块名:蛇形命名法(snake_case)

特殊参数self

特殊参数self会指向实例本身

self.name—>当前被创建实例的name属性

字符串格式化输出

方法一:%s/%d/%f

print时候用格式化符号%s/%d/%f占位,字符串后面紧接%(),括号中为对应的参数名称

class Person:
    # 属性
    name='zhangsan'
    age=29
    height=1.82

    # 方法
    def greet(self):# 打招呼方法
        print("你好,我叫%s,我今年%d岁,身高是%.2f米"%(self.name,self.age,self.height))

# 创建实例
p1=Person()

# 调用方法
p1.greet()

输出:

你好,我叫zhangsan,我今年29,身高是1.82

方法二:f'{表达式:格式化}'[Python3.6新增]

在输出内容的前面加上f,内容中需要变量的地方使用{}即可

参数为浮点数时候可以使用:.2f来设置浮点数的格式

class Person:
    # 属性
    name='zhangsan'
    age=29
    height=1.823

    # 方法
    def greet(self):# 打招呼方法
        print(f"你好,我叫{self.name},我今年{self.age}岁,身高是{self.height:.2f}米")

# 创建实例
p1=Person()

# 调用方法
p1.greet()

输出:

你好,我叫zhangsan,我今年29,身高是1.82

方法三:.format语法

使用{}占位,字符串后接.format(),括号中为对应的参数名称

参数为浮点数时候使用{:.2f}设置浮点数的格式

class Person:
    # 属性
    name='zhangsan'
    age=29
    height=1.823

    # 方法
    def greet(self):# 打招呼方法
        print("你好,我叫{},我今年{}岁,身高是{:.2f}米".format(self.name,self.age,self.height))

# 创建实例
p1=Person()

# 调用方法
p1.greet()

输出:

你好,我叫zhangsan,我今年29,身高是1.82

初始化方法__init__()

__init__(self)方法

__init__ 是 Python 中的特殊方法(special method),它用于初始化对象,在实例别创建后最先调用的函数,第一参数永远是self

class Person:
    # 初始化方法
    def __init__(self):
        self.name = '张三'

    # 自定义方法
    def greet(self):
        print('你好,我是'+self.name)

p1=Person()
p1.greet()

输出:

你好,我是张三

__init__方法添加参数

在初始化方法中的参数,为必填参数,创建实例的时候不填写会报错

class Person:
    # 初始化方法
    def __init__(self,init_name):
        self.name = init_name

    # 自定义方法
    def greet(self):
        print('你好,我是'+self.name)

p1=Person('李四')
p1.greet()

输出:

你好,我是李四

__init__方法添加任意参数

目前的方法只能传递固定个数的参数,如果想要传递任意参数,如:自定义求平均数的average()方法,使用时候可以是average(22,33,45),也可以是average(2,6,8,5,6,9,10)

详情见:可变参数

属性修改

修改类属性

创建好Person类后,设置类属性count,每创建一个实例count+1

class Person:
    # 类属性
    count=0
    
    # 初始化方法
    def __init__(self):
        Person.count+=1

# 实例化对象
p1=Person()
p2=Person()
p3=Person()
print(Person.count)

输出:

3

修改实例属性

在创建好实例p1后,修改它的属性

# 修改实例属性
p1.age=21
print(p1.age)

# 删除实例属性
del Person.height
print(Person.height)

# 删除实例
del p1
print(p1)

删除只能通过删除类属性实现,不能直接删除实例属性

删除方法除了del还可以使用delattr()函数

delattr(ClassName,Attribute) 相等于 del ClassName.Attribute

输出:

# 删除属性,报错内容
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'height'
# 表示已经删除了'Person.height'属性

# 删除实例,报错内容
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'p1' is not defined
#表示已经删除了'p1'实例对象

类属性和实例属性的优先级

类属性优先级高于实例属性,无法通过实例修改类属性,修改的只是对应的实例属性

class Animal:
    localtion = 'Asia'
    def __init__(self,localtion):
        self.localtion = localtion

dog = Animal('GuangDong')
cat = Animal('Africa')
print(dog.localtion)		# ==> GuangDong
print(cat.localtion)		# ==> Africa

cat.localtion='ChongQing'
print(cat.localtion)		# ==> ChongQing
print(Animal.localtion)		# ==> Asia

输出:

GuangDong
Africa
ChongQing
Asia

保护属性与私有属性

保护属性:_xxx

单下划线开头的属性,只有类实例和子类实例可以访问,不能通过from module import *导入,保护属性,不建议调用访问,不会被代码提示工具显示,但是可以直接访问

私有属性:__xxx

双下划线开头的属性/方法,只有类对象自己能访问,子类对象无法访问

#-*- coding:utf-8 -*-

class A(object):
    def __init__(self):# 系统定义方法
        self.string='A string'			# 公有属性
        self._string='A _string'		# 保护属性
        self.__string='A __string'		# 私有属性

    def fun(self):
        return self.string + ' fun-A'

    def _fun(self):
        return self._string+'  _fun-A'

    def __fun(self):# 私有方法
        return self.__string+' __fun-A'

    def for__fun(self):# 内部调用私有方法
        return self.__fun()

class B(A):# A的子类
    def __init__(self):# 系统定义方法
        self.string = 'B string'

a=A()
print(a.string)
print(a._string)
# print(a.__string)# 不可访问

print(a.fun())
print(a._fun())
# print(a.__fun())# 不可访问
print(a.for__fun())

b=B()
print(b.fun())
print(b.fun().__len__())# 系统定义函数

输出:

A string
A _string
A string fun-A
A _string  _fun-A
A __string __fun-A
B string fun-A
14

访问操作私有属性

通过实例方法调用私有属性,可以实现访问和修改等操作

在外部调用实例方法时,是不需要显式传递self参数的

class Animal:
    # 初始化方法
    def __init__(self,name,age):
        self.__name=name
        self.__age=age

    # 获取信息
    def get_info(self):
        return 'name={},age={}'.format(self.__name,self.__age)

    # 修改信息
    def set_info(self,name,age):
        self.__name=name
        self.__age=age
        
# 实例化对象
dog=Animal('wc',2)
print(dog.get_info())

# 调用实例方法修改私有属性
dog.set_info('nidie',3)
print(dog.get_info())

输出:

name=wc,age=2
name=nidie,age=3

强制访问私有属性

通过实例强制访问私有属性:实例名._类名__属性名

class Animal:
    # 初始化方法
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
        
# 实例化对象
dog=Animal('wangwang',2)

# 强制访问私有属性
print(dog._Animal__name)
print(dog._Animal__age)

输出:

wangwang
2

类方法

类方法和实例方法的区别

操作实例对象的属性可以使用实例方法,如果需要操作类的属性,就需要使用类方法

类方法需要使用装饰器@classmethod

与实例方法不同的是:

  1. 类方法需要使用@classmethod来标记为类方法,否则定义的还是实例方法
  2. 类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.__localtion 实际上相当于Animal.__localtion
  3. 类方法无法获得任何实例属性,只能获得类的引用

实例方法

在类Animal中,创建实例dog,cat,可以通过该实例调用的方法,如dog.get_info

# -*- coding=utf-8 -*-
class Animal:
    # 私有属性
    __count=0
    
    # 初始化方法
    def __init__(self,name,age):
        self.name=name
        self.age=age
        Animal.__count+=1
    
    # 实例方法
    def get_info(self):
        return '我是{},今年{}岁了。总计数:{}个'.format(self.name,self.age,self.__count)
    
    # 类方法
    @classmethod
    def get_cnt(cls):
        return cls.__count
        
dog=Animal('汪汪',2)
cat=Animal('喵喵',3)
print(dog.get_info())
print(cat.get_info())

输出:

我是汪汪,今年2岁了。总计数:2个
我是喵喵,今年3岁了。总计数:2

类方法

类方法不能直接操作实例属性,必须通过类实例才能操作。

类方法推荐使用类名直接调用,当然也可以使用实例对象调用(不推荐)。

Animal.get_cnt可以调用,使用dog.get_cnt也可以调用,但是不推荐这样使用

dog=Animal('汪汪',2)
cat=Animal('喵喵',3)
print(dog.get_cnt())
print(Animal.get_cnt())

输出:

2
2

继承类

当已经创建了一个类Person后,还可以再细分为其他类,这些类和Person类相似,比如添加几个属性,修改几个方法

此时,不需要重新新建一个类,可以从原来的类中派生一个新的类,原来的称为父类或者基类/超类,派生出的称为子类,子类继承了父类的所有数据和方法

# 父类
class Animal:
    def __init__(self,name):
        self.name=name
    
    def greet(self):
        print(f'我是{self.name}')

# 子类继承父类
class Dog(Animal):
    def greet(self):
        print(f'汪汪,我是{self.name}')
        

Dog 类是从 Animal 类继承而来的,Dog 类自动获得了 Animal 类的所有数据和方法,而且还可以对从父类继承来的方法进行修改,调用的方式是一样的

animal = Animal('animal')
animal.greet()
dog = Dog('dog')
dog.greet()

输出:

我是animal
汪汪,我是dog

子类添加方法

给子类Dog添加一个run的方法

# 子类
class Dog(Animal):
    def greet(self):
        return (f'汪汪,我是{self.name}')

    # 跑的方法
    def run(self):
    	return ('撒丫子')

dog=Dog('dog')
print(dog.greet()+',我在'+dog.run())

输出:

汪汪,我是dog,我在撒丫子

super()函数

super() 函数是用于调用父类的一个方法

是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到MRO【方法解析顺序(Method Resolution Order)】、重复调用(钻石继承)等种种问题

语法[Python2]
super(class[,self]).method(param1...)
super(class[,self]).__init__(param1...)

此处的class为当前的子类名,如class Person中,子类class Student(Person)super语句为super(Student,self).__init__(name,age)...

语法[Python3]
super().method(param1...)
super().__init__(param1...)
示例

继承父类的属性和方法,使用spuer方法,新增的属性单独添加

# 父类
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def greet(self):
        print(f'我是{self.name},我{self.age}了')

# 子类
class Teacher(Person):
    def __init__(self,name,age,score):
        # 继承父类的属性,使用super继承name,age
        super(Teacher,self).__init__(name,age) # super(Teacher,self).__init__(name,age)
        # 新增的属性单独添加
        self.score=score
    
    def greet(self):
        # 继承父类的方法,输出内容为父类的print内容
        super(Teacher,self).greet() # super(Teacher,self).greet()
        print(f'我是{self.name},我{self.age}了,综合评分{self.score}')

t=Teacher('张三',29,87.5)
t.greet()

输出:

我是张三,我29了
我是张三,我29了,综合评分87.5

实例

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Parent(object):
    def __init__(self):
        self.parent = '我是父类'
        print ('Parent')

    def info(self,message):
        print ("%s 来自父类" % message)

class Child(Parent):
    def __init__(self):
        # super(Child,self)首先找到Child的父类Parent,然后把类Child的对象转换为类Parent的对象
        super(Child,self).__init__()
        print ('子类')

    def info(self,message):
        super(Child, self).info(message)
        print ('子类的 info 方法')
        print (self.parent)

# 主函数
if __name__ == '__main__':
    child = Child()
    child.info('Hello World')

输出:

Parent
子类
Hello World 来自父类
子类的 info 方法
我是父类

isinstance()函数类型判断

通过isinstance()函数可以判断一个变量的类型

语法

isinstance(type,class)# 判断type是不是class类型

实例

定义类

现有父类Person(name,gender),子类Student(name,gender,score)Teacher(name,gender,course)

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

class Teacher(Person):
    def __init__(self, name, gender, course):
        super(Teacher, self).__init__(name, gender)
        self.course = course
实例化对象
p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')
判断父类

判断p,s,t这几个变量的时候可以使用isinstance()判断类型

isinstance(p,Person)	# ==> True
isinstance(p,Student)	# ==> False
isinstance(p,Teacher)	# ==> False

这说明在继承链上,一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法

判断子类
isinstance(s,Person)	# ==> True
isinstance(s,Student)	# ==> True
isinstance(s,Teacher)	# ==> False

因为Student继承自Person,所以s也是Person类型

多态

它是指对不同类型的参数进行相同的操作,根据对象类型不同做出不同的行为,继承拿到父类的数据和方法,子类可以重新父类的方法,可以自己添加新的方法,有了继承才有多态,实现为不同数据提供一个统一的接口

实例

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def who(self):
        return 'I am a Person, my name is %s' % self.name

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score
    def who(self):
        return 'I am a Student, my name is %s' % self.name

class Teacher(Person):
    def __init__(self, name, gender, course):
        super(Teacher, self).__init__(name, gender)
        self.course = course
    def who(self):
        return 'I am a Teacher, my name is %s' % self.name
    
p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')

print(p.who())
print(s.who())
print(t.who())

输出:

I am a Person, my name is Tim
I am a Student, my name is Bob
I am a Teacher, my name is Alice

这种行为别成为多态,一般调用的时候先从子类自身查找方法,如果自身没有,再按照继承链向上找

多重继承

多种继承主要在出现组合情况的时候使用,如果没有多重继承,那么使用组合情况可能需要更多的子类

例如python的网络服务器有:TCPServerUDPServerUnixStreamServerUnixDatagramServer

服务器运行模式有:多线程ThreadingMixin多进程ForkingMixin

要创建多线程TCPServer

class MyServer(TCPServer,ThreadingMixin)

要创建多进程UPDServer

class MyServer(UPDServer,ForkingMixin)

实例

已知类Student、Teacher继承Person类,技能类BasketballMixin、FootballMixin继承SkillMixin类,请通过多重继承,分别定义“会打篮球的学生”和“会踢足球的老师”

# -*- coding=utf-8 -*-
# 人员
class Person(object):
    def __init__(self):
        print("Person")
    
class Student(Person):
    def __init__(self):
        super(Student,self).__init__()
        print("Student")

class Teacher(Person):
    def __init__(self):
        super(Teacher,self).__init__()
        print("Teacher")

# 技能
class SkillMixin(object):
    def __init__(self):
        print("SkillMixin")

class BasketballMixin(SkillMixin):
    def __init__(self):
        super(BasketballMixin,self).__init__()
        print("BasketballMixin")

class FootballMixin(SkillMixin):
    def __init__(self):
        super(FootballMixin,self).__init__()
        print("FootballMixin")

# 会打篮球的学生
class BasketballStudent(BasketballMixin,Student):
    def __init__(self):
        super(BasketballStudent,self).__init__()
        print('会打篮球的学生')

# 会踢足球的老师
class FootballTeacher(FootballMixin,Teacher):
    def __init__(self):
        super(FootballTeacher,self).__init__()
        print('会踢足球的老师')

s=BasketballStudent()
t=FootballTeacher()

输出:

SkillMixin
BasketballMixin
会打篮球的学生
SkillMixin
FootballMixin
会踢足球的老师

获取对象信息

前文中,可以通过isinstance()方法来判断是否是某个类型,现在需要获取更多的信息

获取类型type()

通过type()方法可以获取变量的类型

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

p = Person('Alice', 'Female')
s = Student('Bob', 'Male', 100)
type(p) # ==> <class '__main__.Person'>
type(s) # ==> <class '__main__.Student'>

输出:

<class '__main__.Person'>
<class '__main__.Student'>

获取属性dir()

通过dir()方法可以获取变量的所有属性

dir(p)

输出:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name']

dir()返回的属性是字符串列表,其中__xxx__为特殊属性和方法,可以直接访问

如果其中存在私有属性,如:初始化属性中的gender改为self.__gender=gender,则输出:

['_Person__gender', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', 
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']

获取设置对象属性

dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() setattr()函数

如上例中的:

p = Person('Alice', 'Female')
s = Student('Bob', 'Male', 100)

获取pname属性

getattr(p,'name')				# ==> 'Alice'

如果有私有属性,需要强制访问,方式为_类名__属性名(详情见:强制访问私有属性

getattr(p,'_Person__gender')	# ==> 'Female'

如果获取的属性不存在,则会报错

getattr(p,'age')	# ==> AttributeError: 'Person' object has no attribute 'age'

如果获取的属性不存在,指定默认返回值

getattr(p,'age',20)				# ==> 'Female'

设置属性值

setattr(p,'name','Mike')		# 'Alice' ==> 'Mike'

可变参数

可以用setattr()方法来设置属性值,可变参数,可以用来添加任意关键字参数,以键值对的方式设置值

class Person(object):
    def __init__(self, name, gender, **agrv):
        self.name = name
        self.gender = gender
        for k,v in agrv.items():
            setattr(self,k,v)
            
p = Person('Bob', 'Male', age=18, course='Python')
print(p.age)
print(p.course)

输出:

18
Python

如果不使用setattr()方式来添加参数,可以使用for循环遍历,例如设计一个求平均数的函数

def average(*agrv):
    sum = 0
    if len(agrv) == 0:
        print(sum)
    for i in agrv:
        sum += i
    avg = sum / len(agrv)
    print(avg)

average(1,5,6,24)

输出:

9.0

类的特殊方法

__str__()方法

通常变量可以通过str()函数转换为字符串类型输出,但是自定义的类无法转换成字符串

class Person:
    # 初始化方法
    def __init__(self):
        self.name = '张三'

    # 自定义方法
    def greet(self):
        print('你好,我是'+self.name)

p1=Person()
p1.greet()
str(p1)

输出:

你好,我是张三
'<__main__.Person object at 0x00000257907AD760>'

输出发现str()返回的是这个实例的地址,这是因为使用的是对象的内建方法__str__返回的

如果自定义的类也实现__str__()方法,便可以转换为字符串输出

class Person:
    # 初始化方法
    def __init__(self):
        self.name = '张三'

    # 自定义方法
    def greet(self):
        print('你好,我是'+self.name)
        
    def __str__(self):
        return '你好,我是'+self.name	# return str(self.name)

p1=Person()
p1.greet()
str(p1)

输出:

你好,我是张三
'你好,我是张三'

此时发现,如果只输入p1,显示的仍然是地址

<__main__.Person object at 0x00000257907A4E50>

__repr__()方法

上述情况是因为Python定义了__str__()__repr__()两种方法,__str__()显示给用户,而__repr__()显示给开发人员,当使用str()时候,实际调用的是__str__()方法,而直接输入变量,调用的是__repr__()方法,所以需要再实现__repr__()方法

class Person:
    # 初始化方法
    def __init__(self):
        self.name = '张三'

    # 自定义方法
    def greet(self):
        print('你好,我是'+self.name)
        
    def __str__(self):
        return '你好,我是'+self.name
    
    def __repr__(self):
        return '你好,我是'+self.name

p1=Person()
p1.greet()
str(p1)

输出:

你好,我是张三
'你好,我是张三'
你好,我是张三

__len__()方法

对于列表List和元组Tuple,都可以使用内建方法len()来获取元素个数,如果需要达到这个效果,就需要实现__len__()方法

例如有个班级Class类,初始化把学生列表传进去,通过len()函数可以返回学生个数

class Class:
    def __init__(self,students):
        self.students=students
        
    def __len__(self):
        return len(self.students)

stu=['Mike','James','Alice']
cls=Class(stu)
print(f'此班级有 {len(cls)} 名学生')

输出:

此班级有 3 名学生
实例

实现一个斐波那契数列:0,1,1,2,3,5,8…,创建一个Fib类,Fib(10)表示数列前十个元素,print(Fib(10))可以打印输出,len(Fib(10))可以返回数列个数10

class Fib(object):
    def __init__(self,num):
        self.res=[]
        self.num=num
        a,b=0,1
        for i in range(num):
            self.res.append(a)
            a,b=b,a+b
    def __str__(self):
        return str(self.res)
        
    def __len__(self):
        return len(self.res)
        
f=Fib(10)
print(f)
print(str(f))
print(len(f))

输出:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
10

__slots__()方法

用来限制可添加的属性,如此时有一个Student类,包含name,gender,score这几个属性

class Student:
    def __init__(self,name,gender,score):
        self.name = name
        self.gender = gender
        self.score = score

类中的参数都可以动态的添加,如此时再添加一个age属性

s=Student('Mike','Male',87)
s.age=25	# 动态添加属性age

如果不做限制,会有很多属性,不便于后期管理,所以需要使用__slots__()方法来限制添加的属性

class Student:
    __slots__ = ('name', 'gender', 'score','total')
    def __init__(self,name,gender,score):
        self.name = name
        self.gender = gender
        self.score = score

此时执行动态添加属性age的语句,会报错,如果添加total则不会报错

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

假设Person类通过__slots__定义了namegender,请在派生类Student中通过__slots__继续添加score的定义,使Student类可以实现namegenderscore3个属性。

class Person(object):
    __slots__=['name','gender']
    def __init__(self,name,gender):
        self.name=name
        self.gender=gender

class Student(Person):
    __slots__=['score']
    def __init__(self,name,gender,score):
        super(Student,self).__init__(name,gender)
        self.score=score

s=Student('Alice','Female',96)
s.name='Bob'
s.score=87
print(s.score)

__call__()方法

Python中,函数是一个对象,可以将一个函数赋值给一个变量,且不改变函数的功能

>>> f=abs
>>> f
<built-in function abs>
>>> f.__name__
'abs'
>>> f(-123)
123

此时,f被称为可调用的对象,其实所有的函数都是可调用对象

如果把一个类实例也变成一个可调用对象(函数),需要实现一个__call__()方法

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    def __call__(self,friend):
        print('My name is {}.'.format(self.name))
        print('My friend is {}.'.format(friend))
      
p=Person('Bob',25)
p('Mike')		# ==> 用函数的方式调用Person类的实例p

输出:

My name is Bob.
My friend is Mike.
实例

对前面的斐波那契数列类Fib,加入__call__方法

class Fib(object):
    def __init__(self):
        self.res=[]
        
    def __call__(self,num):
        self.num=num
        a,b=0,1
        for i in range(num):
            self.res.append(a)
            a,b=b,a+b
        return self.res
f=Fib()
print(f(10))	# 可以像函数一样调用

输出:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

模块和包

为了便于管理自定义的内容,可以将模块根据特定规则划分到包中

导入格式:from 包 import 模块

包必须包含__init__.py文件,模块文件没有__init__.py文件

自定义模块

定义一个叫tools的模块,模块名:tools.py

# tools.py
def say_hello(name):
    print('你好啊{}'.format(name))

def say_goodbye(name):
    print('拜拜{}'.format(name))

格式

import 模块名1 [as 别名1], 模块名2 [as 别名2],…

from 模块名 import 成员名1 [as 别名1],成员名2 [as 别名2],…

导入模块

导入官方模块不需要考虑路径问题,导入自定义模块需要考虑路径(详情见:导入模块的路径)

导入整个模块

import MODULE

导入模块的部分属性或函数

from PACKAGE import MODULE

导入模块中的所有内容

from PACKAGE import *

为了防止导入的函数与本文件的函数冲突,有两种方法解决:

  1. 直接导入模块,不指定具体内容
  2. 使用from PACKAGE import MODULE as NAME把导入的内容进行重命名

如使用两种方法导入math模块的sin(),cos()函数

# 从模块导入所有类
from math import sin,cos,pi
sin(pi/2)
cos(pi/3)

# 导入整个模块
import math
math.sin(pi/2)
math.cos(pi/3)

# 使用别名
from math import sin as s,pi
s(pi/2)

导入模块的路径

使用sys模块中的path变量,可以得到一个路径列表,导入模块的时候会搜索这个路径列表,如果想要添加路径,可以给sys.path赋值

import sys					# 或from sys import path
sys.path.append('../')		#   path.append('../')
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值