Python - HongkuanZhang/Technique-Notes GitHub Wiki

Python class 的子类父类继承

  • 情况一:子类需要自动调用父类的方法:子类不重写__init__()方法,实例化子类后,会自动调用父类的__init__()的方法。
  • 情况二:子类不需要自动调用父类的方法:子类重写__init__()方法,实例化子类后,将不会自动调用父类的__init__()的方法。
  • 情况三:子类重写__init__()方法又需要调用父类的方法(既包含父类初始化方法又包含子类初始化方法), 使用super:
class Father:
  def __init__(self):
    self.father_value = 88
    print("Value from father",self.father_value)

class Son(Father):
  def __init__(self):
    super().__init__()
    self.son_value = 100
    print("Son value from son",self.son_value)
    print("Father value from son",self.father_value)

Son_object = Son()
# 输出如下
# Value from father 88
# Son value from son 100
# Father value from son 88
# 也就是说Son_object既继承了father_value,也初始化了自己的son_value.

@classmethod的使用

class Father:
  def __init__(self):
    self.father_value = 88
    print("Value from father",self.father_value)
  
  # 加上classmethod,可以实现不需要实例化类调用参数(后面会演示)
  # 另外,函数不使用self而是cls,也就是说函数归属于调用它的class的
  @classmethod
  def method(cls):
    C = cls()
    return C

class Son(Father):
  def __init__(self):
    super().__init__()
    self.son_value = 100
    print("Son value from son",self.son_value)
    print("Father value from son",self.father_value)
  def __call__(self,w):
    print('Message from __call__ of son:',w)
  def son_func(self):
    print('Hello')

#下例就是通过子类调用method函数而不实例化class
Son_object = Son.method()
# 输出如下
# Value from father 88
# Son value from son 100
# Father value from son 88
# 这里是先通过调用method函数,然后函数里的内容初始化了一个Son的实例,然后实例的初始化和继承引发了
# 上面这三个输出,然后method中由于返回了实例,因此Son_object被赋值了这个实例

#之后可以直接调用Son_object中的函数如下
# 验证__call__函数
Son_object('hahahha')
# 输出 Message from __call__ of son: hahahha

# 验证son_func函数
Son_object.son_func()
# 输出 Hello

关于super继承

关于super继承我们平时比较多见的是super().__init__这样的表达,其实这个写法既继承了初始化的属性,也继承了父类的方法,具体如下

class Father:
    def __init__(self):
        self.father_value = 88
        print("Value from father",self.father_value)
    def father_method(self,x):
        return x * 3

class Son(Father):
    def __init__(self):
        super().__init__()
        self.son_value = 100
        print("Son value from son",self.son_value)
        print("Father value from son",self.father_value)
        
>> s = Son()
#Value from father 88
#Son value from son 100
#Father value from son 88

#继承了父类方法
>> s.father_method(30)
# 90

另外,我们也可以在子类中用super.father_method(args)的方法来直接执行父类方法,如下

class Father:
    def __init__(self):
        self.father_value = 88
    def father_method(self,x):
        return x * 3

class Son(Father):
    def __init__(self):
        super().__init__()
        self.son_value = 100
        print(super().father_method(55))

>> s = Son()
# 165

isinstance和type的区别

两者都可以用来查看对象类型并判断两个对象的类型是否一致,但是前者会考虑对象的继承关系,而后者不会考虑

class A:
    pass
 
class B(A):
    pass
 
isinstance(A(), A)    # returns True
type(A()) == A        # returns True
isinstance(B(), A)    # returns True (考虑了继承关系)
type(B()) == A        # returns False (未考虑继承关系)
# 也就是说如果两个函数都继承于一个函数,那么他们在isinstance函数的判断里会被看成一个instance。

另外,isinstance也可以接受列表来检验是否是相同类型的对象

>> a = 2
>> isinstance (a,(str,int,list)) # 是元组中的一个返回 True
# True

getattr()和setattr()

getattr()这个函数会获得类的属性,若没有对应属性,则触发异常,但是可以定义一个没有属性时候的默认值,则会返回所定义的默认值

