Python学习笔记(二)

文章目录

  • 1. 类
    • 1.1. 私有变量
    • 1.2. 继承
    • 1.3. 属性设置校验
    • 1.4. 定制类
    • 1.5. 枚举类
    • 1.6. 杂

供个人学习笔记回顾时使用.

1. 类

天下语言是一家, 你抄我完, 我抄他.
没错, python的没啥特殊的, 先来个简单的例子:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'


lisa = Student('Lisa', 99)
print(lisa.get_grade())
# A

1.1. 私有变量

双下划线开头的变量, 例子如下:

class Student(object):
    def __init__(self, gender):
        self.__gender = gender

    def get_gender(self):
      return self.__gender

    def set_gender(self, value):
      self.__gender = value


b = Student('liu')
print(b.get_gender())
# liu

但是
这种私有变量定义形式也是伪的, 还是可以通过b._Student__gender这个属性直接拿到这个私有变量, 不过建议不要这么使用

1.2. 继承

没啥说的, 上面的两个例子已经看出来了, 例子:

class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):

    def run(self):
        print('Dog is running...')

class Cat(Animal):

    def run(self):
        print('Cat is running...')

python和c++一样, 可以多继承, 语法就是在括号里多写几个类

class Runnable(object):
    def run(self):
        print('Running...')


class Flyable(object):
    def fly(self):
        print('Flying...')


class Dog(Flyable, Runnable):
    pass

b = Dog()
b.fly()
# Flying...

1.3. 属性设置校验

类似于js中proxy的set的功能, 采用decorator语法, 代码很简单, 如下:

class Screen(object):
    @property
    def width(self):
        return self._width
    
    @width.setter
    def width(self, value):
        if value < 0:
            raise ValueError("width must be greater than 0")
        self._width = value

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self, value):
        if value < 0:
            raise ValueError("height must be greater than 0")
        self._height = value

    @property
    def resolution(self):
        return self._height * self._width

如果width, height设置小于0会报错.
其中width, height可读可写, resolution只可读, 不可写

1.4. 定制类

这里的语法和功能也比较好理解, 类似于js的原型链覆盖, Symbol.iterator属性

__str____repr__: 打印默认输出, 很类似与js中的toString方法
__iter____next__: 类中如果定义了这两个方法, 说明可以被for...in遍历

更多定制类方法:

  1. python官方文档
  2. 廖雪峰学习文档(只介绍了部分)

1.5. 枚举类

枚举: 是一个被命名的整型常数的集合

枚举见过, 枚举类我倒是之前没见过, 不过也还算好理解. 枚举定义方法有两种
一. 直接使用Enum关键字

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

这些属性里的值默认从1开始递增

二. 如果需要更精确地控制枚举类型,可以从Enum派生出自定义类:
@unique装饰器可以帮助我们检查保证没有重复值。

from enum import Enum, unique

@unique
class Weekday(Enum):
    Sun = '123' # Sun的value被设定为123
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

访问这些枚举类型可以有若干种方法:

>>> day1 = Weekday.Mon
>>> print(day1)
Weekday.Mon
>>> print(Weekday.Tue)
Weekday.Tue
>>> print(Weekday['Tue'])
Weekday.Tue
>>> print(Weekday.Tue.value)
2
>>> print(day1 == Weekday.Mon)
True
>>> print(day1 == Weekday.Tue)
False
>>> print(Weekday(1))
Weekday.Mon
>>> print(day1 == Weekday(1))
True
>>> Weekday(7)
Traceback (most recent call last):
  ...
ValueError: 7 is not a valid Weekday
>>> for name, member in Weekday.__members__.items():
...     print(name, '=>', member)
...
Sun => Weekday.Sun
Mon => Weekday.Mon
Tue => Weekday.Tue
Wed => Weekday.Wed
Thu => Weekday.Thu
Fri => Weekday.Fri
Sat => Weekday.Sat

1.6. 杂

一、使用type()函数
使用type()函数,可以获取任何数据的类型。如果要判断一个数据是不是函数,可以使用types模块中定义的常量,
如:types.FunctionType、types.LambdaType。

>>> import types
>>> def fn():
...     pass
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType

二、使用isinstance()函数
isinstance函数判断的是一个对象是否是该类型或位于该类型的父类继承链上。isinstance还可以判断一个变量是否是某些类型的一种,用元组写多种类型。

>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True
>>> isinstance([1, 2, 3], (list, tuple))
True

三、使用dir()函数
1.如果要获得一个对象全部的属性和方法,可以使用dir()函数。它返回一个包含 字符串的list。

# 例如1.1的例子就可以用这个方法来查看
print(dir(b))
['_Student__gender', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_gender', 'set_gender']

2.类似“__xxx__”的属性和方法在Python中都是有特殊用途的,比如len()函数获取对象的长度。但实际上,在len函数内部它会去自动调用对象的__len__()方法,所以,你可以在类中自己设定一个__len__()方法,让len返回你想要返回的长度。

>>> len('ABC')
3
>>> 'ABC'.__len__()
3

四、操作一个对象状态
如getattr() 获取、setattr() 设置 和hasattr() 有没有 方法,可以直接操作一个对象的状态。

hasattr(obj, 'x')  # 有属性‘x’吗?
setattr(obj, 'y', 18)  # 设置一个属性‘y’,值为18.
getattr(obj, 'y')  # 获取属性y
getattr(obj, 'z', 404)  # 获取属性z,如果不存在,就返回默认值404.

五、类属性和实例属性

回顾一个知识点, JS中实例和对象的区别:
1、实例是类的具象化产品,
2、而对象是一个具有多种属性的内容结构。
实例都是对象,而对象不全是实例。

好了, 拉回到python中, 一个样, 直接看代码

class Student(object):
    name = 'Student'

>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student

还可以使用__slots__变量来限制类的属性, 如下例:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

六、类还可以使用Type来创建

class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。

type()函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object)...的定义:

创建例子:

>>> def fn(self, name='world'): # 先定义函数
...     print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<class 'type'>
>>> print(type(h))
<class '__main__.Hello'>

要创建一个class对象,type()函数依次传入3个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。

字数太多, 有点卡了… 新开一个博客

reference links:

  1. 廖雪峰Python学习文档

你可能感兴趣的:(Python)