python - 面向对象

类和对象

类(Class):字段和方法是类的属性。(这两个术语,用以区分普通的变量和函数)只有当你拥有一个该类的对象时,你才能使用这些字段和方法

对象(Object):是类的实例

1 class Person:  # 类:关键字class 类名 冒号
2     pass
3 
4 
5 p = Person()  # 对象:类名后跟一对括号
6 print(p)      # 打印 <__main__.Person object at 0x00532E08>

 

self:

类方法与普通函数只一个区别,类方法必须有一个额外的参数self,位于参数列表开头,但是不用在调用这个方法时为这个参数赋值,python会自动为它提供。这种特定的变量引用的是对象本身。如果你有一个没有参数的方法,也至少有一个参数self。

1 class Person:
2     def say_hi(self):  # say_hi()方法不需要参数,但函数定义中仍有self
3         print('hi')
4 
5 
6 p = Person()
7 p.say_hi()

 

__init__()方法

 1 class Person:
 2     def __init__(self, name):   # 构造函数,在类的对象初始化时自动调用
 3         self.name = name
 4 
 5     def say_hi(self):
 6         print('hi,my name is {}'.format(self.name))
 7 
 8 
 9 p = Person('zhangsan')  # 隐式调用__init__()方法
10 p.say_hi()

 

实例变量和类变量

类的字段有两种类型:类变量与对象变量。它们根据是类还是对象拥有这些变量来分类。

  • 类变量:是共享的,它们可以被属于该类的所有实例访问。该类变量只有一个副本,当任何一个对象对类变量做出改变时,发生的变动将在其它所有实例中得到体现。
  • 对象变量:由类的每一个独立的对象或实例所拥有。每个对象都拥有属于自己的字段副本,也就是说,它们不会被共享,也不会以任何方式与其它不同实例中的相同名称的字段产生关联。
  • 类方法:属于类的方法,也叫静态方法。该方法中引用类变量。可以使用装饰器将一个方法标记为类方法
引用类变量:类名.变量名
引用对象变量:self.变量名
引用类方法:类名.方法名
class Robot:

    num = 0  # number属于Robot类,因此它是一个类变量

    def __init__(self, name):
        self.name = name  # name属于一个对象,因此它是一个对象变量
        Robot.num += 1  # 引用类变量(类名.变量名)也可以使用:self.__class__.number += 1 因为每个对象都通过self.__class__属性来引用它的类

    def sayhi(self):
        print(f'hi, {self.name}')  # 引用对象变量(self.变量名)

    @classmethod  # 使用装饰器decorator将print_num()方法标记为类方法
    def print_num(cls):
        print(f'num={Robot.num}')


# 机器人1
r1 = Robot('zhangsan')
r1.sayhi()

Robot.print_num()
r1.print_num()


# 机器人2
r2 = Robot('lisi')
r2.sayhi()

Robot.print_num()
r2.print_num()


print(id(Robot.num), Robot.num)  # 此处r1.num,r2.num,Robot.num指向同一个内存地址,是同一个变量
print(id(r1.num), r1.num)
print(id(r2.num), r2.num)

打印如下:

hi, zhangsan
num=1
num=1
hi, lisi
num=2
num=2
4389296960 2
4389296960 2
4389296960 2

 

以下定义了对象变量r1.num后,r1.num和Robot.num就只是同名,但实质不同的两个变量

r1.num += 3
print(id(Robot.num), Robot.num)  # 此处r2.num,Robot.num指向同一个内存地址,r1.num指向另一个不同的地址
print(id(r1.num), r1.num)
print(id(r2.num), r2.num)

打印如下:

4330748736 2
4330748832 5
4330748736 2

  

私有变量:

所有类成员都是公开的,除非使用双下划线作为前缀,例如:__privatevar,python会认为是一个私有变量

 

 

 

继承:

1. 父类,子类

 1 class SchoolMember:
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5         print('initialized SchoolMember: {}'.format(self.name))
 6 
 7     def tell(self):
 8         print('name: {}, age: {}'.format(self.name, self.age), end=' ')
 9 
10 
11 class Teacher(SchoolMember):  # 继承SchoolMember
12     def __init__(self, name, age, salary):
13         SchoolMember.__init__(self, name, age)  # 通过self显式调用父类的__init__方法(如果子类没有定义__init__方法,python会自动调用基类的构造函数)
14         self.salary = salary
15         print('initialized Teacher: {}'.format(name))
16 
17     def tell(self):
18         SchoolMember.tell(self)  # 在方法名前面加上类名,再传入self和其他变量,来调用基类方法
19         print('salary:{}'.format(self.salary))
20 
21 
22 class Student(SchoolMember):
23     def __init__(self, name, age, marks):
24         SchoolMember.__init__(self, name, age)
25         self.marks = marks
26         print('initialized Student: {}'.format(self.name))
27 
28     def tell(self):
29         SchoolMember.tell(self)
30         print('marks: {}'.format(self.marks))
31 
32 
33 t = Teacher('wanglaoshi', 80, 20000)
34 s = Student('lisi', 22, 98)
35 
36 mm = [t, s]
37 
38 for member in mm:
39     member.tell()    # 当使用SchoolMember类的tell()方法时,可以将Teacher或Student的实例看做SchoolMember的实例。python会从当前的实际类型中寻找方法,若子类中未定义tell()方法,则会调用父类的tell()方法

2. 多态性:在不考虑实例类型的情况下使用实例,也就是说,不同类型的实例有相同的调用方法。比如上例中的Teacher、Student、SchoolMember都有tell()方法,t和s可以以相同的形式调用tell()方法。优点:增加程序的可扩展性,例如,SchoolMember增加新的子类,使用者无需更改自己的代码,还是用tell()方法去调用

3. 多重继承:继承元组中有超过一个类,例如:

 1 class B:
 2     pass
 3 
 4 
 5 class C:
 6     pass
 7 
 8 
 9 class A(B, C):  # 多重继承(继承B和C)
10     pass

 

posted @ 2020-02-08 14:21  小虫虫大虫虫  阅读(226)  评论(0编辑  收藏  举报