python入门之:函数+类+对象

函数+类+对象

函数

与java不同的是,参数并不用事先声明类型

def add(x, y, z):
    return x + y + z


print(add(1, 2, 3))

全局变量和局部变量

简单的来说,局部变量是在函数内定义的变量,只能在定义它的函数中使用。
全局变量,是定义在函数之外的变量,它可以在程序的任何位置使用。

默认参数

def add(x, y, z, m=10):
    return x + y + z + m


print(add(1, 2, 3))
print(add(1, 2, 3, 4))
16
10

不定长参数

元组形式导入(*)

在创建函数时,将参数前面加上*,加上*号的参数被接收后会以元组的形式导入。

def add(a, *b):
    print(a)
    print(b)
    for i in b:
        print(i)


add(1, 2, 3, "string", "new")
1
(2, 3, 'string', 'new')
2
3
string
new
字典形式导入(**)
def add(a, **kwargs):
    print(a)
    print(kwargs)
    for i in kwargs.items():
        print(i)


add(1, b=2, c=3, e="hello")

结果

{'b': 2, 'c': 3, 'e': 'hello'}
('b', 2)
('c', 3)
('e', 'hello')

匿名函数

通过使用lambda来创建匿名函数,它是一种无需定义函数名的函数,可以通过变量来记录该函数。
相比普通函数,其只能是单个表达式,即lambda函数的语法中只包含一个语句,所以其功能比较单一且不能被其它程序使用。

add = lambda a, b, c: a * b / c * 0.5
print(add(20, 30, 60))

结果5.0

递归函数

递归函数,它可直接或间接地调用函数自身。其中函数递归时,要有递归公式和边界条件,递归公式用于分解规模较大的问题为规模较小的问题,边界条件用于终止递归函数。

def f(x):
    if x == 1:
        return 1
    else:
        return x + f(x - 1)


print(f(3))

结果6

思路

f(3)=3+f(2)

f(2)=2+f(1)

f(1)=1

再逆推

f(2)=2+f(1)=3

f(3)=3+f(2)=6

类与对象

类的定义+对象的创建和使用

class My:
    s = "zhangsan"

    def my(self, i):
        print(i)


if __name__ == "__main__":
    a = My()
    print(a.s)
    a.my("string")

私有成员和私有方法的定义和使用

定义类中的属性和方法默认为公有属性公有方法,该类中的对象可以任意访问类中的公有成员和公有方法,可以通过将成员和方法定义为私有,即私有成员和私有方法,从而限制对象对类的访问

通过在类成员名称或类方法名称前面加上双下划线__限制成员的访问,即定义为私有成员和私有方法

这里要注意,实例化的对象是无法直接访问类中的私有成员和私有方法的,它们都可通过公有方法中的参数self调用

class My:
    __s = "zhangsan"

    def __my(self, i):
        print(i)

    def order(self):
        print("共有方法通过self访问私有成员" + self.__s)
        self.__my("hello")

if __name__ == "__main__":
    a = My()
    a.order()

结果

共有方法通过self访问私有成员zhangsan
hello

构造方法和析构方法

类中有两个名为 __init__()__del__()的特殊方法,它们分别是构造方法析构方法,该两种方法在类创建销毁时会自动调用

构造方法

每个定义的类中都有一个默认的__init__()构造方法,如果在定义类时未定义,则系统会调用默认的构造方法,而如果用户在定义时显式地定义了构造方法,则会调用该定义的构造方法。

可以通过无参构造方法有参构造方法来分别对该方法创建的对象赋予相同的初始值和不同的初始值。

注:这里按照参数的有无分为两种构造方法,但除了self,因为类中必须包含参数 self, 且为第一个参数。

class My:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def order(self):
        s = self.a * self.b / 2
        return s


if __name__ == "__main__":
    a = My(3, 4)
    print(a.order())

结果6.0

析构方法

对象被清理时,系统会自动调用析构方法,即对象在内存中被释放时自动触发执行__del__()析构方法

class My:
    def __init__(self, a, b):
        self.a = a
        self.b = b
        print("__init__构造函数被执行")
    def __del__(self):
        print("__del__析构函数被执行")

    def order(self):
        s = self.a * self.b / 2
        return s


if __name__ == "__main__":
    a = My(3, 4)
    print(a.order())

结果

__init__构造函数被执行
6.0
__del__析构函数被执行

类方法和静态方法

在使用 Python 编程时,一般不需要使用类方法或静态方法,程序完全可以使用函数来代替类方法或静态方法。但是在特殊的场景(比如使用工厂模式)下,类方法或静态方法也是不错的选择。

类方法

类方法通过装饰器@classmethod修饰,它的第一个参数并非类本身self,而是cls

与实例方法不一样,它既可由类实例化的对象调用,也可由类调用,且类方法可以修改类属性,而实例方法不能。