>>>class A(object):
...     bar = 1
... 
>>> a = A()
>>> getattr(a, 'bar')        # 获取属性 bar 值
# 1
>>> getattr(a, 'bar2')       # 属性 bar2 不存在,触发异常
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: 'A' object has no attribute 'bar2'
>>> getattr(a, 'bar2', 3)    # 属性 bar2 不存在,返回了默认值
# 3

getattr()正好相对应,是给对象添加属性,用法如下:

>>>class A():
...  name = "runoob"
... 
>>> a = A()
>>> setattr(a, "age", 28)
>>> print(a.age)
#28

class内部属性

在定义class时,没有写在类内函数内的变量都默认为类的变量,如下例

class A(object):
  MAX = 100
  def __init__(self,input_value):
    self.input_value = input_value
  Less = 1
>> a = A()
>> a.MAX
# 100
>> a.Less
# 1

Python装饰器和@property

装饰器用法见link
property的作用主要是使得函数方法变为只读属性,然后进行属性读取,也可以赋予属性值设置和删除属性的功能,具体见下例

class Person(object):

    def __init__(self):
        self._age = 15

    # property作为装饰器,使得age方法变为只读属性
    # 之所以把叫只读属性,是因为通过这个方法隐藏真实的属性名_age
    # 用户在访问一个实例person的属性值age的时候是通过person.age来访问的
    # 虽然返回的是self._age的值,但是用户并不知道属性的真实名称是_age
    # 进而后面进行属性读取
    @property
    def age(self):
        return self._age
    
    # 属性方法名加上.setter即可增加设置属性值的操作
    # 这时候属性就不是只读的了,可以对值进行更改
    @age.setter
    def age(self,age):
        if isinstance(age,str):
            self._age = int(age)
        elif isinstance(age,int):
            self._age = age
    
    # 属性方法名加上.deleter即可增加删除属性的操作
    @age.deleter
    def age(self):
        del self._age

>> p = Person()
# 读取属性
>> p.age
# 15
# 属性赋值
>> p.age = 88
>> p.age
# 88
# 删除属性
>> del p.age
>> p.age
# AttributeError: 'Person' object has no attribute '_age'

Python typing类型提示

typing主要用于提示函数的输入和输出类型,结合下例会理解的更清楚

from typing import List, Union, Optional
# import了三个数据类型,List即list数据类型,List[x]表示一个装着x(如int)类型数据的list
# Union是联合类型,Union[x,y]表示输入的数据类型非x即y
# Optional是可选类型,Optional[x]等价于Union[X,None]
# 但要注意的是并不是说默认参数是None,默认参数可以自定义,不一定为None
# 因此使用Optional不可以省略默认参数

# 此例中a为整数或者字符,Optional为整数或者None(默认值一定要定义,此例中定义为None,也可以是别的任何数值或字符)
# c为整数list
def foo_v2(a: Union[int,str], b: Optional[int] = Nonec: List[int]):
    if b:
        print(a + b)
    else:
        print("parameter b is a NoneType!")
    
    print('Input list is:', c)

>> foo_v2(10)
# 输出为 parameter b is a NoneType! 以及将c打印出来
>> foo_v2(1020)
# 输出为 30 以及将c打印出来

# 如果b:Optional[int] = 100 则
>> foo_v2(10)
# 输出为 110 以及将c打印出来

# 另外还可以定义返回数据的类型,如
# def foo_v2(a: Union[int,str], b: Optional[int] = None,c: List[int]) -> Union[Any]:
# 表示返回任意类型的数据, 但是python不强制检查类型,即即使返回错的类型也不会中断程序

import 同级目录和上级目录中的文件夹的函数

文件树:
dir1
  a.py
  b.py
dir2
  c.py
从a中引用b中的test函数
from .b import test
从a中引用c中的test函数
from ..c import test

Sorted函数

对于上面的sorted函数,key可以赋予两个值,例如key=(a,b),然后会首先以a为标准进行排序,若a相同再以b来排序。这里a和b都可以是list,如图中所示。图中的作用是对句子的BIO标签进行排序。

