Python Class

Class Definition

  • class <name>(<parents>): the common 'Object' as a parent
    • static member variables- just state outside constructor
    • class member varaibles
      • with same name, instance member will shadow the class member
      • >>> class Student(object):
        ...     name = 'Student'
        ...
        >>> s = Student() 
        >>> print(s.name) 
        Student
        
  • def __init__(self, vars): _constructor
  • private members: default is public
    • double underline __
      • indication for private variable
      • _var will be replaced by _classname__var, preventing conflict of same name in base and derived class
    • single underline _
      • to prevent attributes be loaded by "from module import"
  • def name(self, vars): member functions
    • usually modify the class (self)
  • class member function - the class method: @classmethod decorator
    • the member function does not modify self
  • static member function: @staticmethod decorator
  • operator overload
    • __eq___

Property and Setter

@property and @<attribute>.setter decorates the function to be getter and setter

Inheritance

  • must call parent constructor in init() explicitly
    • child constructor -> parent contructor
  • Support multiple inheritance
    • isinstance(A,B) - is A an Instance of B
      • use super() to avoid multiple constructor call
      • if needs to call multiple constructors, must use parent._init__() method to explicitly call the second parent
    • use C3 linearization for method resolution
    • MixIn
      • achieve different functions through multiple inheritance
  • Abstract method: @abstractmethod decorator

Methods on classes

  • isinstance(a, class name)
    • judge inheritance
  • type()
    • class type
    • types module
      • include function types, generation types, etc
  • dir()
    • show all attributes and methods
  • getattr(<obj>, str), setattr(), hasattr()
    • throw AttributeError is not found

Dynamic Programming Language

vs Java(static language)

  • object shares same methods will be treated likely
  • bind attributes and methods to instances freely

    • class Student(object):
          def __init__(self, name):
              self.name = name
      
      s = Student('Bob')
      s.score = 90
      
      def set_age(self, age):
          self.age = age
      from types import MethodType
      s.set_age = MethodType(set_age, s)
      
  • __slots__: special variable to define the list of attributes we allow to bind

    • does not work on children
    • class Student(object):
          __slots__ = ('name', 'age')
      

customized class methods

  • __str__
    • use by print()
  • \_repr___
    • used by call func name, usually can be the same as above
  • __len\__
  • __iter\_ and __next___

    • used by for ... in
    • will call \_next__()_ to get next one
    • class Fib(object):
          def __init__(self):
              self.a, self.b = 0, 1 
      
          def __iter__(self):
              return self 
      
          def __next__(self):
              self.a, self.b = self.b, self.a + self.b # 计算下一个值
              if self.a > 100000: 
                  raise StopIteration()
              return self.a
      
  • __getitem\__

    • supports random access (list-like object)
    • usually needs to support int or slice type of inputs
  • \_getattr__(self, attr)_

    • the way python gets attributes
    • can be over-written to suppress attribute errors of parse commands
    • class Chain(object):
      
          def __init__(self, path=''):
              self._path = path
      
          def __getattr__(self, path):
              return Chain('%s/%s' % (self._path, path))
      
          def __str__(self):
              return self._path
      
          __repr__ = __str__
      
  • __call\__(self)_

    • directly calls the object instance
    • class Student(object):
          def __init__(self, name):
              self.name = name
      
          def __call__(self):
              print('My name is %s.' % self.name)
      
      >>> s = Student('Michael')
      >>> s()
      My name is Michael.
      
    • callable(<object>)
      • if a object is a Callable

Examples

class Document():
    # static variable/constant
    WELCOME_STR = 'Welcome! The context for this book is {}.'

    def __init__(self, title, author, context):
        print('init function called')
        self.title = title
        self.author = author
        self.__context = context

    # class method
    @classmethod
    def create_empty_book(cls, title, author):
        return cls(title=title, author=author, context='nothing')

    # member function
    def get_context_length(self):
        return len(self.__context)

    # static function
    @staticmethod
    def get_welcome(context):
        return Document.WELCOME_STR.format(context)