简单的说,你调用了类方法修改类属性A,该类的所有实例的属性A都被修改

但是,如果你通过实例B调用实例方法修改了属性A,则只有实例B的A属性变更了,其余实例没有变化。

通过类.类方法调用
class My:
    str = "hello world"

    @classmethod
    def leiFangFa(cls):
        cls.str = "lisi"  # 类方法可以修改类属性

    @classmethod
    def leiFangFaTwo(cls):
        print(cls.str)

    def shiLiFangFaTwo(self):
        self.str = "wangwu"  # 实例方法修改了str,只能修改实例的这个str,不能修改类的str

    def shiLiFangFaThree(self):
        print(self.str) # 实例方法,使用了类属性


if __name__ == "__main__":
    my = My()
    my2 = My()
    # My.shiLiFangFaTwo()  报错TypeError: shiLiFangFaTwo() missing 1 required positional argument:
    # 'self',因为实例方法一个有一个参数是self,但是类方法是没有的
    print("第一次调用实例方法,str获取hello world")
    my.shiLiFangFaThree()
    my2.shiLiFangFaThree()
    print("调用类方法,修改了类属性,不管有多少个实例,它的str都变成了lisi")
    My.leiFangFa()
    print("第二次调用实例方法,它的str都变成了lisi")
    my.shiLiFangFaThree()
    my2.shiLiFangFaThree()
    print("my实例通过实例方法,修改了str的值为wangwu")
    my.shiLiFangFaTwo()
    print("my实例通过实例方法,打印str的值为wangwu")
    my.shiLiFangFaThree()
    print("my2实例通过实例方法,打印str的值并没有与my实例的保持一致,而是打印的是lisi,为类的属性")
    my2.shiLiFangFaThree()
    print("再次调用类方法,获取str的值,没有被实例方法shiLiFangFaTwo改变,仍然是lisi")
    My.leiFangFaTwo()

结果

第一次调用实例方法,str获取hello world
hello world
hello world
调用类方法,修改了类属性,不管有多少个实例,它的str都变成了lisi
第二次调用实例方法,它的str都变成了lisi
lisi
lisi
my实例通过实例方法,修改了str的值为wangwu
my实例通过实例方法,打印str的值为wangwu
wangwu
my2实例通过实例方法,打印str的值并没有与my实例的保持一致,而是打印的是lisi,为类的属性
lisi
再次调用类方法,获取str的值,没有被实例方法shiLiFangFaTwo改变,仍然是lisi
lisi
通过实例.类方法调用

类.实例方法会报错,那实例.类方法呢

class My:
    str = "hello world"

    @classmethod
    def leiFangFa(cls):
        cls.str = "lisi"  # 类方法可以修改类属性

    @classmethod
    def leiFangFaTwo(cls):
        print(cls.str)

    def shiLiFangFaThree(self):
        print(self.str)


if __name__ == "__main__":
    my = My()
    my2 = My()
    print("第一次:首先两个实例分别打印出str的值,均为hello world")
    my.shiLiFangFaThree()
    my2.shiLiFangFaThree()
    print("第一次:通过类调用类方法获取str的值,为hello world")
    My.leiFangFaTwo()
    print("通过实例调用类方法,修改了类属性str的值为lisi")
    my.leiFangFa()
    print("第二次:再次通过两个实例获取str的值")
    my.shiLiFangFaThree()
    my2.shiLiFangFaThree()
    print("第二次:通过类调用类方法获取str的值,为lisi")
    My.leiFangFaTwo()

结果

第一次:首先两个实例分别打印出str的值,均为hello world
hello world
hello world
第一次:通过类调用类方法获取str的值,为hello world
hello world
通过实例调用类方法,修改了类属性str的值为lisi
第二次:再次通过两个实例获取str的值
lisi
lisi
第二次:通过类调用类方法获取str的值,为hello world
lisi
类方法的使用场景

类方法用在模拟java定义多个构造函数的情况。 由于Python类中只能有一个初始化方法,不能按照不同的情况初始化类。

说实在我没看明白是怎么实现的,可能后续能反应过来,所以先记录上

class Book():

    def __init__(self, title):
        self.title = title

    @classmethod
    def create(cls, title):
        book = cls(title=title)
        return book

book1 = Book("python")
book2 = Book.create("python and django")
print(book1.title)
print(book2.title)
python
python and django
静态方法

首先静态方法与类方法一样,既可由类实例化的对象调用,也可由类调用。静态方法没有self参数,是通过装饰器@staticmethod修饰

由于没有默认参数,所以它无法使用默认参数来访问类成员。

静态方法的优点:

1、它消除了self参数的使用。

2、它提高了代码的可读性,表示该方法不依赖于对象本身的状态。

