欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 零零碎碎的知识点------python篇一

程序员文章站 2022-03-30 09:32:45
python一语言特性python的函数参数传递可变类型数据不可变类型的数据语言特性python的函数参数传递这两张图片的不同点在于,第一张图片的值在执行完函数之后没有发生变化,而第二张图片中的列表在执行完函数之后的值发生了变化。原因:当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针...

语言特性

python的函数参数传递

荐
                                                        零零碎碎的知识点------python篇一
荐
                                                        零零碎碎的知识点------python篇一
这两张图片的不同点在于,第一张图片的值在执行完函数之后没有发生变化,而第二张图片中的列表在执行完函数之后的值发生了变化。
原因:

当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.

注意,这地方需要记住的一点是:类型是属于对象的,而不是变量
而对象又分为可变不可变两种类型数据

可变类型数据

List(列表)、Dictionary(字典)、Set(集合)

不可变类型的数据

Number(数字)、String(字符串)、Tuple(元组)

  • 数字

python中的number用于存储数值,数据类型是不允许进行改变的,如果进行改变也就是意味着要重新分配内存空间

数字支持的数据类型:

整形(int)-通常被称为整型或整数,是正数或者负整数。
长整型(long integers)-无限大小的整数,整数最后使用大写或小写的L表示。
浮点型(floating point real values)-浮点型由整数部分和小数部分组成。
复数(complex numbers)-复数由实数部分和虚数部分构成,可以使用a+bj,或者complex(a,b)表示,复数的a和b部分都是浮点型.
布尔值(bool)- 只有True,False两个值。很方便的进行逻辑运算。
字节(bytes):二进制类型。主要储存一些字符串的编码。或者数字的二进制表示。

python中的三个方法

静态方法(staticmethod)、类方法(classmethod)和实例方法
  • 类方法: 是类对象的方法,在定义时需要在上方使用 @classmethod 进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用

  • 实例方法: 是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;

  • 静态方法: 是一个任意函数,在其上方使用 @staticmethod 进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系

类变量和实例变量

实例化之后,每个实例单独拥有的变量。可以进行修改,应用。
但是类变量里面的值,是所有实例可以共享的。
荐
                                                        零零碎碎的知识点------python篇一
对于赋值情况

  • 类变量
    (1)类的设计里class里def外,通过变量名能被赋值
    def里通过类对象即类名字的点运算变量名可被赋值
    (2)程序里通过类对象(类名字)的点运算类名字也可被赋值
  • 实例对象变量
    (1)类的设计时def里通过self点运算变量名能被赋值,不一定非在init里,其他已被调用的方法函数里也行
    (2)程序里通过实例对象的点运算变量名可被赋值(上面p1.name就是用的这种方法)

python自省

运行时可以通过type(),dir(),getattr(),hasattr(),isinstance().等这些方法获得对象的类型

type()和instance()的用法比较熟悉

  • dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。
  • 剩下的l两个不熟悉的用法可以看看这篇博文

推导式

字典推导式

字典推导式,可以交换原来的键和值;也可以给键值对赋值

  • 交换键和值

荐
                                                        零零碎碎的知识点------python篇一

  • 单独取出来键或者值,用列表的形式返回
    荐
                                                        零零碎碎的知识点------python篇一
  • 给键和值赋值
    荐
                                                        零零碎碎的知识点------python篇一
列表推导式

列表推导式可以减少代码量
比如说要创建一个0-10列表,

荐
                                                        零零碎碎的知识点------python篇一
但是如果使用列表推导式的话
荐
                                                        零零碎碎的知识点------python篇一

集合推导式

跟列表推导式类似,区别在于使用的是大括号{}

荐
                                                        零零碎碎的知识点------python篇一

python中的单下划线和双下划线

(1)、以单下划线开头,表示这是一个保护成员,只有类对象和子类对象自己能访问到这些变量。以单下划线开头的变量和函数被默认当作是内部函数,使用from module improt *时不会被获取,但是使用import module可以获取
(2)、以单下划线结尾仅仅是为了区别该名称与关键词
(3)、双下划线开头,表示为私有成员,只允许类本身访问,子类也不行。在文本上被替换为_class__method
(4)、双下划线开头,双下划线结尾。一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突。是一些 Python 的“魔术”对象,表示这是一个特殊成员,例如:定义类的时候,若是添加__init__方法,那么在创建类的实例的时候,实例会自动调用这个方法,一般用来对实例的属性进行初使化,Python不建议将自己命名的方法写为这种形式。

荐
                                                        零零碎碎的知识点------python篇一
私有变量:实例._类名__变量名
私有方法:实例._类名__方法名()

字符串格式化:% 和 .format

迭代器和生成器

将列表生成式中[]改成() 之后数据结构会发生改变,从列表变为生成器。

迭代器

迭代器有两个基本的方法:

  • iter()把可迭代对象转换成迭代器,需要返回一个迭代器
  • next()输出迭代器的下一个值

用isinstance()方法判断或者可以for循环的遍历的对象是可迭代对象,可以被next()函数调用,并不断返回下一个值得对象。

字符串,列表或元组对象都可用iter()创建迭代器,并通过next()取值。

生成器

生成器一定是迭代器,而迭代器不一定是生成器,一边循环一边计算的机制称为生成器,含有yield语句的函数,可以减少内存空间。
含有yield语句的函数一般都是生成器

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。

生成器和迭代器的区别在于,生成器并不是一上来就把所有值装载进内存,因而也不会占用大量的内存,只是在需要使用next()函数获取值的时候,才会取一个值返回,内存开销非常小。

