A2:类与实例
类是什么?一切事物皆对象,即所有的东西都是对象,对象是可以看到、摸到、感觉到、听到、闻到、尝到的东西。
对象是一个自包含的实体,用一组可识别的特性和行为来识别。面向对象编程,就是object-oriented programming(针对对象进行编程)
首先,编写一个程序,猫叫。
def cat_shut():
print("miao")
cat_shut()
如果别的python文件也想让猫叫呢?别的Python文件引用?这个猫叫的函数有没有更合适的地方呢?就是类,放到单独的类中。类就是具有相同属性和方法的集合。
class Cat:
def cat_shut(self):
print("miao")
- 类名第一个字母大写,如果是多个单词,每个单词的第一个字母大写
- 对外公开的方法没有修饰符。Python 中声明私有方法,请在方法名称的开头插入双下划线。
怎么用这个类呢?实例化。实例,就是一个真实的对象,比如我们都是「人」,我们都是「人」的实例。实例化就是创建对象的过程。
cat = Cat()
cat.cat_shut()
A3:构造方法
希望出生的猫咪都有自己的名字,在猫叫的时候,说我叫什么名字。此时,就需要构造函数。
构造方法,又叫构造函数,就是对类进行初始化。在类创建的时候,就是调用构造方法的时候了。可是上面的代码,我们并没有实现构造方法呢?怎么调用的?
所有类都有构造方法,如果你没有定义,就会调用默认生成的空的构造方法。若有自定义的构造方法,默认的构造方法就失效了。
class Cat:
def __init__(self, name):
self.__name = name
def cat_shut(self):
print("my name is %s, miao" % self.__name)
cat = Cat("mimi")
cat.cat_shut()
c# 如下
using System;
namespace HelloWorldApplication
{
class Cat
{
private string name = "";
public Cat(string name){
this.name = name;
}
public string Shout(){
return "my name is " + name + " miao";
}
}
class HelloWorld
{
static void Main(string[] args){
Cat cat = new Cat("abc");
Console.WriteLine(cat.Shout());
}
}
}
python中,两个下划线开头的为私有属性,否则会公有属性。
私有属性只允许类内部访问。
A4:方法重载
C#中,有的父母孩子生下来,并没有名字,如果写cat=Cat()就会报错。
如果猫咪即使没有名字,也要生下来,可以使用方法重载。
using System;
namespace HelloWorldApplication
{
class Cat
{
private string name = "";
public Cat(string name){
this.name = name;
}
public Cat(){
this.name = "无名";
}
public string Shout(){
return "my name is " + name + " miao";
}
}
class HelloWorld
{
static void Main(string[] args){
Cat cat = new Cat("abc");
Console.WriteLine(cat.Shout());
Cat cat2 = new Cat();
Console.WriteLine(cat2.Shout());
}
}
}
方法重载提供了创建多个同名方法的能力,这些方法具有不同的参数类型。而且,不仅构造方法可以方法重载,普通方法也是可以重载的。
方法重载的好处是什么?可以在不改变原有方法的基础上,新增功能。方法重载提供了扩展函数的能力。
如果要分清猫咪的姓和名,还可以再重载实现一个方法。eg:
public Cat(string firstName, string secondName){
xxxx
}
但是Python是不支持方法重载的,假如声明多个方法同名,参数类型不同的方法,方法调用的时候,只会调用最后一个定义的同名方法。
但可以通过逻辑改变来实现方法重载。默认参数的形式。
class Cat:
def __init__(self, name):
self.__name = name
def cat_shut(self):
print("my name is %s, miao" % self.__name)
def cat_eat(self, food="apple"):
print("cat eat %s" % food)
cat = Cat("mimi")
cat.cat_shut()
cat.cat_eat("orange")
cat.cat_eat()
# 输出
my name is mimi, miao
cat eat orange
cat eat apple
A5:属性与修饰符
属性是一个方法或者一对方法,在调用它的代码来看,适合使用字段的方式来调用方法的场合。
字段是存储类要满足其设计所需的数据,字段是与类有关的变量。比如上面的name就是一个字段。
那么,属性是什么呢?
下面新增了一个猫叫次数的ShoutNum属性。
class Cat
{
private string name = "";
// 这里是小写
private int shoutNum = 3;
// 这里是大写
public int ShoutNum
{
get
{
return shoutNum;
}
set
{
shoutNum = value;
}
}
public Cat(string name)
{
this.name = name;
}
public Cat()
{
this.name = "no name";
}
public string Shout()
{
return "my name is" + name + ", miao";
}
}
public指该成员可以被其他任何类来访问,俗称公有的。
private只能被同一类的成员访问,其他类包括它的子类都无法访问,俗称私有的。
如果类成员没有加修饰符,则默认为private。
还有其他三种修饰符,后面再讲。
通常,
字段都是私有的,即私有的变量
属性都是公有的,即公有的变量
这里shoutNum就是私有变量,属性名一般小写开头,或者_开头。
ShoutNum就是公有的对外属性,属性名一般大写开头。
属性的get和set
属性有两个方法get和set。
- get访问器返回与声明的属性相同的数据类型,表示的意思是调用时可以得到内部字段的值或引用;
- set访问器没有显式设置参数,但它有一个隐式参数,用关键字value表示,它的作用是调用属性时可以给内部的字段或引用赋值。
那又何必呢, 我把字段的修饰符改为public, 不就可以做到对变量的既读又写了吗?
如果仅仅是可读可写,那与声明了public的字段没什么区别。但是对于对外界公开的数据,通常希望能做更多的控制,这就好像我们的房子,我们并不希望房子是全透明的,那样你在家里的所有活动全部都被看得清清楚楚,毫无隐私可言。
通常我们的房子有门有窗,但更多的是不透明的墙。这门和窗其实就是public, 而房子内的东西,其实就是private。而对于这个房子来说,门窗是可以控制的,我们并不是让所有的人都可以从门随意进出,也不希望蚊子苍蝇来回出入。这就是属性的作用了,如果你把字段声明为public,那就意味着不设防的门窗,任何时候,调用者都可以读取或写入,这是非常糟糕的一件事。如果把对外的数据写成属性,我 那情况就会好很多。