empty_book = Document.create_empty_book('What Every Man Thinks About Apart from Sex', 'Professor Sheridan Simove')


print(empty_book.get_context_length())
print(empty_book.get_welcome('indeed nothing'))

########## output ##########

init function called
7
Welcome! The context for this book is indeed nothing.
from abc import ABCMeta, abstractmethod

class Entity(metaclass=ABCMeta):
    def __init__(self, object_type):
        print('parent class init called')
        self.object_type = object_type

    def get_context_length(self):
        raise Exception('get_context_length not implemented')
    @abstractmethod 
    def get_title(self): 
        pass

class Document(Entity):
    def __init__(self, title, author, context):
        print('Document class init called')
        Entity.__init__(self, 'document')
        self.title = title
        self.author = author
        self.__context = context

    def get_context_length(self):
        return len(self.__context)

class Video(Entity):
    def __init__(self, title, author, video_length):
        print('Video class init called')
        Entity.__init__(self, 'video')
        self.title = title
        self.author = author
        self.__video_length = video_length

    def get_context_length(self):
        return self.__video_length

harry_potter_book = Document('Harry Potter(Book)', 'J. K. Rowling', '... Forever Do not believe any thing is capable of thinking independently ...')
harry_potter_movie = Video('Harry Potter(Movie)', 'J. K. Rowling', 120)

print(harry_potter_book.object_type)
print(harry_potter_movie.object_type)

harry_potter_book.print_title()
harry_potter_movie.print_title()

print(harry_potter_book.get_context_length())
print(harry_potter_movie.get_context_length())

########## output ##########

Document class init called
parent class init called
Video class init called
parent class init called
document
video
Harry Potter(Book)
Harry Potter(Movie)
77
120

Python Modularization

Some principles

  • import once
    • usually at the beginning of program
  • use absolute file path
    • don't use sys.path.append() to change running path
  • Single Repository
  • Set up independent running environments

    • two ways to change running path (the list interpretor looks for packges)

      • import sys  
        
        print(sys.path)
        
        ########## output ##########
        
        ['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
        
        # change path
        sys.path[0] = '/home/ubuntu/workspace/your_projects'
        
      • # use Virtual Enviornment
        # in the activate file in the virtual environment
        export PYTHONPATH="/home/ubuntu/workspace/your_projects"
        
      • use the second one
  • If need running code in package (eg. printing) use if \_name__ == '__main__'_


MetaClass

Type

  • return the type of the class
    • instance type is the class
    • class is of type 'type'
      • class is an instance of 'type'
  • can dynamically create new types without definition
    • >>> def fn(self, name='world'): # 先定义函数
      ...     print('Hello, %s.' % name)
      ...
      >>> Hello = type('Hello', (object,), dict(hello=fn)) # create hello calss with attribute hello
      

Metaclass

  • inherit type
  • allows you to create and modify classes
    • and modify the behaviors in class creation
  • class is the instance of metaclass
  • overwrites __new\_ _to modify class creation behaviors
    • the type.\_new__(class, name, bases, attrs) _is called when python interpretor finds class definiions

MetaClass in Engineering

Example

ORM(Object-Relational Mapping)

# use case
class User(Model):
    # 定义类的属性到列的映射:
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

# 创建一个实例:
u = User(id=12345, name='Michael', email='[email protected]', password='my-pwd')
# 保存到数据库:
u.save()
class Field(object):

    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return '<%s:%s>' % (self.__class__.__name__, self.name)

class StringField(Field):

    def __init__(self, name):
        super(StringField, self).__init__(name, 'varchar(100)')

class IntegerField(Field):

    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')

class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
        if name=='Model':
            return type.__new__(cls, name, bases, attrs)
        print('Found model: %s' % name)
        mappings = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v
        for k in mappings.keys():
            attrs.pop(k)
        attrs['__mappings__'] = mappings # 保存属性和列的映射关系
        attrs['__table__'] = name # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)

lass Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))

results matching ""

    No results matching ""