关于str.strip

return和yield的区别

关于argparse

import argparse
person_parser = argparse.ArgumentParser(description = 'The explanation for the parser function')
person_parser.add_argument('-n','--name',default='Tom')
person_parser.add_argument('-w','--weight',default='30kg')

args = person_parser.parse_args()
print('Name: {}, Weight: {}'.format(args.name,args.weight))

#如果命令行输入为 python3 this_file.py --name Jerry --weight 20kg
#则输出为'Name: Jerry, Weight: 20kg'
#PS: 如果想知道应该输入什么参数则 python3 this_file.py -h 即可得到对于parser的描述

argparse的使用主要就三步,第一步是通过ArgumentParser来初始化parser,第二步是用parser.add_argument来定义要读入的参数,最后一步是用parser.parse_args来读取终端输入中的参数,得到的parser通过parser.[attribute_name]即可获取相应属性的值。一般来说代码文件中还要定义一个Config类,这个类通过self.[attribute_name]=parser.[attribute_name]来把parser中的外部参数属性值给到Config类中,Config类中还包含很多内部参数,如self.B = "B-"这样的定义。之后令变量config = Config(parser),我们拿着这个config给所有模块用于其定义一些参数。

*args & **kwargs 的使用

除了上述方法之外,还要注意一个反过来的情况,就是定义的函数里没有使用args或者kwargs但是使用函数时候,传参的地方用了args方法,如下

def method(a=1,b=2):
    print(a,b)
>> dict = {'a'=20}
>> method(**dict)
# 输出为 20 2
# 这里要注意的是这种方法传参必须是字符一致,即dict中的key必须是a和b,不能是别的,这样才能传给对应的参数

List中for循环嵌套

关于os的几个总结

os.listdir(path)

返回包含path路径中所有文件名字(包含文件格式)的迭代器, 可用for循环取出。这个命令不返回子目录(文件夹)中的文件名, 只返回当前目录的文件名。

os.walk(path)

os.walk输入一个路径名称,以yield的方式(其实是一个生成器)返回一个三元组 dirpath, dirnames, filenames, 用法如下:

import os
path = r'C:\Users\Administrator\Desktop\file'
for dirpath,dirnames,filenames in os.walk(path):
    print(dirpath,dirnames,filenames)

#dirpath为目录路径, dirname为目录路径下所有目录的名称, 结果如下:  
#C:\Users\Administrator\Desktop\file ['file1', 'file2'] ['file_test1.txt', 'file_test2 .txt']
#C:\Users\Administrator\Desktop\file\file1 [] ['file1_test1.txt', 'file1_test2.txt']
#C:\Users\Administrator\Desktop\file\file2 [] ['file2_test1.txt']

获得一个路径下所有文件的路径:

import os
path = r'C:\Users\Administrator\Desktop\file'
for dirpath,dirnames,filenames in os.walk(path):
    for filename in filenames:
        print(os.path.join(dirpath,filename))

#结果如下:
#C:\Users\Administrator\Desktop\file\file_test1.txt
#C:\Users\Administrator\Desktop\file\file_test2 .txt
#C:\Users\Administrator\Desktop\file\file1\file1_test1.txt
#C:\Users\Administrator\Desktop\file\file1\file1_test2.txt
#C:\Users\Administrator\Desktop\file\file2\file2_test1.txt

改变输出字体颜色

改变输出颜色主要是靠转义字符,具体来说如下:

# 定义颜色class
class bcolors:
    HEADER  = '\033[95m'
    BLUE    = '\033[94m'
    GREEN   = '\033[92m'
    WARNING = '\033[93m'
    FAIL    = '\033[91m'
    ENDC    = '\033[0m'
    BOLD    = '\033[1m'
    HIGHL   = '\x1b[6;30;42m'
    UNDERLINE = '\033[4m'
# 输出彩色字体:
# 下方输出结果为前面string为蓝色,后面string为绿色
print (bcolors.BLUE + "BLUE STRING" + " " + bcolors.GREEN + "GREEN STRING")
⚠️ **GitHub.com Fallback** ⚠️