与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:继承静态方法info: crazyit 类方法fly: ------- 静态方法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的多态竟然是通过一个在所有类之外新建一个类来实现,很奇怪的方式,我有点不太理解。



