类可以认为是定义了属性和行为了一个整体,而对象可以看做是由类为模板,给类中的属性赋予了值的实例。
很多语言都有可以面向对象编程,Python也是一样,这些面向对象的编程语言在操作对象时基本上大同小异,只是语法不同而已。
因此对于成员变量、方法、静态方法、子类、父类这些基本的概念就不在赘述了,直接拿Java中的类和对象来类比。
定义一个类,无非就是创建成员变量、构造方法、getter、setter和一些普通方法对一个对象的成员变量进行操作。 例如,下面用Java写了一个类:
class Student { private int number; private String name; public Student(int number, String name) { this.number = number; this.name = name; } public void sayHello() { System.out.println("Hello, I am " + this.name); } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [name=" + name + ", number=" + number + "]"; } } public static void main(String[] args) { Student stu = new Student("001", "Jackson"); stu.setName("Roy"); stu.sayHello(); // Hello, I am Roy }对应成Python就是:
class Student: def __init__(self, number = None, name = None): self.__number = number self.__name = name def sayHello(self): print(f'hello, I am {self.number}') @property def number(self): return self.__number @number.setter def number(self, number): self.__number = number @property def name(self): return self.__name @name.setter def name(self, name): self.__name = name def __str__(self): return f"Student [number={self.number}, name={self.name}]" stu = Student('001', 'Jackson') print(stu.name) # Jackson 调用了getter方法 stu.name = 'Roy' # 将name改为了Roy,调用setter方法 stu.sayHello() # Hello, I am Roy一个类必然有属性,Java中属性(字段)都是定义在类里面方法外面,为了更好的封闭性,将属性(字段)设置为private类型,然后提供getter和setter来访问该属性(字段)。 比如Java中定义一个变量name:
private String name;而Python,字段不需要声明类型,直接定义/赋值就行。因此对于一般字段(跟随对象的字段)直接写在构造方法里面直接赋值。
Python中,如果想设置某个字段为private,那么就命名该字段时,以两个下划线开头,比如:__name。
Java中构造方法是public+类名,比如:
public Student(String name){ this.name = name; }而Python中构造方法是用__init__()方法,比如def __init__(self){},比如:
def __init__(self, name): self.name = name它们都是通过参数传递给成员变量赋值。
需要注意的是,Python中的任何方法的定义,都必须要有一个self参数,self的使用就像是Java中的this。为了更好的封闭性,将类中的属性设置为private封装起来,然后提供方法来访问和修改该属性,比如提供getter来访问字段,setter来设置某个字段值。
Java中一般set方法命名都是setXxx比如setName,然后新的值作为参数传递进来:
public void setName(String name) { this.name = name; } public Stirng getName() { return this.name; }而Python的习俗似乎不喜欢使用setXxx来命名setter,而是setter和getter和字段同名。 为了区别于普通方法,因此需要在getter和setter上面加上“修饰器(Decorator)”(我觉得十分类似Java中的注解)。
@property def name(self): return self.__name @name.setter def name(self, name): self.__name = namePython中调用Setter和Getter的方式也和调用普通方法不相同。 对于一般方法,都是将值作为实参传入,但是,Python中使用Getter和Setter操作字段时,是直接对象.方法。比如:
print(stu.name) # 不是输出name属性,而是调用了name的get方法 stu.name = 'Roy' # 不是直接给name属性赋值,而是调用了name的set方法在Java中,会有一个每个对象可以有一个tostring方法,这样就可以直接定制对象的输出形式,在Python中,这个方法叫做__str__方法。
在Java中,有一个变量在该类第一次加载时就会初始化,只跟随类,于对象无关,这样的字段/变量做静态变量。在定义时使用static修饰。
Python中也有这种跟随类的变量,叫做类变量。 但是Python中的的变量并没有声明也就没有修饰符比如static,如何表示静态变量呢?
Python中写在类里面方法外面的变量可以是类变量。 比如:
class Person: count = 0 def __init__(self): Person.count += 1 Person() Person() Person() print(Person.count) # 3但是,在方法外面定义的变量也可以使用self访问,但是不能修改:
class Person: count = 0 def __init__(self): print(id(self.count)) print(id(Person.count)) # 相等 # 上面两种访问方式访问到的是同一个变量如果进行修改,就会变成两个变量:
class Person: count = 0 def __init__(self): self.count = 3 print(id(self.count)) print(id(Person.count)) # 不想等 # 对self.count进行赋值后,不再是同一个变量Python中一个对象可以有很多内置方法,十分人性化,常见的比如__str__、__eq__方法,还有很多这种内置方法,比如定义对象与对象的运算(加减乘除),对象与对象进行比较(>=、<=之类)等一系列人性化的方法,让很多只能用于内置对象的语法也可以用在自定义对象上,十分魔幻。 很多魔法方法的介绍可以看这里:Python - Magic Methods。
子类Child继承父类Father:
class Father: def __init__(self): self.gnene = 1 class Child(Father): def __init__(self): super().__init__(self)Python继承一个类,只需在定义类时,把父类写在括号里面即可。
Python中,调用父类的方法,有两种方式:
使用super().父类的方法直接父类名称.父类方法名例如下面:
class Parent(): def __init__(self): self.gene = 1 def sayHello(self): print('hello, I am super class') class Child(Parent): def __init__(self): super().__init__() # OK Parent.__init__() # 也OKPython支持多继承,例如:
class Father: def __init__(self): self.gene = 1 class Mother: def __init__(self): self.gene = 2 class Child(Father, Mother): def __init__(self): super().__init__(self)这样子类会同时继承父类的方法和字段,假如父类的方法和字段冲突了,就继承从左往右,第一个父类的方法或字段。
我觉得Python的继承不严谨,比如:
class Father: def __init__(self): self.gene = 1 class Mother: def __init__(self): self.gene = 2 class LaoWang: def __init__(self): self.gene = 3 class Child(Father, Mother): def __init__(self): LaoWang.__init__(self) # 重点 c = Child() print(c.gene) # 输出 3Python面向对象和其他语言面向对象大同小异,思想几乎是一样的,只是语法不同,可能有细微的特性不同。