*args and **kwargs

  • 元组参数,即 *args,参数格式化存储在一个元组中,长度没有限制,必须位于普通参数和默认参数之后。(它可以传递多个参数)
  • 字典参数,即 **kwargs,参数格式化存储在一个字典中,必须位于参数列表的最后面。(它可以优先定义你事先没有定义的参数)

面向切面编程AOP和装饰器

对于切面编程AOP的准确理解,可以看看这篇博文这篇博文
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
装饰器

鸭子模型


class Duck():
  def walk(self):
    print('I walk like a duck1')
  def swim(self):
    print('i swim like a duck2')

class Person():
  def walk(self):
    print('this one walk like a duck3')
  def swim(self):
    print('this man swim like a duck4')

duck = Person()
duck.swim()
duck.walk()

荐
                                                        零零碎碎的知识点------python篇一

可以很明显的看出,Person类拥有跟Duck类一样的方法,当有一个函数调用Duck类,并利用到了两个方法walk()和swim()。我们传入Person类也一样可以运行,函数并不会检查对象的类型是不是Duck,只要他拥有walk()和swim()方法,就可以正确的被调用。
再举例,如果一个对象实现了__getitem__方法,那python的解释器就会把它当做一个collection,就可以在这个对象上使用切片,获取子项等方法;如果一个对象实现了__iter__和next方法,python就会认为它是一个iterator,就可以在这个对象上通过循环来获取各个子项。
也就是说,你只要能用就行,我不管你是谁,只要有我能调动你,我就运行。

python重载

重简单理解就是,可以定义几个名字相同的函数,但是他们的参数类型或者数量不同,从而实现不同的代码逻辑。函数名字同,参数类型或者数量不同
所以他解决的是就是参数问题。
1、解决参数类型
2、解决参数数量

解决第一个问题
  • 对于函数的名字一样,但是参数的类型不同的情况。其实可以不用解决。函数名字一样,说明功能一样,既然功能一样,使用的就是同一套代码,而且python是可以接收任何类型的参数的。所以没有必要写成两个函数。这篇博文中就将到了python里面的多种传参。注意,看这篇博文的评论。
    那如果说,非要解决,非得写两个函数,进行不同类型的传参的话,其实是有两种方法的。
    第一种
    简单的判断
    荐
                                                        零零碎碎的知识点------python篇一
    这样很简单粗暴,但是如果类型过多,你要写多少if–else???我觉得很繁琐
    第二种
    用functools模块里面的singledispatch装饰器实现函数重载
from functools import singledispatch


@singledispatch
def test(content):
  print('惊不惊喜,意不意外,我不属于下面注册的那些类型,所以走默认类型')


@test.register
def yeah(content:str):
  name = content
  print('%s,他们会的东西可多了'%name)


@test.register
def yoyo(content:tuple):
  age = content
  print('你的年龄在这个范围内吗?',age)

test('王一博丫,易烊千玺丫')
test((20,21,22,23))
test(11)

荐
                                                        零零碎碎的知识点------python篇一
这个函数在传入参数不同时的具体实现,通过下面注册的函数来实现。
注册的时候使用@我们定义的函数名.register来注册。被注册的函数名随你心情。
被注册的函数的第一个参数,通过类型标注来确定它应该使用什么类型。注意写法,参数:类型

当我们调用我们定义的函数时,如果参数类型符合某个被注册的函数,那么就会执行这个被注册的函数。如果参数类型不满足任何一个被注册的函数,那么就会执行我们的原函数。

解决第二个问题

函数功能相同的话,参数个数不同,可以对那些缺少的参数设定为缺省参数。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。
这是缺省参数的博文。
或者,也可以使用元组传参,这个传参方式可以传多个参数。也是可以解决问题的。

新式类和旧式类(旧式类也称之为经典类)

Python 3.x中默认都是新式类,经典类被移除。
移除原因在于:经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的,而新式类是采用C3算法(不同于广度优先)进行匹配的。经典类最容易出现的就是子类越过父类的方法。

这也就是为什么我们在继承父类,如果父类有__init___方法的时候,子类想要用这个方法,就得调一下父类的__init__。否则的话,就会报错,绕过父类的一些方法。比如下面的这个例子


class Apple():
  def __init__(self):
    print('我是父类')
    self.age = 11

  def new(self):
    print('我是父类的方法,默认的年龄%s'%self.age)

class Orange(Apple):
  def __init__(self):
    print('我是子类')

  def good(self):
    print('我是子类的方法')


o = Orange()
o.good()
o.new()

荐
                                                        零零碎碎的知识点------python篇一
他就绕过了父类里面的age被绕过,然后报错。
除非,


class Apple():
  def __init__(self):
    print('我是父类')
    self.age = 11

  def new(self):
    print('我是父类的方法,默认的年龄%s'%self.age)

class Orange(Apple):
  def __init__(self):
    super().__init__()
    print('我是子类')

  def good(self):
    print('我是子类的方法')


o = Orange()
o.good()
o.new()

在子类中调用父类的__init__,再去执行
荐
                                                        零零碎碎的知识点------python篇一
还有很经典的一个旧式类的深度优先例子

class A():
    def foo1(self):
        print "A"
class B(A):
    def foo2(self):
        pass
class C(A):
    def foo1(self):
        print "C"
class D(B, C):
    pass

d = D()
d.foo1()

# A

按照经典类的查找顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的…那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过。
但是新式类不会

__new__和__init__的区别

  • __new__是一个静态方法,而__init__是一个实例方法.
  • __new__方法会返回一个创建的实例,而__init__什么都不返回.
  • 只有在__new__返回一个cls的实例时后面的__init__才能被调用.
  • 当创建一个新实例时调用__new__,初始化一个实例时用__init__

本文地址:https://blog.csdn.net/zxcvbbnn/article/details/107009547