静态方法的用途有限,因为它们不能访问类实例的属性(像常规方法那样),也不能访问类本身的属性(像类方法那样)。

所以它们对日常方法没有用处。

但是,它们可以用于将一些实用程序函数与一个类(例如,从一种类型到另一种类型的简单转换)组合在一起,该类不需要访问除了所提供的参数以外的任何信息(可能还有一些对模块全局的属性)

它们可以放在类之外,但是在类内部对它们进行分组可能有意义,因为它们只适用于类。

您还可以通过实例或类而不是模块名来引用方法,这可能有助于读者理解该方法与哪个实例相关。

class Bird:
    # classmethod修饰的方法是类方法
    @classmethod
    def fly (cls):
        print('类方法fly: ', cls)
    # staticmethod修饰的方法是静态方法
    @staticmethod
    def info (p):
        print('静态方法info: ', p)
# 调用类方法,Bird类会自动绑定到第一个参数
Bird.fly()  #①
# 调用静态方法,不会自动绑定,因此程序必须手动绑定第一个参数
Bird.info('crazyit')
# 创建Bird对象
b = Bird()
# 使用对象调用fly()类方法,其实依然还是使用类调用,
# 因此第一个参数依然被自动绑定到Bird类
b.fly()  #②
# 使用对象调用info()静态方法,其实依然还是使用类调用,
# 因此程序必须为第一个参数执行绑定
print("-------")
b.info('fkit')

结果

类方法fly:  <class '__main__.Bird'>
静态方法info:  crazyit
类方法fly:  <class '__main__.Bird'>
-------
静态方法info:  fkit

继承

类和类可以继承,继承(派生)的类的称为派生类或子类,被继承的类称为基类或父类

继承的实现
class teacher:
    teacher_name = "teacher"

    def get_teacher_name(self):
        print(self.teacher_name)

    def get_sex(self):
        print("nan")


class student(teacher):
    student_name = "student"

    def get_student_name(self):
        print(self.student_name)

    def get_teacher_name_two(self):
        print(self.teacher_name)

    def get_sex(self):
        print("nv")

    def get_super(self):
        super().get_sex()

if __name__ == "__main__":
    teacherX = teacher()
    studentX = student()
    print("通过老师的实例获取teacher_name")
    teacherX.get_teacher_name()
    print("通过老师的实例调用get_sex")
    teacherX.get_sex()
    print("通过学生的实例获取student_name")
    studentX.get_student_name()
    print("通过学生的实例调用父类的get_teacher_name方法获取从父类继承来的teacher_name")
    studentX.get_teacher_name()
    print("通过学生的实例获取从父类继承来的teacher_name")
    studentX.get_teacher_name_two()
    print("父类与子类有同样的方法,覆盖了父类的方法")
    studentX.get_sex()
    print("子类通过super()调用父类的方法,可以通过super()函数,在派生类重写基类的方法后,仍可调用基类中的方法。")
    studentX.get_super()

结果

通过老师的实例获取teacher_name
teacher
通过老师的实例调用get_sex
nan
通过学生的实例获取student_name
student
通过学生的实例调用父类的get_teacher_name方法获取从父类继承来的teacher_name
teacher
通过学生的实例获取从父类继承来的teacher_name
teacher
父类与子类有同样的方法,覆盖了父类的方法
nv
子类通过super()调用父类的方法,可以通过super()函数,在派生类重写基类的方法后,仍可调用基类中的方法。
nan
一个类可以继承多个父类

这一点是和java不也一样的,java是可以只能继承父类,但是可以实现多个接口

多态

多态指不考虑对象类型并使用该对象,让具有不同功能的函数使用相同的函数名称,从而通过函数名称调用不同功能的函数。

class Person:
    def get_word(self, name):
        name.get_word()


class Employee:
    def get_word(self):
        print("职工")


class Teacher(Employee):
    def get_word(self):
        print("教师")


class Professor(Employee):
    def get_word(self):
        print("教授")


if __name__ == "__main__":
    A = Person()
    A.get_word(Employee())
    A.get_word(Teacher())
    A.get_word(Professor())

结果

职工
教师
教授

从上面的演示来看,python的多态和java的相差很大

java是通过方法的入参为接口或者父类,在运行的时候才知道传入的是哪个子类或者实现类,但是python的多态竟然是通过一个在所有类之外新建一个类来实现,很奇怪的方式,我有点不太理解。

枚举类

from enum import Enum, unique


@unique
class WeekDay(Enum):  # 继承了Enum枚举
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6
    Sun = 7


print(WeekDay.Wed)
print(WeekDay.Wed.value)
print(WeekDay(7))
print(WeekDay['Sat'])
day = WeekDay.Fri
print(day == WeekDay.Fri)
WeekDay.Wed
3
WeekDay.Sun
WeekDay.Sat
True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值